From ee69eaf8b8eacfd1199769ab55fb22147a799faf Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Fri, 25 Oct 2024 10:21:31 -0400 Subject: [PATCH 001/327] adjusted update from google api to use async generator --- .../writing_observer/aggregator.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index f45e06714..158e83cee 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -298,12 +298,15 @@ async def fetch_doc_from_google(student, doc_id): await kvs.set(key, text) return text - if learning_observer.settings.module_setting('writing_observer', 'use_google_documents'): - [await fetch_doc_from_google( - learning_observer.util.get_nested_dict_value(d, 'provenance.provenance.value.user_id'), - learning_observer.util.get_nested_dict_value(d, 'doc_id') - ) for d in doc_ids] - return doc_ids + fetch_from_google_documents = learning_observer.settings.module_setting('writing_observer', 'use_google_documents') + async for d in doc_ids: + if fetch_from_google_documents: + yield await fetch_doc_from_google( + learning_observer.util.get_nested_dict_value(d, 'provenance.provenance.value.user_id'), + learning_observer.util.get_nested_dict_value(d, 'doc_id') + ) + else: + yield d def get_last_document_id(s): From 0bac912e6364684eb5c051adca221bb74d6424ee Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Fri, 25 Oct 2024 10:39:20 -0400 Subject: [PATCH 002/327] fixed small bug in yield statements --- modules/writing_observer/writing_observer/aggregator.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 158e83cee..188de004a 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -301,12 +301,11 @@ async def fetch_doc_from_google(student, doc_id): fetch_from_google_documents = learning_observer.settings.module_setting('writing_observer', 'use_google_documents') async for d in doc_ids: if fetch_from_google_documents: - yield await fetch_doc_from_google( - learning_observer.util.get_nested_dict_value(d, 'provenance.provenance.value.user_id'), + await fetch_doc_from_google( + learning_observer.util.get_nested_dict_value(d, 'provenance.provenance.STUDENT.value.user_id'), learning_observer.util.get_nested_dict_value(d, 'doc_id') ) - else: - yield d + yield d def get_last_document_id(s): From 5127ea754b0fb36049d7c5b467699abc19f47039 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Wed, 30 Oct 2024 14:24:08 -0400 Subject: [PATCH 003/327] fixed possible create_task bug (#192) Addressed weak reference for created tasks in asyncio --- learning_observer/learning_observer/dashboard.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8d06bfd3a..6df3dbf75 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -588,6 +588,7 @@ async def websocket_dashboard_handler(request): previous_client_query = None batch = [] lock = asyncio.Lock() + background_tasks = set() async def _send_update(update): '''Send an update to our batch @@ -646,7 +647,9 @@ async def _drive_generator(generator, dag_kwargs): item['option_hash'] = dag_kwargs['option_hash'] await _send_update({'op': 'update', 'path': update_path, 'value': item}) - send_batches = asyncio.create_task(_batch_send()) + send_batches_task = asyncio.create_task(_batch_send()) + background_tasks.add(send_batches_task) + send_batches_task.add_done_callback(background_tasks.discard) while True: try: @@ -676,7 +679,9 @@ async def _drive_generator(generator, dag_kwargs): # reschedule timeout). for k, v in client_query.items(): for target in v.get('target_exports', []): - asyncio.create_task(_execute_dag(v, target, client_query)) + execute_dag_task = asyncio.create_task(_execute_dag(v, target, client_query)) + background_tasks.add(execute_dag_task) + execute_dag_task.add_done_callback(background_tasks.discard) # Obsolete code -- we should put this back in after our refactor. Allows us to use From 5ad48abd3eb529a11cc242d3bc32ab32087f09a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 13:13:15 -0500 Subject: [PATCH 004/327] Bump rollup from 2.79.1 to 2.79.2 in /modules/lo_dash_react_components (#179) Bumps [rollup](https://github.com/rollup/rollup) from 2.79.1 to 2.79.2. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v2.79.1...v2.79.2) --- updated-dependencies: - dependency-name: rollup dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/lo_dash_react_components/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/lo_dash_react_components/package-lock.json b/modules/lo_dash_react_components/package-lock.json index 036c4ca1c..2bab0a655 100644 --- a/modules/lo_dash_react_components/package-lock.json +++ b/modules/lo_dash_react_components/package-lock.json @@ -25367,9 +25367,9 @@ } }, "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "bin": { "rollup": "dist/bin/rollup" }, From 45d1c388223093914f85ac81905c9cff582af3c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 13:13:54 -0500 Subject: [PATCH 005/327] Bump cookie and express in /modules/lo_dash_react_components (#183) Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `cookie` from 0.6.0 to 0.7.1 - [Release notes](https://github.com/jshttp/cookie/releases) - [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1) Updates `express` from 4.20.0 to 4.21.1 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md) - [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1) --- updated-dependencies: - dependency-name: cookie dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../package-lock.json | 130 +++++------------- 1 file changed, 34 insertions(+), 96 deletions(-) diff --git a/modules/lo_dash_react_components/package-lock.json b/modules/lo_dash_react_components/package-lock.json index 2bab0a655..6cf4d12f8 100644 --- a/modules/lo_dash_react_components/package-lock.json +++ b/modules/lo_dash_react_components/package-lock.json @@ -6619,20 +6619,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/body-parser/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -7689,9 +7675,9 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -9927,23 +9913,23 @@ } }, "node_modules/express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", @@ -9952,11 +9938,11 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -10367,12 +10353,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -10391,6 +10377,14 @@ "ms": "2.0.0" } }, + "node_modules/finalhandler/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -20525,11 +20519,11 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -25845,79 +25839,23 @@ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, "node_modules/serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-static/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/serve-static/node_modules/http-errors": { + "node_modules/serve-static/node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serve-static/node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } From fdf00eaf1389cb4272397daaa41f1d5ece5f032d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 13:14:33 -0500 Subject: [PATCH 006/327] Bump elliptic from 6.5.7 to 6.6.0 in /modules/lo_dash_react_components (#193) Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.7 to 6.6.0. - [Commits](https://github.com/indutny/elliptic/compare/v6.5.7...v6.6.0) --- updated-dependencies: - dependency-name: elliptic dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/lo_dash_react_components/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/lo_dash_react_components/package-lock.json b/modules/lo_dash_react_components/package-lock.json index 6cf4d12f8..528896ff6 100644 --- a/modules/lo_dash_react_components/package-lock.json +++ b/modules/lo_dash_react_components/package-lock.json @@ -8922,9 +8922,9 @@ "integrity": "sha512-ndBQYz3Eyy3rASjjQ9poMJGoAlsZ/aZnq6GBsGL4w/4sWIAwiUHVSsMuADbxa8WJw7pZ0oxLpGbtoDt4vRTdCg==" }, "node_modules/elliptic": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", - "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", + "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", From 0105345159b58cb494a3d61bf4115bea8bca0d0d Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Mon, 4 Nov 2024 13:20:35 -0500 Subject: [PATCH 007/327] added communication protocol readme to documentation --- autodocs/system_design.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/autodocs/system_design.rst b/autodocs/system_design.rst index a48558798..43c818d49 100644 --- a/autodocs/system_design.rst +++ b/autodocs/system_design.rst @@ -12,3 +12,5 @@ System Design :parser: myst_parser.sphinx_ .. include:: ../docs/reducers.md :parser: myst_parser.sphinx_ +.. include:: ../learning_observer/learning_observer/communication_protocol/README.md + :parser: myst_parser.sphinx_ From 22bf45097b49ce4f37245c3c3ee2525d3510206b Mon Sep 17 00:00:00 2001 From: Paul Brost Date: Wed, 6 Nov 2024 16:00:01 -0500 Subject: [PATCH 008/327] updated npm packages for lo_event --- modules/lo_event/package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/lo_event/package.json b/modules/lo_event/package.json index c7aaee715..d62e93855 100644 --- a/modules/lo_event/package.json +++ b/modules/lo_event/package.json @@ -32,8 +32,8 @@ "lodash": "^4.17.21", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-redux": "^9.1.2", - "redux-thunk": "^2.4.2", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", "sqlite3": "^5.1.6", "uuid": "^10.0.0", "ws": "^8.14.2", @@ -54,7 +54,6 @@ "path-browserify": "^1.0.1", "process": "^0.11.10", "querystring-es3": "^0.2.1", - "redux": "^4.2.1", "stream-browserify": "^3.0.0", "url": "^0.11.3", "util": "^0.12.5", From 4ff4f3a19c0944959e9cff183edac7ef7c7291f4 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 7 Nov 2024 09:41:21 -0500 Subject: [PATCH 009/327] Abstracted current gpt responders to their own module (#178) See #195 for future work. Full commit list * abstracted current gpt responders to their own module * updated wo_requirements to install lo_gpt * added a comment about how we ought to handle responders in the future * updated readme with future work --- modules/lo_gpt/README.md | 34 +++ modules/lo_gpt/lo_gpt/__init__.py | 0 modules/lo_gpt/lo_gpt/gpt.py | 238 ++++++++++++++++++ modules/lo_gpt/lo_gpt/module.py | 26 ++ modules/lo_gpt/setup.cfg | 10 + modules/lo_gpt/setup.py | 14 ++ .../wo_bulk_essay_analysis/gpt.py | 184 +------------- wo_requirements.txt | 1 + 8 files changed, 326 insertions(+), 181 deletions(-) create mode 100644 modules/lo_gpt/README.md create mode 100644 modules/lo_gpt/lo_gpt/__init__.py create mode 100644 modules/lo_gpt/lo_gpt/gpt.py create mode 100644 modules/lo_gpt/lo_gpt/module.py create mode 100644 modules/lo_gpt/setup.cfg create mode 100644 modules/lo_gpt/setup.py diff --git a/modules/lo_gpt/README.md b/modules/lo_gpt/README.md new file mode 100644 index 000000000..34aebb103 --- /dev/null +++ b/modules/lo_gpt/README.md @@ -0,0 +1,34 @@ +# Learning Observer GPT + +This module allows users make queries to a GPT model. + +This code is abstracted directly from the `wo_bulk_essay_analysis` module and should be treated as scaffolding as we determine the appropriate way to use query GPT responders. + +## Long-term goals / Future work + +### General Design + +Currently the GPT responders are using an Object Oriented approach which clashes with much of Learning Observer's design. We ought to change this from an OO approach to a Functional Programming approach. + +### Querying Responders + +This package currently initializes a single GPT responder for use. In practice, we need to keep track of multiple responders depending on the context/use case. The different responders ought to be defined and queried via PMSS like + +```css +.wo .group_a { + gpt_responder: openai; + model: gpt-4o; + temperature: 0.5; +} + +.dynamic-assessment { + gpt_responder: ollama; + ollama_server: http://my-ollama-server.learning-observer.org/ +} + +[school=ncsu] { + open_ai_creds: [NCSU-billed account] +} + +// ... and so on +``` diff --git a/modules/lo_gpt/lo_gpt/__init__.py b/modules/lo_gpt/lo_gpt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modules/lo_gpt/lo_gpt/gpt.py b/modules/lo_gpt/lo_gpt/gpt.py new file mode 100644 index 000000000..69ee8acf1 --- /dev/null +++ b/modules/lo_gpt/lo_gpt/gpt.py @@ -0,0 +1,238 @@ +''' +This file defines connections to various GPT providers. Each provider +defines a chat completion method. Supported large-language proviers: + +- OpenAI ChatGPT +- Ollama + +TODO OpenAI is built to provide multiple choices. The response from their +API looks like `response['choices'][0]['message']['content']`. The Ollama +API only provides a single completion so the response looks like +`response['message']['content']`. Much of the code is shared between both +APIs so the code can be abstracted to the parent class. +''' +import aiohttp +import json +import loremipsum +import os + +import learning_observer.communication_protocol.integration +from learning_observer.log_event import debug_log +import learning_observer.prestartup +import learning_observer.settings + +gpt_responder = None +SYSTEM_PROMPT_DEFAULT = 'You are a helper agent, please help fulfill user requests.' + + +class GPTAPI: + def chat_completion(self, prompt, system_prompt): + ''' + Respond to user prompt + ''' + raise NotImplementedError + + +class GPTInitializationError(Exception): + '''Raise when GPT fails to initialize. + This usually happens when the users forgets to + provide information in the `creds.yaml` file. + ''' + + +class GPTRequestErorr(Exception): + '''Raise when the GPT chat completion raises + an exception + ''' + + +class OpenAIGPT(GPTAPI): + def __init__(self, **kwargs): + ''' + kwargs: + - `model`: the GPT model we should use, defaults to `gpt-3.5-turbo-16k` + - `api_key`: OpenAI api key, defaults to the `OPENAI_API_KEY` environment variable. + ''' + super().__init__() + self.model = kwargs.get('model', 'gpt-3.5-turbo-16k') + self.api_key = kwargs.get('api_key', os.getenv('OPENAI_API_KEY')) + if self.api_key is None: + exception_text = 'Error while starting openai:\n'\ + 'Please ensure that the API Key is correctly configured in '\ + '`creds.yaml` under `modules.writing_observer.gpt_responders.openai.api_key`, '\ + 'or alternatively, set it as the `OPENAI_API_KEY` environment '\ + 'variable.' + raise GPTInitializationError(exception_text) + + async def chat_completion(self, prompt, system_prompt): + url = 'https://api.openai.com/v1/chat/completions' + headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {self.api_key}'} + messages = [ + {'role': 'system', 'content': system_prompt}, + {'role': 'user', 'content': prompt} + ] + content = {'model': self.model, 'messages': messages} + async with aiohttp.ClientSession() as session: + async with session.post(url, headers=headers, json=content) as resp: + json_resp = await resp.json() + if resp.status == 200: + return json_resp['choices'][0]['message']['content'] + error = 'Error occured while making OpenAI request' + if 'error' in json_resp: + error += f"\n{json_resp['error']['message']}" + raise GPTRequestErorr(error) + + +class OllamaGPT(GPTAPI): + '''GPT responder for handling request to the Ollama API + ''' + def __init__(self, **kwargs): + ''' + kwargs + - `model`: the GPT model we should use, defaults to `llama2` + - `host`: Ollama server to connect to - the Ollama client will + default to `localhost:11434`. + ''' + super().__init__() + self.model = kwargs.get('model', 'llama2') + # the Ollama client checks for the `OLLAMA_HOST` env variable + # or defaults to `localhost:11434`. We provide a warning when + # a specific host is not found. + self.ollama_host = kwargs.get('host', os.getenv('OLLAMA_HOST', None)) + if self.ollama_host is None: + debug_log('WARNING:: Ollama host not specified. Defaulting to '\ + '`localhost:11434`.\nTo set a specific host, set '\ + '`modules.writing_observer.gpt_responders.ollama.host` '\ + 'in `creds.yaml` or set the `OLLAMA_HOST` environment '\ + 'variable.\n'\ + 'If you wish to install Ollama and download a model, '\ + 'run the following commands:\n'\ + '```bash\ncurl https://ollama.ai/install.sh | sh\n'\ + 'ollama run \n```') + self.ollama_host = 'http://localhost:11434' + + async def chat_completion(self, prompt, system_prompt): + '''Ollama only returns a single item compared to GPT returning a list + ''' + url = f'{self.ollama_host}/api/chat' + messages = [ + {'role': 'system', 'content': system_prompt}, + {'role': 'user', 'content': prompt} + ] + content = {'model': self.model, 'messages': messages, 'stream': False} + async with aiohttp.ClientSession() as session: + async with session.post(url, json=content) as resp: + json_resp = await resp.json(content_type=None) + if resp.status == 200: + return json_resp['message']['content'] + error = 'Error occured while making Ollama request' + if 'error' in json_resp: + error += f"\n{json_resp['error']['message']}" + raise GPTRequestErorr(error) + + +class StubGPT(GPTAPI): + '''GPT responder for handling stub requests + ''' + def __init__(self, **kwargs): + super().__init__() + + async def chat_completion(self, prompt, system_prompt): + return "\n".join(loremipsum.get_paragraphs(1)) + + +GPT_RESPONDERS = { + 'openai': OpenAIGPT, + 'ollama': OllamaGPT, + 'stub': StubGPT +} + + +@learning_observer.prestartup.register_startup_check +def initialize_gpt_responder(): + '''Iterate over the gpt_responders listed in `creds.yaml` + and attempt to initialize it. On successful initialization + of a responder, exit the this startup check. Otherwise, + try the next one. + ''' + global gpt_responder + # TODO change this to use settings.module_settings() instead + # that method now uses pmss which doesn't support lists and + # dictionaries yet. + # TODO think through how we might use different gpt responders + # with different PMSS groups. We may have mutliple responders + # running on the same system for different modules or schools. + responders = learning_observer.settings.settings['modules']['writing_observer'].get('gpt_responders', {}) + exceptions = [] + for key in responders: + if key not in GPT_RESPONDERS: + exceptions.append(KeyError( + f'GPT Responder `{key}` is not yet configured on this system.\n'\ + f'The available responders are [{", ".join(GPT_RESPONDERS.keys())}].' + )) + continue + try: + gpt_responder = GPT_RESPONDERS[key](**responders[key]) + debug_log(f'INFO:: Using GPT responder `{key}` with model `{responders[key]["model"]}`') + return True + except GPTInitializationError as e: + exceptions.append(e) + debug_log(f'WARNING:: Unable to initialize GPT responder `{key}:`.\n{e}') + gpt_responder = None + no_responders = 'No GPT responders found in `creds.yaml`. To add a responder, add either'\ + '`openai` or `ollama` along with any subsettings to `modules.writing_observer.gpt_responders`.\n'\ + 'Example:\n```\ngpt_responders:\n ollama:\n model: llama2\n```' + exception_strings = '\n'.join(str(e) for e in exceptions) if len(exceptions) > 0 else no_responders + exception_text = 'Unable to initialize a GPT responder. Encountered the following errors:\n'\ + f'{exception_strings}' + raise learning_observer.prestartup.StartupCheck("GPT: " + exception_text) + + +async def api_chat_completion(request): + '''This function drieclty interacts with the gpt_responder + chat completion interface. + + Expected Input (Request): + ------------------------- + - Method: POST + - Content-Type: application/json + - JSON Body: + { + "prompt": "", # Required + "system_prompt": "" # Optional, default `You are a helper agent, please help fulfill user requests.` + } + + Expected Output (Response): + --------------------------- + - Status: 200 OK + - Content-Type: application/json + - JSON Body: + { + "response": "" + } + ''' + # TODO add error handling + global gpt_responder + try: + data = await request.json() + except json.JSONDecodeError: + return aiohttp.web.json_response({"error": "Invalid JSON"}, status=400) + + prompt = data['prompt'] + system_prompt = data.get('system_prompt', SYSTEM_PROMPT_DEFAULT) + response_data = {'response': await gpt_responder.chat_completion(prompt, system_prompt)} + return aiohttp.web.json_response(response_data) + + +async def test_responder(): + responder = OllamaGPT('llama2') + response = await responder.chat_completion('Why is the sky blue?') + print('Response:', response) + + +if __name__ == '__main__': + import asyncio + loop = asyncio.get_event_loop() + asyncio.ensure_future(test_responder()) + loop.run_forever() + loop.close() diff --git a/modules/lo_gpt/lo_gpt/module.py b/modules/lo_gpt/lo_gpt/module.py new file mode 100644 index 000000000..46799d74d --- /dev/null +++ b/modules/lo_gpt/lo_gpt/module.py @@ -0,0 +1,26 @@ +''' +Learning Observer GPT +''' +import learning_observer.downloads as d +import learning_observer.communication_protocol.query as q +from learning_observer.dash_integration import thirdparty_url, static_url +from learning_observer.stream_analytics.helpers import KeyField, Scope + +import lo_gpt.gpt + +# Name for the module +NAME = 'Learning Observer GPT' + +# TODO Create a really simple dashboard for interfacing with the GPT api. +# This should be created in NextJS. +# An input for each api parameter, a submit button, and the json output. + +''' +Additional API calls we can define, this one returns the colors of the rainbow +''' +EXTRA_VIEWS = [{ + 'name': 'GPT Chat Completion', + 'suburl': 'api/llm', + 'method': 'POST', + 'handler': lo_gpt.gpt.api_chat_completion +}] diff --git a/modules/lo_gpt/setup.cfg b/modules/lo_gpt/setup.cfg new file mode 100644 index 000000000..7ca78a5ad --- /dev/null +++ b/modules/lo_gpt/setup.cfg @@ -0,0 +1,10 @@ +[metadata] +name = Learning Observer GPT +description = Use this to iterface with GPT models. + +[options] +packages = lo_gpt + +[options.entry_points] +lo_modules = + lo_gpt = lo_gpt.module diff --git a/modules/lo_gpt/setup.py b/modules/lo_gpt/setup.py new file mode 100644 index 000000000..46795a41f --- /dev/null +++ b/modules/lo_gpt/setup.py @@ -0,0 +1,14 @@ +''' +Install script. Everything is handled in setup.cfg + +To set up locally for development, run `python setup.py develop`, in a +virtualenv, preferably. +''' +from setuptools import setup + +setup( + name="lo_gpt", + package_data={ + 'lo_gpt': ['assets/*'], + } +) diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py index baf06a6a1..c2790fa07 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py @@ -1,175 +1,11 @@ -import aiohttp -import loremipsum -import os - import learning_observer.communication_protocol.integration -from learning_observer.log_event import debug_log import learning_observer.prestartup import learning_observer.settings +import lo_gpt.gpt + template = """[Task]\n{question}\n\n[Essay]\n{text}""" rubric_template = """{task}\n\n[Rubric]\n{rubric}""" -gpt_responder = None - - -class GPTAPI: - def chat_completion(self, prompt, system_prompt): - ''' - Respond to user prompt - ''' - raise NotImplementedError - - -class GPTInitializationError(Exception): - '''Raise when GPT fails to initialize. - This usually happens when the users forgets to - provide information in the `creds.yaml` file. - ''' - - -class GPTRequestErorr(Exception): - '''Raise when the GPT chat completion raises - an exception - ''' - - -class OpenAIGPT(GPTAPI): - def __init__(self, **kwargs): - ''' - kwargs: - - `model`: the GPT model we should use, defaults to `gpt-3.5-turbo-16k` - - `api_key`: OpenAI api key, defaults to the `OPENAI_API_KEY` environment variable. - ''' - super().__init__() - self.model = kwargs.get('model', 'gpt-3.5-turbo-16k') - self.api_key = kwargs.get('api_key', os.getenv('OPENAI_API_KEY')) - if self.api_key is None: - exception_text = 'Error while starting openai:\n'\ - 'Please ensure that the API Key is correctly configured in '\ - '`creds.yaml` under `modules.writing_observer.gpt_responders.openai.api_key`, '\ - 'or alternatively, set it as the `OPENAI_API_KEY` environment '\ - 'variable.' - raise GPTInitializationError(exception_text) - - async def chat_completion(self, prompt, system_prompt): - url = 'https://api.openai.com/v1/chat/completions' - headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {self.api_key}'} - messages = [ - {'role': 'system', 'content': system_prompt}, - {'role': 'user', 'content': prompt} - ] - content = {'model': self.model, 'messages': messages} - async with aiohttp.ClientSession() as session: - async with session.post(url, headers=headers, json=content) as resp: - json_resp = await resp.json() - if resp.status == 200: - return json_resp['choices'][0]['message']['content'] - error = 'Error occured while making OpenAI request' - if 'error' in json_resp: - error += f"\n{json_resp['error']['message']}" - raise GPTRequestErorr(error) - - -class OllamaGPT(GPTAPI): - '''GPT responder for handling request to the Ollama API - ''' - def __init__(self, **kwargs): - ''' - kwargs - - `model`: the GPT model we should use, defaults to `llama2` - - `host`: Ollama server to connect to - the Ollama client will - default to `localhost:11434`. - ''' - super().__init__() - self.model = kwargs.get('model', 'llama2') - # the Ollama client checks for the `OLLAMA_HOST` env variable - # or defaults to `localhost:11434`. We provide a warning when - # a specific host is not found. - self.ollama_host = kwargs.get('host', os.getenv('OLLAMA_HOST', None)) - if self.ollama_host is None: - debug_log('WARNING:: Ollama host not specified. Defaulting to '\ - '`localhost:11434`.\nTo set a specific host, set '\ - '`modules.writing_observer.gpt_responders.ollama.host` '\ - 'in `creds.yaml` or set the `OLLAMA_HOST` environment '\ - 'variable.\n'\ - 'If you wish to install Ollama and download a model, '\ - 'run the following commands:\n'\ - '```bash\ncurl https://ollama.ai/install.sh | sh\n'\ - 'ollama run \n```') - self.ollama_host = 'http://localhost:11434' - - async def chat_completion(self, prompt, system_prompt): - '''Ollama only returns a single item compared to GPT returning a list - ''' - url = f'{self.ollama_host}/api/chat' - messages = [ - {'role': 'system', 'content': system_prompt}, - {'role': 'user', 'content': prompt} - ] - content = {'model': self.model, 'messages': messages, 'stream': False} - async with aiohttp.ClientSession() as session: - async with session.post(url, json=content) as resp: - json_resp = await resp.json() - if resp.status == 200: - return json_resp['message']['content'] - error = 'Error occured while making Ollama request' - if 'error' in json_resp: - error += f"\n{json_resp['error']['message']}" - raise GPTRequestErorr(error) - - -class StubGPT(GPTAPI): - '''GPT responder for handling stub requests - ''' - def __init__(self, **kwargs): - super().__init__() - - async def chat_completion(self, prompt, system_prompt): - return "\n".join(loremipsum.get_paragraphs(1)) - - -GPT_RESPONDERS = { - 'openai': OpenAIGPT, - 'ollama': OllamaGPT, - 'stub': StubGPT -} - - -@learning_observer.prestartup.register_startup_check -def initialize_gpt_responder(): - '''Iterate over the gpt_responders listed in `creds.yaml` - and attempt to initialize it. On successful initialization - of a responder, exit the this startup check. Otherwise, - try the next one. - ''' - global gpt_responder - # TODO change this to use settings.module_settings() instead - # that method now uses pmss which doesn't support lists and - # dictionaries yet. - responders = learning_observer.settings.settings['modules']['writing_observer'].get('gpt_responders', {}) - exceptions = [] - for key in responders: - if key not in GPT_RESPONDERS: - exceptions.append(KeyError( - f'GPT Responder `{key}` is not yet configured on this system.\n'\ - f'The available responders are [{", ".join(GPT_RESPONDERS.keys())}].' - )) - continue - try: - gpt_responder = GPT_RESPONDERS[key](**responders[key]) - debug_log(f'INFO:: Using GPT responder `{key}` with model `{responders[key]["model"]}`') - return True - except GPTInitializationError as e: - exceptions.append(e) - debug_log(f'WARNING:: Unable to initialize GPT responder `{key}:`.\n{e}') - gpt_responder = None - no_responders = 'No GPT responders found in `creds.yaml`. To add a responder, add either'\ - '`openai` or `ollama` along with any subsettings to `modules.writing_observer.gpt_responders`.\n'\ - 'Example:\n```\ngpt_responders:\n ollama:\n model: llama2\n```' - exception_strings = '\n'.join(str(e) for e in exceptions) if len(exceptions) > 0 else no_responders - exception_text = 'Unable to initialize a GPT responder. Encountered the following errors:\n'\ - f'{exception_strings}' - raise learning_observer.prestartup.StartupCheck("GPT: " + exception_text) @learning_observer.communication_protocol.integration.publish_function('wo_bulk_essay_analysis.gpt_essay_prompt') @@ -183,7 +19,7 @@ async def process_student_essay(text, prompt, system_prompt, tags): @learning_observer.cache.async_memoization() async def gpt(gpt_prompt): - completion = await gpt_responder.chat_completion(gpt_prompt, system_prompt) + completion = await lo_gpt.gpt.gpt_responder.chat_completion(gpt_prompt, system_prompt) return completion if len(prompt) == 0: @@ -208,17 +44,3 @@ async def gpt(gpt_prompt): 'prompt': prompt } return output - - -async def test_responder(): - responder = OllamaGPT() - response = await responder.chat_completion('Why is the sky blue?', 'You are a helper agent, please help fulfill user requests.') - print('Response:', response) - - -if __name__ == '__main__': - import asyncio - loop = asyncio.get_event_loop() - asyncio.ensure_future(test_responder()) - loop.run_forever() - loop.close() diff --git a/wo_requirements.txt b/wo_requirements.txt index 54e26e129..5d42da251 100644 --- a/wo_requirements.txt +++ b/wo_requirements.txt @@ -1,3 +1,4 @@ writing_observer @ git+https://github.com/ETS-Next-Gen/writing_observer.git#subdirectory=modules/writing_observer/ +lo_gpt @ git+https://github.com/ETS-Next-Gen/writing_observer.git#subdirectory=modules/lo_gpt/ wo_bulk_essay_analysis @ git+https://github.com/ETS-Next-Gen/writing_observer.git#subdirectory=modules/wo_bulk_essay_analysis/ wo_classroom_text_highlighter @ git+https://github.com/ETS-Next-Gen/writing_observer.git#subdirectory=modules/wo_classroom_text_highlighter/ From cc3a4b7b7eb4a74f2b5f4ff06da3e8c30028c6a1 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 7 Nov 2024 11:00:57 -0500 Subject: [PATCH 010/327] small installation fixes --- Makefile | 3 +++ modules/writing_observer/writing_observer/awe_nlp.py | 1 + 2 files changed, 4 insertions(+) diff --git a/Makefile b/Makefile index f22128c14..019952a31 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,9 @@ install-packages: venv # Using the `--no-binary` option includes all files. pip uninstall -y protobuf pip install --no-binary=protobuf protobuf==4.25 + # Numpy v2 usually gets installed but causes issues with a + # mismatch in binary headers, since something wants numpy v1 + pip install -U numpy==1.26.4 # testing commands test: diff --git a/modules/writing_observer/writing_observer/awe_nlp.py b/modules/writing_observer/writing_observer/awe_nlp.py index 838f82d09..8eb616204 100644 --- a/modules/writing_observer/writing_observer/awe_nlp.py +++ b/modules/writing_observer/writing_observer/awe_nlp.py @@ -75,6 +75,7 @@ def init_nlp(): raise OSError(error_text) from e import awe_components.setup.data awe_components.setup.data.download_models() + nlp = spacy.load('en_core_web_lg') # Adding all of the components, since # each of them turns out to be implicated in From 78723f9fc9306f7b8642634163da103532e57f95 Mon Sep 17 00:00:00 2001 From: Paul Brost Date: Thu, 7 Nov 2024 22:42:55 -0500 Subject: [PATCH 011/327] Update to redux-thunk and compile error fix --- modules/lo_event/lo_event/reduxLogger.js | 2 +- modules/lo_event/lo_event/util.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/lo_event/lo_event/reduxLogger.js b/modules/lo_event/lo_event/reduxLogger.js index 1aac21609..c4087d08f 100644 --- a/modules/lo_event/lo_event/reduxLogger.js +++ b/modules/lo_event/lo_event/reduxLogger.js @@ -19,7 +19,7 @@ * use bits and pieces, or to treat this code as an examplar. */ import * as redux from 'redux'; -import thunk from 'redux-thunk'; +import { default as thunk } from 'redux-thunk'; const EMIT_EVENT = 'EMIT_EVENT'; const EMIT_LOCKFIELDS = 'EMIT_LOCKFIELDS'; diff --git a/modules/lo_event/lo_event/util.js b/modules/lo_event/lo_event/util.js index b2f7d4c34..8641d7bcd 100644 --- a/modules/lo_event/lo_event/util.js +++ b/modules/lo_event/lo_event/util.js @@ -447,8 +447,8 @@ export function treeget(tree, key) { else { if (keylist[i] && keylist[i].indexOf('[')>0) { const item = keylist[i].split('[')[0]; - const idx = keylist[i].split('[')[1]; - idx = idx.split(']')[0]; + const idx_orig = keylist[i].split('[')[1]; + const idx = idx.split(']')[0]; if (item in subtree) { if (subtree[item][idx] !== undefined) { subtree =subtree[item][idx]; From e6a922cdbfd9af6a6a63fb21a55db3513f456570 Mon Sep 17 00:00:00 2001 From: Paul Brost Date: Fri, 8 Nov 2024 15:50:28 -0500 Subject: [PATCH 012/327] import thunk statement change --- modules/lo_event/lo_event/reduxLogger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/lo_event/lo_event/reduxLogger.js b/modules/lo_event/lo_event/reduxLogger.js index c4087d08f..1aac21609 100644 --- a/modules/lo_event/lo_event/reduxLogger.js +++ b/modules/lo_event/lo_event/reduxLogger.js @@ -19,7 +19,7 @@ * use bits and pieces, or to treat this code as an examplar. */ import * as redux from 'redux'; -import { default as thunk } from 'redux-thunk'; +import thunk from 'redux-thunk'; const EMIT_EVENT = 'EMIT_EVENT'; const EMIT_LOCKFIELDS = 'EMIT_LOCKFIELDS'; From d4130300e61220f6b879866bf18e3a302e1c9d25 Mon Sep 17 00:00:00 2001 From: Paul Brost Date: Fri, 8 Nov 2024 16:09:12 -0500 Subject: [PATCH 013/327] Make sure b.storage defaults to thunk if not sync or local --- modules/lo_event/lo_event/browserStorage.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/lo_event/lo_event/browserStorage.js b/modules/lo_event/lo_event/browserStorage.js index 1270569c4..613d0fb31 100644 --- a/modules/lo_event/lo_event/browserStorage.js +++ b/modules/lo_event/lo_event/browserStorage.js @@ -107,12 +107,17 @@ if (typeof browser !== 'undefined') { * - window.localStorage * - thunkStorage */ -if (typeof b !== 'undefined' && b.storage && b.storage.sync) { - debug.info('Setting storage to storage.sync'); - storage = b.storage.sync; -} else if (typeof b !== 'undefined' && b.storage && b.storage.local) { - debug.info('Setting storage to storage.local'); - storage = b.storage.local; +if (typeof b !== 'undefined') { + if (b.storage && b.storage.sync) { + debug.info('Setting storage to storage.sync'); + storage = b.storage.sync; + } else if (b.storage && b.storage.local) { + debug.info('Setting storage to storage.local'); + storage = b.storage.local; + } else { + debug.info('Setting storage to default, thunkStorage'); + storage = thunkStorage; + } } else if (typeof localStorage !== 'undefined') { // Add compatibility modifications for localStorage debug.info('Setting storage to localStorage'); From ad9d485a42a40e7cfbd942d71b652c0f957535a6 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 14 Nov 2024 12:54:03 -0500 Subject: [PATCH 014/327] code compiling for deployment of toy-sba (#198) Co-authored-by: Paul Brost --- modules/lo_event/lo_event/reduxLogger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/lo_event/lo_event/reduxLogger.js b/modules/lo_event/lo_event/reduxLogger.js index 1aac21609..c5b74e60f 100644 --- a/modules/lo_event/lo_event/reduxLogger.js +++ b/modules/lo_event/lo_event/reduxLogger.js @@ -19,7 +19,7 @@ * use bits and pieces, or to treat this code as an examplar. */ import * as redux from 'redux'; -import thunk from 'redux-thunk'; +import { thunk } from 'redux-thunk'; const EMIT_EVENT = 'EMIT_EVENT'; const EMIT_LOCKFIELDS = 'EMIT_LOCKFIELDS'; From 83cdafb1574ce0456f6e9386a17658d44bbf3cf9 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 19 Nov 2024 10:45:29 -0500 Subject: [PATCH 015/327] LO Event improvements The improvements include, function to compile metadata, fixed sending metadata on reconnects, cleaned up event auth pipeline, various linting improvements, abstracted items to their own files, various loevent bug fixes. Full commit list: * Missing semicolons * Slight clean-up of lo_event, and adding logic for extra metadata for debugging * WiP: Sync between computers: metadata code * Sane way of adding many pieces of metadata * Comment * Removing arrows, since those have a bug. Should be readded later. * Moving lo_dash_react_components to Node 22, newer packages * Missing semicolons * Default host for websocket logger * updated extension to use appropriate metadata functions and added metadata to queue on socket startup * added stringify where needed * updated to proper storage item and fixed storage bug * changed order of dispatch event targets * document retry code * updated lo_event tests * code cleanup * updated extension event * fixed typo * updated docstring * updated auth pipeline and fixed a few bugs * re-added python build steps * added some extra information to the lodrc readme --------- Co-authored-by: Piotr Mitros --- extension/writing-process/src/background.js | 30 +- extension/writing-process/src/writing.js | 2 +- .../learning_observer/auth/events.py | 61 +- .../incoming_student_event.py | 4 +- modules/lo_dash_react_components/.npmrc | 1 - modules/lo_dash_react_components/README.md | 6 + .../package-lock.json | 36049 ++++++---------- modules/lo_dash_react_components/package.json | 102 +- .../lib/components/DAProblemDisplay.react.js | 2 +- .../lib/components/WOAnnotatedText.react.js | 21 +- .../lib/components/WOStudentTextTile.react.js | 2 +- .../src/lib/index.scss | 4 +- modules/lo_event/examples/browser_events.html | 20 + modules/lo_event/lo_event/disabler.js | 20 +- modules/lo_event/lo_event/lo_event.js | 92 +- .../lo_event/lo_event/metadata/browserinfo.js | 112 + .../lo_event/lo_event/metadata/chromeauth.js | 49 + modules/lo_event/lo_event/metadata/storage.js | 61 + modules/lo_event/lo_event/util.js | 210 +- modules/lo_event/lo_event/websocketLogger.js | 85 +- modules/lo_event/tests/lo_event.test.js | 4 +- modules/lo_event/tests/ws.test.js | 5 +- 22 files changed, 13580 insertions(+), 23362 deletions(-) delete mode 100644 modules/lo_dash_react_components/.npmrc create mode 100644 modules/lo_event/lo_event/metadata/browserinfo.js create mode 100644 modules/lo_event/lo_event/metadata/chromeauth.js create mode 100644 modules/lo_event/lo_event/metadata/storage.js diff --git a/extension/writing-process/src/background.js b/extension/writing-process/src/background.js index aa569cfed..5396ce383 100644 --- a/extension/writing-process/src/background.js +++ b/extension/writing-process/src/background.js @@ -17,7 +17,9 @@ import * as loEvent from 'lo_event/lo_event/lo_event.js'; import * as loEventDebug from 'lo_event/lo_event/debugLog.js'; import { websocketLogger } from 'lo_event/lo_event/websocketLogger.js'; import { consoleLogger } from 'lo_event/lo_event/consoleLogger.js'; -import * as loEventUtils from 'lo_event/lo_event/util.js'; +import { browserInfo } from 'lo_event/lo_event/metadata/browserinfo.js'; +import { chromeAuth } from 'lo_event/lo_event/metadata/chromeauth.js'; +import { localStorageInfo, sessionStorageInfo } from 'lo_event/lo_event/metadata/storage.js'; // We would like to support fetching the websocket server from storage @@ -33,8 +35,20 @@ const loggers = [ websocketLogger(WEBSOCKET_SERVER_URL) ] -loEvent.init('org.mitros.writing_analytics', '0.01', loggers, loEventDebug.LEVEL.SIMPLE); -loEvent.setFieldSet([loEventUtils.getBrowserInfo(), loEventUtils.fetchDebuggingIdentifier()]); +loEvent.init( + 'org.mitros.writing_analytics', + '0.01', + loggers, + { + debugLevel: loEventDebug.LEVEL.SIMPLE, + metadata: [ + browserInfo(), + chromeAuth(), + localStorageInfo(), + sessionStorageInfo(), + ] + } +); loEvent.go(); // Function to serve as replacement for @@ -205,16 +219,6 @@ async function reinjectContentScripts() { // Let the server know we've loaded. loEvent.logEvent("extension_loaded", {}); -// Send the server the user info. This might not always be available. -// HACK: this code will be changed pending server side changes to how we -// handle auth and metadata. -loEventUtils.profileInfoWrapper().then((result) => { - if (Object.keys(result).length > 0) { - loEvent.logEvent('chrome_identity', { chrome_identity: result }); - loEvent.logEvent('metadata_finished', {}) - } -}); - // And let the console know we've loaded // chrome.extension.getBackgroundPage().console.log("Loaded"); remove logFromServiceWorker("Loaded"); diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index 653544a28..1367e8a81 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -37,7 +37,7 @@ function log_event(event_type, event) { "title": google_docs_title(), "id": doc_id(), "url": window.location.href, - } + }; event['event'] = event_type; // We want to track the page status during events. For example, diff --git a/learning_observer/learning_observer/auth/events.py b/learning_observer/learning_observer/auth/events.py index 96b7a60ec..ba20dfdc2 100644 --- a/learning_observer/learning_observer/auth/events.py +++ b/learning_observer/learning_observer/auth/events.py @@ -53,22 +53,6 @@ def wrapper(f): return wrapper -def find_event(event_type, event_list): - ''' - Find the first event of type `event` in the `event_list` - - Return `None` if no event found. - - >>> find_event('this-one', [{'event': 'not-this-one'}, {'event': 'not-this-one'}, {'event': 'this-one'}]) - {'event': 'this-one'} - >>> find_event('missing-event', [{'event': 'not-this-one'}, {'event': 'not-this-one'}, {'event': 'this-one'}]) - ''' - for e in event_list: - if e.get('event', None) == event_type: - return e - return None - - def encode_id(source, unsafe_id): ''' This is a bit of encoding logic to generically encode IDs from @@ -117,7 +101,7 @@ def token_authorize_user(auth_method, user_id_token): @register_event_auth("http_basic") -async def basic_auth(request, headers, first_event, source): +async def basic_auth(request, event, source): ''' Authenticate with HTTP Basic through nginx. ''' @@ -144,7 +128,7 @@ async def basic_auth(request, headers, first_event, source): @register_event_auth("guest") -async def guest_auth(request, headers, first_event, source): +async def guest_auth(request, event, source): ''' Guest users. @@ -169,7 +153,7 @@ async def guest_auth(request, headers, first_event, source): @register_event_auth("local_storage") -async def local_storage_auth(request, headers, first_event, source): +async def local_storage_auth(request, event, source): ''' This authentication method is used by the browser extension, based on configuration options. Each Chromebook is given a unique ID @@ -188,23 +172,21 @@ async def local_storage_auth(request, headers, first_event, source): >>> a {'sec': 'unauthenticated', 'user_id': 'ls-jim', 'providence': 'ls'} ''' - authdata = find_event('local_storage', headers + [first_event]) - - if authdata is None or 'user_tag' not in authdata: + if 'user_tag' not in event: return False - user_id = "ls-" + authdata['user_tag'] + user_id = "ls-" + event['user_tag'] authenticated = token_authorize_user('local_storage', user_id) return { - 'sec': token_authorize_user('local_storage', user_id), + 'sec': authenticated, constants.USER_ID: user_id, 'providence': 'ls' # local storage } @register_event_auth("chromebook") -async def chromebook_auth(request, headers, first_event, source): +async def chromebook_auth(request, event, source): ''' Authenticate student Chromebooks. @@ -212,20 +194,18 @@ async def chromebook_auth(request, headers, first_event, source): the identity token to the Google ID. TODO: See about client-side oauth on Chromebooks ''' - authdata = find_event('chrome_identity', headers + [first_event]) - - if authdata is None or 'chrome_identity' not in authdata: + if 'chrome_identity' not in event: return False # If we have an auth key, we are authenticated! - lsa = await local_storage_auth(request, headers, first_event, source) + lsa = await local_storage_auth(request, event, source) if lsa and lsa['sec'] == 'authenticated': auth = 'authenticated' else: auth = 'unauthenticated' - untrusted_google_id = authdata.get('chrome_identity', {}).get('id', None) + untrusted_google_id = event.get('chrome_identity', {}).get('id', None) debug_log("untrusted_google_id", untrusted_google_id) if untrusted_google_id is None: @@ -241,7 +221,7 @@ async def chromebook_auth(request, headers, first_event, source): @register_event_auth("hash_identify") -async def hash_identify(request, headers, first_event, source): +async def hash_identify(request, event, source): ''' It's sometimes convenient to point folks to pages where the user ID is encoded in the URL e.g. by hash: @@ -258,38 +238,33 @@ async def hash_identify(request, headers, first_event, source): This could be made better by providing an authenticated user list. Then, it'd be okay for the math team example ''' - authdata = find_event('hash_auth', headers + [first_event]) - debug_log("authdata", authdata) - - if authdata is None or 'hash' not in authdata: + if 'hash' not in event: return False return { 'sec': 'unauthenticated', - constants.USER_ID: "hi-" + authdata['hash'], + constants.USER_ID: "hi-" + event['hash'], 'providence': 'mch' # Math contest hash -- toying with plug-in archicture } @register_event_auth("testcase_auth") -async def test_case_identify(request, headers, first_event, source): +async def test_case_identify(request, event, source): ''' This is for test cases. It's quick, easy, insecure, and shouldn't be used in production. ''' - authdata = find_event('test_framework_fake_identity', headers + [first_event]) - - if authdata is None or constants.USER_ID not in authdata: + if constants.USER_ID not in event: return False return { 'sec': "unauthenticated", - constants.USER_ID: "testcase-" + authdata[constants.USER_ID], + constants.USER_ID: "testcase-" + event[constants.USER_ID], 'providence': 'tc' } -async def authenticate(request, headers, first_event, source): +async def authenticate(request, event, source): ''' Authenticate an event stream. @@ -312,7 +287,7 @@ async def authenticate(request, headers, first_event, source): 3. `user_id` -- a unique user identifier ''' for auth_method in learning_observer.settings.settings['event_auth']: - auth_metadata = await AUTH_METHODS[auth_method](request, headers, first_event, source) + auth_metadata = await AUTH_METHODS[auth_method](request, event, source) if auth_metadata: if "safe_user_id" not in auth_metadata: auth_metadata['safe_user_id'] = encode_id( diff --git a/learning_observer/learning_observer/incoming_student_event.py b/learning_observer/learning_observer/incoming_student_event.py index 1ca84d2b0..6cb7de904 100644 --- a/learning_observer/learning_observer/incoming_student_event.py +++ b/learning_observer/learning_observer/incoming_student_event.py @@ -403,12 +403,10 @@ async def handle_auth_events(events): if not authenticated: authenticated = await learning_observer.auth.events.authenticate( request=request, - headers=[event], - first_event={}, + event=event, source='' ) if authenticated: - print(authenticated) await ws.send_json({ 'status': 'auth', constants.USER_ID: authenticated[constants.USER_ID] diff --git a/modules/lo_dash_react_components/.npmrc b/modules/lo_dash_react_components/.npmrc deleted file mode 100644 index b6f27f135..000000000 --- a/modules/lo_dash_react_components/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/modules/lo_dash_react_components/README.md b/modules/lo_dash_react_components/README.md index 69c606bbe..1db5654bb 100644 --- a/modules/lo_dash_react_components/README.md +++ b/modules/lo_dash_react_components/README.md @@ -4,8 +4,14 @@ In Learning Observer, we create React components and generate a Python package for them to be used with the Dash framework. These components are housed in the `lo_dash_react_components` module and enable the creation of highly customizable dashboards. This document guides you through the component development process, the build process, and using the components in your dashboards. +### Pre-built installation + +These components take a bit of extra infrastructure to build (mainly `node`). If you just with to use these components, without developing new ones or changing current ones, we suggest installing the pre-built package available in the [LO Assets github repository](https://github.com/ETS-Next-Gen/lo_assets/tree/main/lo_dash_react_components). + ### Requirements +TODO verify which Node versions work. Previously, we encountered dependency issues with newer versions of node. + A downstream dependency in the build process may cause breaking behavior depending on your node version. The latest version of Node `v16` (tested on `v16.19.1`) should work fine; however, we've noticed errors on Node `v18`. If you already have `v18` on your system, install [nvm: Node Version Manager](https://github.com/nvm-sh/nvm). When running `nvm` commands within the project without specifying a specific version, it will automatically look for the version defined in the `.nvmrc` file in the root directory. diff --git a/modules/lo_dash_react_components/package-lock.json b/modules/lo_dash_react_components/package-lock.json index 528896ff6..785fdec74 100644 --- a/modules/lo_dash_react_components/package-lock.json +++ b/modules/lo_dash_react_components/package-lock.json @@ -9,110 +9,115 @@ "version": "0.0.1", "license": "AGPL-3.0", "dependencies": { - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", - "bootstrap": "^5.2.3", - "node-sass": "^9.0.0", - "nodemon": "^2.0.21", - "ramda": "^0.26.1", - "react": "^18.2.0", - "react-bootstrap": "^2.7.2", - "react-dom": "^18.2.0", - "react-router": "^6.8.2", - "react-router-dom": "^6.8.2", + "bootstrap": "^5.3.3", + "ramda": "^0.30.1", + "react": "^18.3.1", + "react-bootstrap": "^2.10.5", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0", "react-scripts": "^5.0.1", - "react-tooltip": "^5.20.0", - "recharts": "^2.4.3", - "web-vitals": "^2.1.4" + "react-tooltip": "^5.28.0", + "recharts": "^2.13.3", + "web-vitals": "^4.2.4" }, "devDependencies": { - "@babel/core": "^7.5.4", - "@babel/plugin-proposal-object-rest-spread": "^7.5.4", - "@babel/preset-env": "^7.5.4", - "@babel/preset-react": "^7.0.0", - "@plotly/dash-component-plugins": "^1.2.0", - "@plotly/webpack-dash-dynamic-import": "^1.2.0", - "babel-eslint": "^10.0.2", - "babel-loader": "^8.0.6", - "copyfiles": "^2.1.1", - "css-loader": "^3.0.0", - "eslint": "^6.0.1", - "eslint-config-prettier": "^6.0.0", - "eslint-plugin-import": "^2.18.0", - "eslint-plugin-react": "^7.14.2", + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "@babel/preset-react": "^7.25.9", + "autoprefixer": "^10.4.20", + "babel-loader": "^9.2.1", + "css-loader": "^7.1.2", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.0.0", + "eslint-plugin-standard": "^4.1.0", + "nodemon": "^3.1.7", "npm-run-all": "^4.1.5", - "prop-types": "^15.7.2", - "react-docgen": "^4.1.1", - "style-loader": "^0.23.1", - "styled-jsx": "^5.1.2", - "terser-webpack-plugin": "^2.3.0", - "webpack": "4.37.0", - "webpack-cli": "3.3.6", - "webpack-serve": "3.1.0" + "postcss": "^8.4.47", + "postcss-loader": "^8.1.1", + "prettier": "^3.3.3", + "sass": "^1.80.6", + "style-loader": "^4.0.0", + "tailwindcss": "^3.4.14", + "webpack": "^5.96.1", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.1.0" }, "engines": { - "node": ">=16.0.0 <17.0.0", - "npm": ">=8.11.0" + "node": ">=22.0.0" } }, - "node_modules/@adobe/css-tools": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==" + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.0.tgz", - "integrity": "sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.0", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.0", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.0", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -122,87 +127,130 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", + "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" }, "engines": { - "node": ">=6.9.0" + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", + "license": "MIT", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz", - "integrity": "sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-member-expression-to-functions": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -211,13 +259,24 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.0.tgz", - "integrity": "sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.3.1" + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -226,132 +285,104 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.2" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz", - "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.21.0" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -361,122 +392,110 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", - "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.20.2" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", - "dependencies": { - "@babel/types": "^7.20.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "license": "MIT", "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "@babel/types": "^7.26.0" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -484,12 +503,14 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -498,125 +519,78 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", - "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", - "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.12.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.21.0.tgz", - "integrity": "sha512-MfgX49uRrFUTL/HvWtmx3zmpyzMMr4MTj3d527MLlr/4RTT9G/ytFFP7qet2uM2Ve03b+BkpWUpK+lRXnQ+v9w==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.21.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-json-strings": { + "node_modules/@babel/plugin-proposal-class-properties": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -625,13 +599,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -644,6 +620,8 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -659,6 +637,8 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -670,43 +650,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-proposal-optional-chaining": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", @@ -723,6 +672,8 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -735,15 +686,10 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz", - "integrity": "sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -751,25 +697,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -781,6 +713,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -792,6 +725,7 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -803,6 +737,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -814,11 +749,12 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.21.0.tgz", - "integrity": "sha512-tIoPpGBR8UuM4++ccWN3gifhVvQu7ZizuR1fklhRJrd5ewgbkUS+0KVFeWWxELtn18NTLoW32XV7zyOgIAiz+w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", + "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -827,34 +763,28 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", + "integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", - "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -863,12 +793,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -881,6 +812,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -892,6 +824,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -900,11 +833,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -917,6 +851,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -928,6 +863,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -939,6 +875,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -950,6 +887,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -961,6 +899,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -972,6 +911,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -983,6 +923,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -997,6 +938,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1008,11 +950,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1021,12 +964,46 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", - "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1036,13 +1013,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", - "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1052,11 +1030,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1066,11 +1045,28 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz", - "integrity": "sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1079,19 +1075,33 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz", - "integrity": "sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -1102,12 +1112,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", - "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1117,11 +1128,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", - "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1131,12 +1143,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1146,11 +1159,43 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1160,12 +1205,28 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1175,12 +1236,13 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz", - "integrity": "sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.9.tgz", + "integrity": "sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-flow": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-flow": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1190,11 +1252,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz", - "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1204,13 +1268,29 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1220,11 +1300,27 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1234,11 +1330,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1248,12 +1345,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", - "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1263,13 +1361,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz", - "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1279,14 +1378,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", - "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1296,12 +1396,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1311,12 +1412,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1326,11 +1428,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1339,13 +1442,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1354,12 +1457,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", - "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1368,12 +1472,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1382,12 +1489,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.20.2.tgz", - "integrity": "sha512-KS/G8YI8uwMGKErLFOHS/ekhqdHhpEloxs43NecQHVgo2QuQSyJhGIY1fL8UGl9wy5ItVwwoUL4YxVqsplGq2g==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1396,12 +1505,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", - "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1410,16 +1520,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz", - "integrity": "sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.21.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1428,12 +1536,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", - "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "license": "MIT", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1442,13 +1551,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", - "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1457,13 +1567,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1472,12 +1584,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1486,17 +1599,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz", - "integrity": "sha512-ReY6pxwSzEU0b3r2/T/VhqMKg/AkceBT19X0UptA3/tYi5Pe2eXgEUH+NNMC5nok6c6XQz5tyVTUpuezRfSMSg==", + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.9.tgz", + "integrity": "sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow==", + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1505,12 +1614,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1519,13 +1629,17 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", - "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1534,12 +1648,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", + "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/plugin-transform-react-jsx": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1548,12 +1663,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", + "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1562,12 +1679,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -1576,28 +1695,29 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.0.tgz", - "integrity": "sha512-xo///XTPp3mDzTtrqXoBlK9eiAYW3wv9JXglcn/u1bi60RW11dEUxIgA8cbnDhutS1zacjMRmAwxE0gMklLnZg==", + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-typescript": "^7.20.0" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1606,13 +1726,18 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", + "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -1621,86 +1746,22 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", - "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.20.1", - "@babel/helper-compilation-targets": "^7.20.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.20.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.2", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.20.2", - "@babel/plugin-transform-classes": "^7.20.2", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.20.2", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.19.6", - "@babel/plugin-transform-modules-commonjs": "^7.19.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.6", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.20.1", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.20.2", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1709,32 +1770,29 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-react": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", - "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1743,14 +1801,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-typescript": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.0.tgz", - "integrity": "sha512-myc9mpoVA5m1rF8K8DgLEatOYFDpwC+RkMkjZ0Du6uI62YvDe8uxIEYVs/VCdSJ097nlALiU/yBC7//3nI+hNg==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-transform-typescript": "^7.21.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1759,1058 +1816,1169 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" - }, - "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "license": "MIT", "dependencies": { - "regenerator-runtime": "^0.13.11" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz", - "integrity": "sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw==", - "dev": true, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", + "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", + "license": "MIT", "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.11" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" - }, - "node_modules/@csstools/normalize.css": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", - "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", - "integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" - } + "peerDependencies": { + "@babel/core": "^7.0.0" + } }, - "node_modules/@eslint/eslintrc/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "bin": { - "acorn": "bin/acorn" + "node_modules/@babel/preset-env": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" }, "engines": { - "node": ">=0.4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "node_modules/@babel/preset-react": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz", + "integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==", + "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-react-display-name": "^7.25.9", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/plugin-transform-react-jsx-development": "^7.25.9", + "@babel/plugin-transform-react-pure-annotations": "^7.25.9" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/@babel/preset-typescript": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", + "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", - "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.4.1.tgz", - "integrity": "sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==", - "dependencies": { - "@floating-ui/utils": "^0.1.1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@floating-ui/dom": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.1.tgz", - "integrity": "sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw==", + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.4.1", - "@floating-ui/utils": "^0.1.1" + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@floating-ui/utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.1.tgz", - "integrity": "sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw==" - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { - "node": ">=10.10.0" + "node": ">=6.9.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "engines": { - "node": ">=12.22" + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "engines": { - "node": ">=8" - } + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "license": "MIT" }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "engines": { - "node": ">=8" - } + "node_modules/@csstools/normalize.css": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.1.1.tgz", + "integrity": "sha512-YAYeJ+Xqh7fUou1d1j9XHl44BmsuThiTr4iNrgCQ3J27IbhXsxXDGZ1cXv8Qvs99d4rBbLiSKy3+WZiet32PcQ==", + "license": "CC0-1.0" }, - "node_modules/@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "license": "CC0-1.0", "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0" + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "license": "CC0-1.0", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "license": "CC0-1.0", "dependencies": { - "color-convert": "^2.0.1" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^12 || ^14 || >=16" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "license": "CC0-1.0", "dependencies": { - "fill-range": "^7.0.1" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "license": "CC0-1.0", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=10" + "node": "^12 || ^14 || >=16" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "license": "CC0-1.0", "dependencies": { - "color-name": "~1.1.4" + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" }, "engines": { - "node": ">=7.0.0" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/console/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "license": "CC0-1.0", "dependencies": { - "to-regex-range": "^5.0.1" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "license": "CC0-1.0", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "license": "CC0-1.0", "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "license": "CC0-1.0", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8.6" + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" } }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "license": "CC0-1.0", "dependencies": { - "has-flag": "^4.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/console/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "license": "CC0-1.0", "dependencies": { - "is-number": "^7.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8.0" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "license": "CC0-1.0", "dependencies": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14 || >=16" }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "license": "CC0-1.0", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" } }, - "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" + "node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "license": "CC0-1.0", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" } }, - "node_modules/@jest/core/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10.0.0" } }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@jest/core/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@jest/core/node_modules/color-convert": { + "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "type-fest": "^0.20.2" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/core/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=8" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/core/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@jest/core/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "@floating-ui/utils": "^0.2.8" } }, - "node_modules/@jest/core/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "license": "MIT", "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" } }, - "node_modules/@jest/core/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { - "node": ">=8.6" + "node": ">=10.10.0" } }, - "node_modules/@jest/core/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jest/core/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "license": "BSD-3-Clause" }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@jest/core/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { - "node": ">=8.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/environment/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/environment/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@jest/environment/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@jest/environment/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/environment/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/environment/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, - "node_modules/@jest/environment/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/@jest/expect-utils": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.4.3.tgz", - "integrity": "sha512-/6JWbkxHOP8EoS8jeeTd9dTfc9Uawi+43oLKHfp6zzux3U2hqOOVnV3ai4RpDYHOccL6g+5nrxpoc8DmJxtXVQ==", - "dependencies": { - "jest-get-type": "^29.4.3" - }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/@jest/fake-timers": { + "node_modules/@jest/console": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "license": "MIT", "dependencies": { "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", + "chalk": "^4.0.0", "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "jest-util": "^27.5.1", + "slash": "^3.0.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/@jest/types": { + "node_modules/@jest/core": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/fake-timers/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@jest/fake-timers/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" }, "engines": { - "node": ">=7.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/fake-timers/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/fake-timers/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@jest/fake-timers/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">=0.12.0" + "node": ">=0.10.0" } }, - "node_modules/@jest/fake-timers/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "@sinclair/typebox": "^0.24.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/jest-util": { + "node_modules/@jest/source-map": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "license": "MIT", "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", + "callsites": "^3.0.0", "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "source-map": "^0.6.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">=8.6" + "node": ">=0.10.0" } }, - "node_modules/@jest/fake-timers/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/fake-timers/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" }, "engines": { - "node": ">=8.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/globals": { + "node_modules/@jest/transform": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "license": "MIT", "dependencies": { - "@jest/environment": "^27.5.1", + "@babel/core": "^7.1.0", "@jest/types": "^27.5.1", - "expect": "^27.5.1" + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/types": { + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/types": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", @@ -2822,4996 +2990,5654 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@jest/globals/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=6.0.0" } }, - "node_modules/@jest/globals/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@jest/globals/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "devOptional": true, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": ">=10.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@jest/globals/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", + "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "color-name": "~1.1.4" + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@jest/globals/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/globals/node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "node_modules/@jsonjoy.com/util": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", + "devOptional": true, + "license": "Apache-2.0", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@jest/globals/node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "license": "MIT", "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "eslint-scope": "5.1.1" } }, - "node_modules/@jest/globals/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", "dependencies": { - "to-regex-range": "^5.0.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/globals/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "node": ">=8.0.0" } }, - "node_modules/@jest/globals/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", "engines": { - "node": ">=0.12.0" + "node": ">=4.0" } }, - "node_modules/@jest/globals/node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 8" } }, - "node_modules/@jest/globals/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 8" } }, - "node_modules/@jest/globals/node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 8" } }, - "node_modules/@jest/globals/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/@parcel/watcher": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", + "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/globals/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8.6" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/globals/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/globals/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node": ">= 10.0.0" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=7.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, "engines": { - "node": ">= 10.13.0" + "node": ">=14" } }, - "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.15.tgz", + "integrity": "sha512-LFWllMA55pzB9D34w/wXUCf8+c+IYKuJDgxiZ3qMhl64KRMBHYM1I3VdGaD2BV5FNPV2/S2596bppxHbv2ZydQ==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "ansi-html": "^0.0.9", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^4.2.0", + "source-map": "^0.7.3" }, "engines": { - "node": ">=10" + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x || 5.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/popperjs" } }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@react-aria/ssr": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.6.tgz", + "integrity": "sha512-iLo82l82ilMiVGy342SELjshuWottlb5+VefO3jOQqQRNYnJBFpUSadswDPbRimSgJUZuFwIEYs6AabkP038fA==", + "license": "Apache-2.0", "dependencies": { - "has-flag": "^4.0.0" + "@swc/helpers": "^0.5.0" }, "engines": { - "node": ">=8" + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, + "node_modules/@remix-run/router": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", + "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", + "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "license": "MIT", "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" + "dequal": "^2.0.3" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "peerDependencies": { + "react": ">=16.8.0" } }, - "node_modules/@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "node_modules/@restart/ui": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", + "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", + "license": "MIT", "dependencies": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@babel/runtime": "^7.21.0", + "@popperjs/core": "^2.11.6", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.4.9", + "@types/warning": "^3.0.0", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.1", + "warning": "^4.0.3" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" } }, - "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.14.0" } }, - "node_modules/@jest/test-result/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" }, "engines": { - "node": ">=8" + "node": ">= 10.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } } }, - "node_modules/@jest/test-result/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" }, "engines": { - "node": ">=10" + "node": ">= 10.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@jest/test-result/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/test-result/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" } }, - "node_modules/@jest/test-result/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", - "dependencies": { - "@jest/test-result": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" + "node": ">= 8.0.0" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "license": "MIT" + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz", + "integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==", + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "license": "BSD-3-Clause", "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "type-detect": "4.0.8" } }, - "node_modules/@jest/transform/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "license": "BSD-3-Clause", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "@sinonjs/commons": "^1.7.0" } }, - "node_modules/@jest/transform/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "license": "Apache-2.0", "dependencies": { - "@types/yargs-parser": "*" + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" } }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", + "license": "MIT", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", + "license": "MIT", "engines": { - "node": ">=7.0.0" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/transform/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" }, "engines": { - "node": ">=8.6" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/transform/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "@babel/types": "^7.12.6" }, "engines": { - "node": ">=8.0" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/types": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.4.3.tgz", - "integrity": "sha512-bPYfw8V65v17m2Od1cv44FH+SiKW7w2Xu7trhcdTLUmSv85rfKsP+qXSjO4KGJr4dtPSzl/gvslZBXctf1qGEA==", + "node_modules/@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@swc/helpers": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", + "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", + "license": "Apache-2.0", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "tslib": "^2.4.0" } }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=10.13.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "engines": { - "node": ">=6.0.0" + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@babel/types": "^7.20.7" } }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" + "@types/connect": "*", + "@types/node": "*" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@types/node": "*" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", "dependencies": { - "eslint-scope": "5.1.1" + "@types/node": "*" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" + "@types/express-serve-static-core": "*", + "@types/node": "*" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "license": "MIT" }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" }, - "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@types/d3-color": "*" } }, - "node_modules/@npmcli/fs/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "@types/d3-time": "*" } }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "@types/d3-path": "*" } }, - "node_modules/@npmcli/fs/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==", + "license": "MIT" }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "8.56.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "license": "MIT", "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@types/estree": "*", + "@types/json-schema": "*" } }, - "node_modules/@npmcli/move-file/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@types/eslint": "*", + "@types/estree": "*" } }, - "node_modules/@plotly/dash-component-plugins": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@plotly/dash-component-plugins/-/dash-component-plugins-1.2.3.tgz", - "integrity": "sha512-BjcGvqS+sbp15rnETIWyuPg8imvxboSrHyOlEBGBUurF5v1nHZpfbk4PAYpk8Q6K20ofScbNf1aXp/lOLHAemA==", - "dev": true - }, - "node_modules/@plotly/webpack-dash-dynamic-import": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@plotly/webpack-dash-dynamic-import/-/webpack-dash-dynamic-import-1.3.0.tgz", - "integrity": "sha512-JuleFNu/DqpzjYABv54j2eJ9+bCUut2EjTrEbyPCvAnjdhabOLnJmGl3Tf6ChDadIfao2Q5yH/R1K2q6dElroQ==", - "dev": true + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" }, - "node_modules/@popperjs/core": { - "version": "2.11.6", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", - "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" } }, - "node_modules/@react-aria/ssr": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.5.0.tgz", - "integrity": "sha512-h0MJdSWOd1qObLnJ8mprU31wI8tmKFJMuwT22MpWq6psisOOZaga6Ml4u6Ee6M6duWWISjXvqO4Sb/J0PBA+nQ==", + "node_modules/@types/express-serve-static-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", + "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "license": "MIT", "dependencies": { - "@swc/helpers": "^0.4.14" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" } }, - "node_modules/@remix-run/router": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz", - "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w==", - "engines": { - "node": ">=14" + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" } }, - "node_modules/@restart/hooks": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.9.tgz", - "integrity": "sha512-3BekqcwB6Umeya+16XPooARn4qEPW6vNvwYnlofIYe6h9qG1/VeD7UvShCWx11eFz5ELYmwIEshz+MkPX3wjcQ==", + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "license": "MIT", "dependencies": { - "dequal": "^2.0.2" - }, - "peerDependencies": { - "react": ">=16.8.0" + "@types/node": "*" } }, - "node_modules/@restart/ui": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.1.tgz", - "integrity": "sha512-cMI9DdqZV5VGEyANYM4alHK9/2Lh/mKZAMydztMl6PBLm6EetFbwE2RfYqliloR+EtEULlI4TiZk/XPhQAovxw==", + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.20.7", - "@popperjs/core": "^2.11.6", - "@react-aria/ssr": "^3.4.1", - "@restart/hooks": "^0.4.7", - "@types/warning": "^3.0.0", - "dequal": "^2.0.3", - "dom-helpers": "^5.2.0", - "uncontrollable": "^7.2.1", - "warning": "^4.0.3" - }, - "peerDependencies": { - "react": ">=16.14.0", - "react-dom": ">=16.14.0" + "@types/node": "*" } }, - "node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "@types/istanbul-lib-report": "*" } }, - "node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "undici-types": "~6.19.8" } }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "license": "MIT", "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "@types/node": "*" } }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "license": "MIT" }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "license": "MIT" + }, + "node_modules/@types/q": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.8.tgz", + "integrity": "sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "license": "MIT", "dependencies": { - "type-detect": "4.0.8" + "@types/prop-types": "*", + "csstype": "^3.0.2" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "node_modules/@types/react-transition-group": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@types/react": "*" } }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "license": "MIT", "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" + "@types/node": "*" } }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" } }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "license": "MIT", + "dependencies": { + "@types/express": "*" } }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" } }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "node_modules/@types/yargs": { + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.9.tgz", + "integrity": "sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", + "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "5.62.0" + }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@svgr/babel-preset": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "license": "MIT", "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", - "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", - "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", - "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", - "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@svgr/core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "license": "MIT", "dependencies": { - "@svgr/plugin-jsx": "^5.5.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.0" + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@svgr/core/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "license": "MIT", "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "license": "BSD-2-Clause", "dependencies": { - "@babel/types": "^7.12.6" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@svgr/plugin-jsx": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.12.3", - "@svgr/babel-preset": "^5.5.0", - "@svgr/hast-util-to-babel-ast": "^5.5.0", - "svg-parser": "^2.0.2" + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@svgr/plugin-svgo": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", "dependencies": { - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "svgo": "^1.2.2" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "node": ">=8.0.0" } }, - "node_modules/@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", "dependencies": { - "tslib": "^2.4.0" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, - "node_modules/@swc/helpers/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" }, - "node_modules/@testing-library/dom": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.0.0.tgz", - "integrity": "sha512-+/TLgKNFsYUshOY/zXsQOk+PlFQK+eyJ9T13IDVNJEi+M+Un7xlJK+FZKkbGSnf0+7E1G6PlDhkSYQ/GFiruBQ==", - "peer": true, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=14" + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" } }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@xtuc/ieee754": "^1.2.0" } }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "@xtuc/long": "4.2.2" } }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true - }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true, - "engines": { - "node": ">=8" - } + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, - "node_modules/@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, - "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, - "node_modules/@testing-library/jest-dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" } }, - "node_modules/@testing-library/jest-dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, - "node_modules/@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" - }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=14.15.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } } }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", - "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "license": "BSD-3-Clause" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": ">=12" + "node": ">= 0.6" } }, - "node_modules/@testing-library/react/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 0.6" } }, - "node_modules/@testing-library/react/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.4.0" } }, - "node_modules/@testing-library/react/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=7.0.0" + "node": ">=0.4.0" } }, - "node_modules/@testing-library/react/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/@testing-library/react/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.4.0" } }, - "node_modules/@testing-library/react/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 10.0.0" } }, - "node_modules/@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5" + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" }, "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" + "node": ">=8.9" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, "engines": { - "node": ">= 6" + "node": ">= 6.0.0" } }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "engines": { - "node": ">=10.13.0" + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.0.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" } }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.3.0" + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "node_modules/ansi-html": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", + "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" } }, - "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dependencies": { - "@types/node": "*" + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" } }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dependencies": { - "@types/node": "*" + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@types/d3-array": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.4.tgz", - "integrity": "sha512-nwvEkG9vYOc0Ic7G7kwgviY4AQlTfYGIZ0fqB7CQHXGyYM6nO7kJh5EguSNA3jfh4rq7Sb7eMVq8isuvg2/miQ==" - }, - "node_modules/@types/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", - "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==" + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { - "@types/d3-color": "*" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@types/d3-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", - "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==" + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" }, - "node_modules/@types/d3-scale": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz", - "integrity": "sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==", + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", "dependencies": { - "@types/d3-time": "*" + "sprintf-js": "~1.0.2" } }, - "node_modules/@types/d3-shape": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.1.tgz", - "integrity": "sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==", - "dependencies": { - "@types/d3-path": "*" + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, - "node_modules/@types/d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/@types/d3-timer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", - "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==" + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, - "node_modules/@types/eslint": { - "version": "8.21.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz", - "integrity": "sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ==", + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "license": "MIT", "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" - }, - "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.33", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", - "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "license": "MIT", "dependencies": { - "@types/node": "*" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" - }, - "node_modules/@types/http-proxy": { - "version": "1.17.10", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz", - "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "license": "MIT", "dependencies": { - "@types/node": "*" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "license": "MIT", "dependencies": { - "@types/istanbul-lib-report": "*" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", - "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", + "node_modules/array.prototype.reduce": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz", + "integrity": "sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q==", + "license": "MIT", "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-array-method-boxes-properly": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "is-string": "^1.0.7" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/jest/node_modules/pretty-format": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", - "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 0.4" } }, - "node_modules/@types/jest/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - }, - "node_modules/@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" - }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==" - }, - "node_modules/@types/node": { - "version": "18.14.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.4.tgz", - "integrity": "sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g==" - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==" - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==" + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" }, - "node_modules/@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "license": "MIT" }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, - "node_modules/@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "license": "ISC", + "engines": { + "node": ">= 4.0.0" } }, - "node_modules/@types/react-dom": { - "version": "18.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", - "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "@types/react": "*" + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", "dependencies": { - "@types/react": "*" + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dependencies": { - "@types/node": "*" + "node_modules/axe-core": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", + "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", + "license": "MPL-2.0", + "engines": { + "node": ">=4" } }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==" - }, - "node_modules/@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "dependencies": { - "@types/express": "*" + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, - "node_modules/@types/serve-static": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", - "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "license": "MIT", "dependencies": { - "@types/mime": "*", - "@types/node": "*" + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" } }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" - }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", - "integrity": "sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "license": "BSD-3-Clause", "dependencies": { - "@types/jest": "*" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/trusted-types": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", - "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" - }, - "node_modules/@types/warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", - "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" - }, - "node_modules/@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "license": "MIT", "dependencies": { - "@types/node": "*" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" } }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + "node_modules/babel-plugin-named-asset-import": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "license": "MIT", + "peerDependencies": { + "@babel/core": "^7.1.0" + } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz", - "integrity": "sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/type-utils": "5.54.0", - "@typescript-eslint/utils": "5.54.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "engines": { - "node": ">=8" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@babel/helper-define-polyfill-provider": "^0.6.2" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "node_modules/babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", + "license": "MIT" }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.54.0.tgz", - "integrity": "sha512-rRYECOTh5V3iWsrOzXi7h1jp3Bi9OkJHrb3wECi3DVqMGTilo9wAYmCbT+6cGdrzUY3MWcAa2mESM6FMik6tVw==", + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "5.54.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz", - "integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==", + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/typescript-estree": "5.54.0", - "debug": "^4.3.4" + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@babel/core": "^7.0.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz", - "integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==", + "node_modules/babel-preset-react-app": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", + "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/visitor-keys": "5.54.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-decorators": "^7.16.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", + "@babel/plugin-proposal-numeric-separator": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.0", + "@babel/plugin-proposal-private-methods": "^7.16.0", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/preset-react": "^7.16.0", + "@babel/preset-typescript": "^7.16.0", + "@babel/runtime": "^7.16.3", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz", - "integrity": "sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "license": "MIT" + }, + "node_modules/bfj": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.1.0.tgz", + "integrity": "sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==", + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.54.0", - "@typescript-eslint/utils": "5.54.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "bluebird": "^3.7.2", + "check-types": "^11.2.3", + "hoopy": "^0.1.4", + "jsonpath": "^1.1.1", + "tryer": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">= 8.0.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz", - "integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==", + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": "*" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz", - "integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==", - "dependencies": { - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/visitor-keys": "5.54.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "ms": "2.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.0.tgz", - "integrity": "sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==", + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.54.0", - "@typescript-eslint/types": "5.54.0", - "@typescript-eslint/typescript-estree": "5.54.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">=0.10.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", "peerDependencies": { - "eslint": ">=5" + "@popperjs/core": "^2.11.8" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "engines": { - "node": ">=10" + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "fill-range": "^7.1.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { - "semver": "bin/semver.js" + "browserslist": "cli.js" }, "engines": { - "node": ">=10" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz", - "integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==", + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/types": "5.54.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node-int64": "^0.4.0" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/builtin-modules": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", - "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "node_modules/builtins": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5" + "semver": "^7.0.0" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", - "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", - "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", - "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==" - }, - "node_modules/@webassemblyjs/helper-code-frame": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", - "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/wast-printer": "1.8.5" + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@webassemblyjs/helper-fsm": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", - "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==" - }, - "node_modules/@webassemblyjs/helper-module-context": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", - "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", - "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "mamacro": "^0.0.3" + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/helper-numbers/node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" - }, - "node_modules/@webassemblyjs/helper-numbers/node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", - "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", - "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", - "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5" + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", - "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "license": "MIT", "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", - "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", - "dependencies": { - "@xtuc/long": "4.2.2" + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", - "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", - "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", - "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/helper-wasm-section": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-opt": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "@webassemblyjs/wast-printer": "1.8.5" + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" } }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", - "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", - "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", - "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-buffer": "1.8.5", - "@webassemblyjs/wasm-gen": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5" - } + "node_modules/caniuse-lite": { + "version": "1.0.30001679", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001679.tgz", + "integrity": "sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", - "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", - "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-wasm-bytecode": "1.8.5", - "@webassemblyjs/ieee754": "1.8.5", - "@webassemblyjs/leb128": "1.8.5", - "@webassemblyjs/utf8": "1.8.5" - } - }, - "node_modules/@webassemblyjs/wast-parser": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", - "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", - "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/floating-point-hex-parser": "1.8.5", - "@webassemblyjs/helper-api-error": "1.8.5", - "@webassemblyjs/helper-code-frame": "1.8.5", - "@webassemblyjs/helper-fsm": "1.8.5", - "@xtuc/long": "4.2.2" + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", - "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/wast-parser": "1.8.5", - "@xtuc/long": "4.2.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "node_modules/check-types": { + "version": "11.2.3", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", + "integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==", + "license": "MIT" }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "bin": { - "acorn": "bin/acorn" + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" }, "engines": { - "node": ">=0.4.0" + "node": ">= 6" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } + "node_modules/cjs-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "license": "MIT" }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">= 10.0" } }, - "node_modules/address": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 10.0.0" + "node": ">=0.10.0" } }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, - "engines": { - "node": ">=8.9" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", "dependencies": { - "debug": "4" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" }, "engines": { - "node": ">= 6.0.0" + "node": ">=6" } }, - "node_modules/agentkeepalive": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { - "node": ">= 8.0.0" + "node": ">=6" } }, - "node_modules/agentkeepalive/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 4.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/coa/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "color-convert": "^1.9.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "peerDependencies": { - "ajv": ">=5.0.0" + "engines": { + "node": ">=4" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/coa/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "engines": { + "node": ">=4" } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "node_modules/coa/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "color-name": "1.1.3" } }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "node_modules/coa/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" + "node_modules/coa/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/coa/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/coa/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "license": "MIT" }, - "node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">= 12" } }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true, + "license": "ISC" }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "license": "MIT" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "mime-db": ">= 1.43.0 < 2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.6" } }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "node_modules/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" }, "engines": { - "node": ">= 6" + "node": ">= 0.8.0" } }, - "node_modules/are-we-there-yet/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "ms": "2.0.0" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dependencies": { - "deep-equal": "^2.0.5" + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "license": "MIT" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "license": "MIT", + "engines": { + "node": ">=0.8" } }, - "node_modules/aria-query/node_modules/deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "safe-buffer": "5.2.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aria-query/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, - "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "node_modules/core-js": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" + "browserslist": "^4.24.2" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "engines": { - "node": ">=8" + "node_modules/core-js-pure": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.39.0.tgz", + "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", - "engines": { - "node": ">=0.10.0" - } + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" }, - "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "node_modules/cross-spawn": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/array.prototype.reduce": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", - "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "license": "CC0-1.0", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, "engines": { - "node": ">=0.10.0" + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": "~2.1.0" + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" } }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "license": "CC0-1.0", "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "node_modules/css-loader": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", + "dev": true, + "license": "MIT", "dependencies": { - "object-assign": "^4.1.1", - "util": "0.10.3" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "optional": true, - "peer": true, + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, "engines": { - "node": ">=0.8" + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/assert/node_modules/inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" - }, - "node_modules/assert/node_modules/util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "license": "MIT", "dependencies": { - "inherits": "2.0.1" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } } }, - "node_modules/ast-types": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", - "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==", - "dev": true, + "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" - }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "license": "CC0-1.0", + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, "engines": { - "node": ">=4" + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "license": "BSD-2-Clause", "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/async-each": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "optional": true - }, - "node_modules/async-foreach": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==", - "engines": { - "node": "*" + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "devOptional": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "license": "MIT" }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, "engines": { - "node": ">= 4.0.0" + "node": ">=8.0.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "bin": { - "atob": "bin/atob.js" - }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 4.5.0" + "node": ">=0.10.0" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" + "node": ">= 6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "optional": true, - "peer": true, - "engines": { - "node": "*" + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "optional": true, - "peer": true + "node_modules/cssdb": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.11.2.tgz", + "integrity": "sha512-lhQ32TFkc1X4eTefGfYPvgovRSzIMofHkigfH8nWtyRL4XJLsRhJFreRvEgKzept7x1rjBuy3J/MurXLaFxW/A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ], + "license": "CC0-1.0" }, - "node_modules/axe-core": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz", - "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, "engines": { "node": ">=4" } }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/axobject-query/node_modules/deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/axobject-query/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", - "dev": true, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" }, "engines": { - "node": ">=6" + "node": "^10 || ^12 || >=14.0" }, "peerDependencies": { - "eslint": ">= 4.12.1" + "postcss": "^8.2.15" } }, - "node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", - "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^10 || ^12 || >=14.0" }, "peerDependencies": { - "@babel/core": "^7.8.0" + "postcss": "^8.2.15" } }, - "node_modules/babel-jest/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "css-tree": "^1.1.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8.0.0" } }, - "node_modules/babel-jest/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "license": "CC0-1.0" + }, + "node_modules/csso/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "cssom": "~0.3.6" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "internmap": "1 - 2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=12" } }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { - "node": ">=7.0.0" + "node": ">=12" } }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "d3-color": "1 - 3" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/babel-loader": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", - "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" + "node": ">=12" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "d3-path": "^3.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" } }, - "node_modules/babel-plugin-macros": { + "node_modules/d3-time": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" + "d3-array": "2 - 3" }, "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/babel-plugin-named-asset-import": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", - "peerDependencies": { - "@babel/core": "^7.1.0" + "node": ">=12" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" + "d3-time": "1 - 3" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=12" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "license": "BSD-2-Clause" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=10" } }, - "node_modules/babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", - "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" - }, - "node_modules/babel-preset-current-node-syntax": { + "node_modules/data-view-buffer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "license": "MIT", "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.4" }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-react-app": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", - "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-decorators": "^7.16.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-transform-flow-strip-types": "^7.16.0", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "babel-plugin-macros": "^3.1.0", - "babel-plugin-transform-react-remove-prop-types": "^0.4.24" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "license": "MIT", "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" + "ms": "^2.1.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "license": "MIT" }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "optional": true, - "peer": true, - "dependencies": { - "tweetnacl": "^0.14.3" + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/bfj": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", - "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "devOptional": true, + "license": "MIT", "dependencies": { - "bluebird": "^3.5.5", - "check-types": "^11.1.1", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" }, "engines": { - "node": ">= 8.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "devOptional": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { - "file-uri-to-path": "1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" } }, - "node_modules/body-parser/node_modules/http-errors": { + "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/body-parser/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { - "node": ">= 0.8" - } - }, - "node_modules/bonjour-service": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz", - "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==", - "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" + "node": ">=6" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/bootstrap": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", - "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "peerDependencies": { - "@popperjs/core": "^2.11.6" + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" } }, - "node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT" + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" }, "engines": { - "node": ">=0.10.0" + "node": ">= 4.2.1" } }, - "node_modules/braces/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" } }, - "node_modules/browserify-sign": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", - "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "license": "Apache-2.0", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.4", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.6", - "readable-stream": "^3.6.2", - "safe-buffer": "^5.2.1" + "esutils": "^2.0.2" }, "engines": { - "node": ">= 4" + "node": ">=6.0.0" } }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "utila": "~0.4" } }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" } }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", "dependencies": { - "pako": "~1.0.5" + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "type": "github", + "url": "https://github.com/sponsors/fb55" } ], + "license": "BSD-2-Clause" + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "deprecated": "Use your platform's native DOMException instead", + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" + "webidl-conversions": "^5.0.0" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=8" } }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dependencies": { - "node-int64": "^0.4.0" + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=8" } }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" - }, - "node_modules/buffer/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "domelementtype": "^2.2.0" + }, "engines": { - "node": ">=6" + "node": ">= 4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/cacache": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", - "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", - "dev": true, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", "dependencies": { - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "minipass": "^3.0.0", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "p-map": "^3.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^2.7.1", - "ssri": "^7.0.0", - "unique-filename": "^1.1.1" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/cacache/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/cacache/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" } }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "license": "BSD-2-Clause" + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/cache-content-type": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", - "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", - "devOptional": true, - "dependencies": { - "mime-types": "^2.1.18", - "ylru": "^1.2.0" - }, - "engines": { - "node": ">= 6.0.0" - } + "node_modules/electron-to-chromium": { + "version": "1.5.55", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.55.tgz", + "integrity": "sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==", + "license": "ISC" }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 4" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "license": "MIT", "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/camel-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, "engines": { - "node": ">= 6" + "node": ">=4" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/camelcase-keys/node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "engines": { - "node": ">=8" - } + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "license": "MIT" }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001458", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001458.tgz", - "integrity": "sha512-lQ1VlUUq5q9ro9X+5gOEyH7i3vm+AYVT1WDCVB69XOZ17KZRhnZ9J0Sqz7wTHQaLBJccNCHq8/Ww5LlOIZbB0w==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "node_modules/es-iterator-helpers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", + "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.3", + "safe-array-concat": "^1.1.2" + }, "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "optional": true, - "peer": true + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "license": "MIT" }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "es-errors": "^1.3.0" }, "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, - "node_modules/check-types": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", - "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/chokidar/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", "dependencies": { - "to-regex-range": "^5.0.1" + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=8" + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/chokidar/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, "engines": { - "node": ">=0.12.0" + "node": ">=0.10.0" } }, - "node_modules/chokidar/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "is-number": "^7.0.0" + "semver": "^7.5.4" }, "engines": { - "node": ">=8.0" + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "node_modules/eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" + }, "engines": { - "node": ">=6.0" + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0" } }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, "funding": [ { "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } ], + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" } }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" + "ms": "^2.1.1" } }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "node_modules/eslint-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "license": "MIT", "dependencies": { - "is-descriptor": "^0.1.0" + "debug": "^3.2.7" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "ms": "^2.1.1" } }, - "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "peer": true, "dependencies": { - "kind-of": "^3.0.2" + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" }, "engines": { - "node": ">=0.10.0" + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" } }, - "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "license": "BSD-3-Clause", "dependencies": { - "is-buffer": "^1.1.5" + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=12.0.0" + }, + "peerDependencies": { + "@babel/plugin-syntax-flow": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.9", + "eslint": "^8.1.0" } }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/class-utils/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } }, - "node_modules/clean-css": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", - "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "license": "Apache-2.0", "dependencies": { - "source-map": "~0.6.0" + "esutils": "^2.0.2" }, "engines": { - "node": ">= 10.0" + "node": ">=0.10.0" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "engines": { - "node": ">=6" + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/eslint-plugin-jest": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "license": "MIT", "dependencies": { - "restore-cursor": "^3.1.0" + "@typescript-eslint/experimental-utils": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } } }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, "engines": { - "node": ">= 10" + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/eslint-plugin-n": { + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.5.0", + "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", + "ignore": "^5.2.4", + "is-builtin-module": "^3.2.1", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" + }, "engines": { - "node": ">=8" + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "ansi-regex": "^5.0.1" + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "node_modules/eslint-plugin-n/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" + "node": ">=10" }, - "engines": { - "node": ">= 4.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "license": "MIT", "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" } }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "node_modules/eslint-plugin-node/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", "bin": { - "color-support": "bin.js" + "semver": "bin/semver.js" } }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" - }, - "node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + "node_modules/eslint-plugin-promise": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", + "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" + "node_modules/eslint-plugin-react": { + "version": "7.37.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", + "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.1.0", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "license": "MIT", "engines": { - "node": ">=4.0.0" + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "license": "Apache-2.0", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "esutils": "^2.0.2" }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "license": "MIT", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">= 0.8.0" + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/compression/node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "engines": { - "node": ">= 0.8" + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" + "node_modules/eslint-plugin-standard": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz", + "integrity": "sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peerDependencies": { + "eslint": ">=5.0.0" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/eslint-plugin-testing-library": { + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz", + "integrity": "sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw==", + "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "@typescript-eslint/utils": "^5.58.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0 || ^8.0.0" } }, - "node_modules/concat-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "license": "BSD-2-Clause", "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" - }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "devOptional": true, + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=0.8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "5.2.1" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": ">= 0.6" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "license": "Apache-2.0", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/cookies": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", - "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", - "devOptional": true, - "dependencies": { - "depd": "~2.0.0", - "keygrip": "~1.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dependencies": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/copy-concurrently/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "license": "MIT", "dependencies": { - "minimist": "^1.2.6" + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "dependencies": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" + "node": ">= 12.13.0" }, - "bin": { - "copyfiles": "copyfiles", - "copyup": "copyfiles" - } - }, - "node_modules/core-js": { - "version": "3.29.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.0.tgz", - "integrity": "sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg==", - "hasInstallScript": true, "funding": { "type": "opencollective", - "url": "https://opencollective.com/core-js" + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" } }, - "node_modules/core-js-compat": { - "version": "3.29.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.29.0.tgz", - "integrity": "sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ==", + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "license": "MIT", "dependencies": { - "browserslist": "^4.21.5" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/core-js-pure": { - "version": "3.29.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.29.0.tgz", - "integrity": "sha512-v94gUjN5UTe1n0yN/opTihJ8QBWD2O8i19RfTZR7foONPWArnjB96QA/wk5ozu1mm6ja3udQCzOzwQXTxi3xOQ==", - "hasInstallScript": true, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cosmiconfig/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" @@ -7820,1330 +8646,1291 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=4.8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/css-loader": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", - "dev": true, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 8.9.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/css-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/css-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" - }, - "node_modules/css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "license": "BSD-2-Clause", "dependencies": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-unit-converter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", - "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" - }, - "node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==" - }, - "node_modules/cssdb": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.4.1.tgz", - "integrity": "sha512-0Q8NOMpXJ3iTDDbUv9grcmQAfdDx4qz+fN/+Md2FGbevT+6+bJNQ2LjB2YIUlLbpBTM32idU1Sb+tb/uGt6/XQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "url": "https://opencollective.com/eslint" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", "bin": { - "cssesc": "bin/cssesc" + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { "node": ">=4" } }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "license": "BSD-3-Clause", "dependencies": { - "css-tree": "^1.1.2" + "estraverse": "^5.1.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=0.10" } }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=4.0" } }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dependencies": { - "cssom": "~0.3.6" - }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", "engines": { - "node": ">=8" + "node": ">=4.0" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" - }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "node_modules/cyclist": { + "node_modules/estree-walker": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "license": "MIT" }, - "node_modules/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ==", - "dependencies": { - "internmap": "1 - 2" - }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 0.6" } }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "engines": { - "node": ">=12" - } + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=0.8.x" } }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", "dependencies": { - "d3-color": "1 - 3" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "engines": { - "node": ">=12" + "node": ">= 0.8.0" } }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" }, "engines": { - "node": ">=12" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "license": "MIT", "dependencies": { - "d3-path": "^3.1.0" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { - "node": ">=12" + "node": ">= 0.10.0" } }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { - "d3-array": "2 - 3" + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">=12" + "node": ">=8.6.0" } }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", "dependencies": { - "d3-time": "1 - 3" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=12" + "node": ">= 6" } }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 4.9.1" } }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "optional": true, - "peer": true, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", "dependencies": { - "assert-plus": "^1.0.0" + "websocket-driver": ">=0.5.1" }, "engines": { - "node": ">=0.10" + "node": ">=0.8.0" } }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" + "bser": "2.1.1" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/decamelize": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-3.2.0.tgz", - "integrity": "sha512-4TgkVUsmmu7oCSyGBm5FvfMoACuoh9EOidm7V5/J2X2djAwwt57qb3F2KMP2ITqODTCSwb+YRV+0Zqrv18k/hw==", - "dev": true, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", "dependencies": { - "xregexp": "^4.2.4" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/decamelize-keys/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" } }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "engines": { - "node": ">=0.10.0" + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" - }, - "node_modules/decimal.js-light": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">=0.10" + "node": ">=10" } }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" - }, - "node_modules/deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==", - "devOptional": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "node_modules/deepmerge": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", - "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "license": "BSD-3-Clause", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4.0" } }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { - "execa": "^5.0.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/default-gateway/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 8" + "node": ">= 0.8" } }, - "node_modules/default-gateway/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "ms": "2.0.0" } }, - "node_modules/default-gateway/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/finalhandler/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8" } }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/default-gateway/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/default-gateway/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/default-gateway/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">= 8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "p-limit": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "license": "MIT", "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "find-up": "^6.3.0" }, "engines": { - "node": ">= 0.4" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, + "node_modules/find-cache-dir/node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "node": ">=12.20" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, "engines": { - "node": ">= 0.8" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "is-callable": "^1.1.3" } }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", - "dev": true, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "node_modules/detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "license": "MIT", "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" }, "engines": { - "node": ">= 4.2.1" - } - }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" + "node": ">=10", + "yarn": ">=1.0.0" }, - "bin": { - "detective": "bin/detective.js" + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" }, - "engines": { - "node": ">=0.8.0" + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "license": "MIT", "dependencies": { - "path-type": "^4.0.0" + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" }, "engines": { - "node": ">=8" + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/dlv": { + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" - }, - "node_modules/dns-packet": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", - "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/form-data": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.2.tgz", + "integrity": "sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=6.0.0" + "node": ">= 6" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" - }, - "node_modules/dom-converter": { + "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" } }, - "node_modules/dom-serializer/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { - "node": ">=0.4", - "npm": ">=1.2" + "node": ">= 0.6" } }, - "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", "dependencies": { - "webidl-conversions": "^5.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "license": "MIT", "dependencies": { - "domelementtype": "^2.2.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { - "node": ">= 4" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/domhandler/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/dot-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", "engines": { - "node": ">=10" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/duplexify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "license": "ISC" }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" } }, - "node_modules/duplexify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/duplexify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "optional": true, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.315", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.315.tgz", - "integrity": "sha512-ndBQYz3Eyy3rASjjQ9poMJGoAlsZ/aZnq6GBsGL4w/4sWIAwiUHVSsMuADbxa8WJw7pZ0oxLpGbtoDt4vRTdCg==" - }, - "node_modules/elliptic": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", - "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" }, - "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "engines": { - "node": ">=10" + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" + "engines": { + "node": ">=6" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/emojis-list": { + "node_modules/global-prefix": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, "engines": { - "node": ">= 4" + "node": ">=6" } }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", "dependencies": { - "once": "^1.4.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/enhanced-resolve": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", - "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" + "get-intrinsic": "^1.1.3" }, - "engines": { - "node": ">=6.9.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/enhanced-resolve/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, - "node_modules/enhanced-resolve/node_modules/memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "license": "MIT" + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "duplexer": "^0.1.2" }, "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/enhanced-resolve/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/enhanced-resolve/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "license": "MIT" }, - "node_modules/enhanced-resolve/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "license": "(Apache-2.0 OR MPL-1.1)" }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "license": "MIT", "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { - "prr": "~1.0.1" + "es-define-property": "^1.0.0" }, - "bin": { - "errno": "cli.js" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/error-stack-parser": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", - "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "dependencies": { - "stackframe": "^1.3.4" + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-abstract": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", - "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -9152,463 +9939,420 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.4" + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" } }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, - "node_modules/es-shim-unscopables": { + "node_modules/hpack.js/node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", "dependencies": { - "has": "^1.0.3" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "safe-buffer": "~5.1.0" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "license": "MIT", "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" }, "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "html-minifier-terser": "cli.js" }, "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": ">=12" } }, - "node_modules/eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": ">=10.13.0" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", - "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", - "dev": true, - "dependencies": { - "get-stdin": "^6.0.0" - }, - "bin": { - "eslint-config-prettier-check": "bin/cli.js" + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" }, "peerDependencies": { - "eslint": ">=3.14.1" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" }, "peerDependenciesMeta": { - "eslint": { + "@rspack/core": { + "optional": true + }, + "webpack": { "optional": true } } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" } }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "node": ">= 0.8" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, - "node_modules/eslint-plugin-jest": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", - "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "^5.0.0" + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=12.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@types/express": "^4.17.13" }, "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { + "@types/express": { "optional": true } } }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", - "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.20.7", - "aria-query": "^5.1.3", - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.6.2", - "axobject-query": "^3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.3", - "language-tags": "=1.0.5", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "semver": "^6.3.0" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "node": ">= 6" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" - }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "node": ">=10.17.0" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "node": ">=10.18" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "harmony-reflect": "^1.4.6" }, "engines": { - "node": ">=8.0.0" + "node": ">=4" } }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">= 4" } }, - "node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/eslint/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "license": "MIT", "dependencies": { - "type-fest": "^0.8.1" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { "node": ">=8" @@ -9617,613 +10361,538 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.8.19" } }, - "node_modules/espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "dependencies": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6.0.0" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" }, "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" + "node": ">= 0.4" } }, - "node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" - }, - "node_modules/esutils": { + "node_modules/internmap": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=10.13.0" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" } }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "license": "MIT", + "engines": { + "node": ">= 10" } }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "license": "MIT", "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "engines": { - "node": ">= 0.8.0" - } + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "license": "MIT", "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", "dependencies": { - "is-descriptor": "^0.1.0" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "kind-of": "^3.0.2" + "builtin-modules": "^3.3.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-brackets/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" + "hasown": "^2.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" + "node": ">= 0.4" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/expect": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.4.3.tgz", - "integrity": "sha512-uC05+Q7eXECFpgDrHdXA4k2rpMyStAYPItEDLyQDo5Ta7fVkJnNA/4zh/OIVkVVNZ1oOK1PipQoyNjuZ6sz6Dg==", - "dependencies": { - "@jest/expect-utils": "^29.4.3", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.4.3", - "jest-message-util": "^29.4.3", - "jest-util": "^29.4.3" + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "node": ">=8" }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/express/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "call-bind": "^1.0.2" }, - "engines": { - "node": ">= 0.8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true, - "peer": true - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "license": "MIT", "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "is-extglob": "^2.1.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/extglob/node_modules/define-property": { + "node_modules/is-inside-container": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "devOptional": true, + "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extglob/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "engines": [ - "node >=0.6.0" - ], - "optional": true, - "peer": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-equals": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz", - "integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==" + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" + "node": ">= 0.4" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-glob/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fast-glob/node_modules/is-number": { + "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } }, - "node_modules/fast-glob/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=8.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-glob/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", "engines": { - "node": ">=8.0" + "node": ">=0.10.0" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dependencies": { - "reusify": "^1.0.4" + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", "dependencies": { - "websocket-driver": ">=0.5.1" + "isobject": "^3.0.1" }, "engines": { - "node": ">=0.8.0" + "node": ">=0.10.0" } }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "license": "MIT", "dependencies": { - "bser": "2.1.1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "license": "MIT", "dependencies": { - "escape-string-regexp": "^1.0.5" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -10231,11616 +10900,1796 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "license": "MIT", "dependencies": { - "flat-cache": "^2.0.1" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "license": "MIT", "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" + "has-symbols": "^1.0.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/file-loader/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "which-typed-array": "^1.1.14" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/file-uri-to-path": { + "node_modules/is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dependencies": { - "minimatch": "^5.0.1" + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" }, "engines": { - "node": ">=10" - } - }, - "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/fill-range/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "license": "BSD-3-Clause", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "license": "BSD-3-Clause", "dependencies": { - "ms": "2.0.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/finalhandler/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/finalhandler/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "license": "MIT", "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "license": "BSD-3-Clause", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.10" + "node": ">=0.10.0" } }, - "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "license": "BSD-3-Clause", "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" - }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "node": ">=8" } }, - "node_modules/flush-write-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/flush-write-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/iterator.prototype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", + "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/flush-write-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/flush-write-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" + "@isaacs/cliui": "^8.0.2" }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "license": "Apache-2.0", "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "optional": true, - "peer": true, + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, "engines": { - "node": "*" + "node": ">=10" } }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", - "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=10", - "yarn": ">=1.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { + "node-notifier": { "optional": true } } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" + "detect-newline": "^3.0.0" }, "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" }, "engines": { - "node": ">= 6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, "engines": { - "node": "*" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "license": "MIT", "dependencies": { - "map-cache": "^0.2.2" + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "license": "MIT", + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, "engines": { - "node": ">= 0.6" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/from2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/from2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" - }, - "node_modules/fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "@jest/types": "^27.5.1", + "@types/node": "*" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" - }, - "node_modules/functions-have-names": { + "node_modules/jest-pnp-resolver": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gaze": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", - "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", - "dependencies": { - "globule": "^1.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "license": "MIT", "engines": { "node": ">=6" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" }, - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "jest-resolve": "*" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "optional": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0" + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "license": "MIT", "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/globule": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", - "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", - "dependencies": { - "glob": "~7.1.1", - "lodash": "^4.17.21", - "minimatch": "~3.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/globule/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globule/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" - }, - "node_modules/gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "dependencies": { - "duplexer": "^0.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "optional": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "optional": true, - "peer": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash-base/node_modules/readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/hash-base/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", - "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", - "devOptional": true - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-minifier-terser/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/html-minifier-terser/node_modules/terser": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz", - "integrity": "sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==", - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-minifier-terser/node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/htmlparser2/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/htmlparser2/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/http-assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", - "integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==", - "devOptional": true, - "dependencies": { - "deep-equal": "~1.0.1", - "http-errors": "~1.8.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" - }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "devOptional": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-errors/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "devOptional": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-middleware": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.2.tgz", - "integrity": "sha512-aYk1rTKqLTus23X3L96LGNCGNgWpG4cG0XoZIT1GUPhhulEHX/QalnO6Vbo+WmKWi4AL2IidjuC0wZtbpg0yhQ==", - "devOptional": true, - "dependencies": { - "http-proxy": "^1.18.1", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "optional": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.14" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" - }, - "node_modules/identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", - "dependencies": { - "harmony-reflect": "^1.4.6" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==" - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" - }, - "node_modules/immer": { - "version": "9.0.19", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", - "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "dependencies": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-local/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-local/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-local/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-local/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-local/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" - }, - "node_modules/ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "devOptional": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "devOptional": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "devOptional": true, - "dependencies": { - "punycode": "2.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "optional": true, - "peer": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" - }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jake/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jake/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", - "dependencies": { - "@jest/core": "^27.5.1", - "import-local": "^3.0.2", - "jest-cli": "^27.5.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", - "dependencies": { - "@jest/types": "^27.5.1", - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-changed-files/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-changed-files/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-circus/node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-circus/node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-cli/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", - "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-config/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-config/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-config/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-config/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-config/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-config/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-diff": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.4.3.tgz", - "integrity": "sha512-YB+ocenx7FZ3T5O9lMVMeLYV4265socJKtkwgk/6YUz/VsEzYDkiMuMhWzZmxm3wDRQvayJu/PjkjjSkjoHsCA==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", - "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", - "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-jsdom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-environment-jsdom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-node/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-environment-node/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-haste-map/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-haste-map/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-haste-map/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-haste-map/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-haste-map/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-jasmine2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-jasmine2/node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-jasmine2/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", - "dependencies": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.4.3.tgz", - "integrity": "sha512-TTciiXEONycZ03h6R6pYiZlSkvYgT0l8aa49z/DLSGYjex4orMUcafuLXYyyEDWB1RKglq00jzwY00Ei7yFNVg==", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", - "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.4.3.tgz", - "integrity": "sha512-1Y8Zd4ZCN7o/QnWdMmT76If8LuDv23Z1DRovBj/vcSFNlGCJGoO8D1nJDw1AdyAGUk0myDLFGN5RbNeJyCRGCw==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.4.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.4.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-message-util/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-message-util/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", - "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-mock/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-mock/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-mock/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-mock/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-mock/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", - "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", - "dependencies": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-resolve-dependencies/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-runner/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-runner/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-runner/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-runtime/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/jest-runtime/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-runtime/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runtime/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-runtime/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-runtime/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-snapshot/node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-snapshot/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/jest-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.4.3.tgz", - "integrity": "sha512-ToSGORAz4SSSoqxDSylWX8JzkOQR7zoBtNRsA7e+1WUX5F8jrOwaNpuh1YfJHJKDHXLHmObv5eOjejUd+/Ws+Q==", - "dependencies": { - "@jest/types": "^29.4.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", - "dependencies": { - "@jest/types": "^27.5.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "leven": "^3.1.0", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", - "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", - "dependencies": { - "ansi-escapes": "^4.3.1", - "chalk": "^4.0.0", - "jest-regex-util": "^28.0.0", - "jest-watcher": "^28.0.0", - "slash": "^4.0.0", - "string-length": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "jest": "^27.0.0 || ^28.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/console/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", - "dependencies": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dependencies": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" - }, - "node_modules/jest-watch-typeahead/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-watch-typeahead/node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", - "dependencies": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.1.3", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/jest-watch-typeahead/node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/jest-watch-typeahead/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/string-length": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", - "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", - "dependencies": { - "char-regex": "^2.0.0", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/string-length/node_modules/char-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", - "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dependencies": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", - "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", - "dev": true, - "dependencies": { - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest/node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest/node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/joi": { - "version": "14.3.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", - "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", - "deprecated": "This module has moved and is now available at @hapi/joi. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", - "devOptional": true, - "dependencies": { - "hoek": "6.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - } - }, - "node_modules/js-base64": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", - "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" - }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "optional": true, - "peer": true - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jsdom/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "optional": true, - "peer": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "optional": true, - "peer": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keygrip": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", - "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", - "devOptional": true, - "dependencies": { - "tsscmp": "1.0.6" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" - } - }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/koa": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.14.1.tgz", - "integrity": "sha512-USJFyZgi2l0wDgqkfD27gL4YGno7TfUkcmOe6UOLFOVuN+J7FwnNu4Dydl4CUQzraM1lBAiGed0M9OVJoT0Kqw==", - "devOptional": true, - "dependencies": { - "accepts": "^1.3.5", - "cache-content-type": "^1.0.0", - "content-disposition": "~0.5.2", - "content-type": "^1.0.4", - "cookies": "~0.8.0", - "debug": "^4.3.2", - "delegates": "^1.0.0", - "depd": "^2.0.0", - "destroy": "^1.0.4", - "encodeurl": "^1.0.2", - "escape-html": "^1.0.3", - "fresh": "~0.5.2", - "http-assert": "^1.3.0", - "http-errors": "^1.6.3", - "is-generator-function": "^1.0.7", - "koa-compose": "^4.1.0", - "koa-convert": "^2.0.0", - "on-finished": "^2.3.0", - "only": "~0.0.2", - "parseurl": "^1.3.2", - "statuses": "^1.5.0", - "type-is": "^1.6.16", - "vary": "^1.1.2" - }, - "engines": { - "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" - } - }, - "node_modules/koa-compose": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", - "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==", - "devOptional": true - }, - "node_modules/koa-compress": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/koa-compress/-/koa-compress-3.1.0.tgz", - "integrity": "sha512-0m24/yS/GbhWI+g9FqtvStY+yJwTObwoxOvPok6itVjRen7PBWkjsJ8pre76m+99YybXLKhOJ62mJ268qyBFMQ==", - "devOptional": true, - "dependencies": { - "bytes": "^3.0.0", - "compressible": "^2.0.0", - "koa-is-json": "^1.0.0", - "statuses": "^1.0.0" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/koa-connect": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/koa-connect/-/koa-connect-2.1.0.tgz", - "integrity": "sha512-O9pcFafHk0oQsBevlbTBlB9co+2RUQJ4zCzu3qJPmGlGoeEZkne+7gWDkecqDPSbCtED6LmhlQladxs6NjOnMQ==", - "devOptional": true - }, - "node_modules/koa-convert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", - "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", - "devOptional": true, - "dependencies": { - "co": "^4.6.0", - "koa-compose": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/koa-is-json": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", - "integrity": "sha512-+97CtHAlWDx0ndt0J8y3P12EWLwTLMXIfMnYDev3wOTwH/RpBGMlfn4bDXlMEg1u73K6XRE9BbUp+5ZAYoRYWw==", - "devOptional": true - }, - "node_modules/koa-route": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/koa-route/-/koa-route-3.2.0.tgz", - "integrity": "sha512-8FsuWw/L+CUWJfpgN6vrlYUDNTheEinG8Zkm97GyuLJNyWjCVUs9p10Ih3jTIWwmDVQcz6827l0RKadAS5ibqA==", - "devOptional": true, - "dependencies": { - "debug": "*", - "methods": "~1.1.0", - "path-to-regexp": "^1.2.0" - } - }, - "node_modules/koa-send": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.1.tgz", - "integrity": "sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==", - "devOptional": true, - "dependencies": { - "debug": "^4.1.1", - "http-errors": "^1.7.3", - "resolve-path": "^1.4.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/koa-static": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/koa-static/-/koa-static-5.0.0.tgz", - "integrity": "sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==", - "devOptional": true, - "dependencies": { - "debug": "^3.1.0", - "koa-send": "^5.0.0" - }, - "engines": { - "node": ">= 7.6.0" - } - }, - "node_modules/koa-static/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "devOptional": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" - }, - "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dependencies": { - "language-subtag-registry": "~0.3.2" - } - }, - "node_modules/lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "dependencies": { - "invert-kv": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/load-json-file/node_modules/type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" - }, - "node_modules/loglevelnext": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-3.0.1.tgz", - "integrity": "sha512-JpjaJhIN1reaSb26SIxDGtE0uc67gPl19OMVHrr+Ggt6b/Vy60jmCtKgQBrygAH0bhRA2nkxgDvM+8QvR8r0YA==", - "devOptional": true, - "engines": { - "node": ">= 6.14.4" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lower-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/make-fetch-happen/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-fetch-happen/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/make-fetch-happen/node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/make-fetch-happen/node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/make-fetch-happen/node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/make-fetch-happen/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/mamacro": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" - }, - "node_modules/map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "dependencies": { - "p-defer": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "dependencies": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/memfs": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", - "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", - "dependencies": { - "fs-monkey": "^1.0.3" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==", - "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "node_modules/memory-fs/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/memory-fs/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/memory-fs/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/memory-fs/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dependencies": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", - "dependencies": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "node_modules/move-concurrently/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" - }, - "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" - }, - "node_modules/nanoid": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", - "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==", - "devOptional": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/no-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.2" - }, - "engines": { - "node": ">= 0.10.5" - } - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/node-gyp/node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/node-gyp/node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/node-gyp/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/node-gyp/node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/node-gyp/node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/node-gyp/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/node-gyp/node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" - }, - "node_modules/node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dependencies": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - } - }, - "node_modules/node-libs-browser/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/node-libs-browser/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, - "node_modules/node-libs-browser/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/node-libs-browser/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/node-libs-browser/node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/node-libs-browser/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" - }, - "node_modules/node-sass": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-9.0.0.tgz", - "integrity": "sha512-yltEuuLrfH6M7Pq2gAj5B6Zm7m+gdZoG66wTqG6mIZV/zijq3M2OO2HswtT6oBspPyFhHDcaxWpsBm0fRNDHPg==", - "hasInstallScript": true, - "dependencies": { - "async-foreach": "^0.1.3", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "gaze": "^1.0.0", - "get-stdin": "^4.0.1", - "glob": "^7.0.3", - "lodash": "^4.17.15", - "make-fetch-happen": "^10.0.4", - "meow": "^9.0.0", - "nan": "^2.17.0", - "node-gyp": "^8.4.1", - "sass-graph": "^4.0.1", - "stdout-stream": "^1.4.0", - "true-case-path": "^2.2.1" - }, - "bin": { - "node-sass": "bin/node-sass" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/node-sass/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/node-sass/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/node-sass/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/node-sass/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/node-sass/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/node-sass/node_modules/get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/node-sass/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/node-sass/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/node-sass/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-sass/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/node-sass/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-sass/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/nodemon": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.21.tgz", - "integrity": "sha512-djN/n2549DUtY33S7o1djRCd7dEm0kBnj9c7S9XVXqRUbuggN1MZH/Nqa+5RFQr63Fbefq37nFXAE9VU86yL1A==", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm-run-all/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/npm-run-all/node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm-run-all/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==" - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "optional": true, - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-path": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", - "dev": true, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz", - "integrity": "sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw==", - "dependencies": { - "array.prototype.reduce": "^1.0.5", - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/only": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", - "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==", - "devOptional": true - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "devOptional": true, - "dependencies": { - "is-wsl": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" - }, - "node_modules/os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "dependencies": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", - "devOptional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "node_modules/parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "dependencies": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "node_modules/parallel-transform/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/parallel-transform/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/parallel-transform/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/parallel-transform/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/param-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/pascal-case/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", - "optional": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", - "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", - "devOptional": true, - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-conf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-conf/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", - "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", - "dev": true, - "dependencies": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.32", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", - "dev": true, - "dependencies": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", - "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/promise-retry/node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types-extra": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "dependencies": { - "react-is": "^16.3.2", - "warning": "^4.0.0" - }, - "peerDependencies": { - "react": ">=0.14.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dependencies": { - "performance-now": "^2.1.0" - } - }, - "node_modules/ramda": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", - "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-app-polyfill": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", - "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", - "dependencies": { - "core-js": "^3.19.2", - "object-assign": "^4.1.1", - "promise": "^8.1.0", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.9", - "whatwg-fetch": "^3.6.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/react-bootstrap": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.7.2.tgz", - "integrity": "sha512-WDSln+mG4RLLFO01stkj2bEx/3MF4YihK9D/dWnHaSxOiQZLbhhlf95D2Jb20X3t2m7vMxRe888FVrfLJoGmmA==", - "dependencies": { - "@babel/runtime": "^7.17.2", - "@restart/hooks": "^0.4.6", - "@restart/ui": "^1.4.1", - "@types/react-transition-group": "^4.4.4", - "classnames": "^2.3.1", - "dom-helpers": "^5.2.1", - "invariant": "^2.2.4", - "prop-types": "^15.8.1", - "prop-types-extra": "^1.1.0", - "react-transition-group": "^4.4.2", - "uncontrollable": "^7.2.1", - "warning": "^4.0.3" - }, - "peerDependencies": { - "@types/react": ">=16.14.8", - "react": ">=16.14.0", - "react-dom": ">=16.14.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "dependencies": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "engines": { - "node": ">=14" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-dev-utils/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-dev-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-dev-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-dev-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@types/node": "*", + "graceful-fs": "^4.2.9" }, "engines": { - "node": ">=7.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-dev-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/react-dev-utils/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" }, "engines": { - "node": ">= 8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-dev-utils/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, "engines": { - "node": ">=10" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-dev-utils/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/jest-watch-typeahead": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", + "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", + "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^28.0.0", + "jest-watcher": "^28.0.0", + "slash": "^4.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0" } }, - "node_modules/react-dev-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-watch-typeahead/node_modules/@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "node_modules/jest-watch-typeahead/node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", "engines": { - "node": ">= 12.13.0" + "node": ">=8" } }, - "node_modules/react-dev-utils/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/jest-watch-typeahead/node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/react-dev-utils/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/jest-watch-typeahead/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" } }, - "node_modules/react-dev-utils/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": { - "p-limit": "^3.0.2" - }, + "node_modules/jest-watch-typeahead/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/react-dev-utils/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/jest-watch-typeahead/node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/react-dev-utils/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/jest-watch-typeahead/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/react-dev-utils/node_modules/shebang-regex": { + "node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/react-dev-utils/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/jest-watch-typeahead/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/react-dev-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-watch-typeahead/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=8" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/react-dev-utils/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/jest-watch-typeahead/node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/react-docgen": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz", - "integrity": "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==", - "dev": true, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.0.0", - "@babel/runtime": "^7.0.0", - "async": "^2.1.4", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "node-dir": "^0.1.10", - "recast": "^0.17.3" - }, - "bin": { - "react-docgen": "bin/react-docgen.js" + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "ansi-regex": "^5.0.1" }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "node_modules/react-refresh": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", - "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-resize-detector": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz", - "integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==", - "dependencies": { - "lodash": "^4.17.21" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + "node": ">=8" } }, - "node_modules/react-router": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz", - "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==", + "node_modules/jest-watch-typeahead/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.3.3" + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": ">=16.8" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/react-router-dom": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.2.tgz", - "integrity": "sha512-N/oAF1Shd7g4tWy+75IIufCGsHBqT74tnzHQhbiUTYILYF0Blk65cg+HPZqwC+6SqEyx033nKqU7by38v3lBZg==", - "dependencies": { - "@remix-run/router": "1.3.3", - "react-router": "6.8.2" - }, + "node_modules/jest-watch-typeahead/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "license": "MIT", "engines": { - "node": ">=14" + "node": ">=12" }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts": { + "node_modules/jest-watch-typeahead/node_modules/string-length": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", - "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "babel-jest": "^27.4.2", - "babel-loader": "^8.2.3", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-preset-react-app": "^10.0.1", - "bfj": "^7.0.2", - "browserslist": "^4.18.1", - "camelcase": "^6.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.1", - "eslint-webpack-plugin": "^3.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "html-webpack-plugin": "^5.5.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^27.4.3", - "jest-resolve": "^27.4.2", - "jest-watch-typeahead": "^1.0.0", - "mini-css-extract-plugin": "^2.4.5", - "postcss": "^8.4.4", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-loader": "^6.2.1", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^7.0.1", - "prompts": "^2.4.2", - "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.1", - "react-refresh": "^0.11.0", - "resolve": "^1.20.0", - "resolve-url-loader": "^4.0.0", - "sass-loader": "^12.3.0", - "semver": "^7.3.5", - "source-map-loader": "^3.0.0", - "style-loader": "^3.3.1", - "tailwindcss": "^3.0.2", - "terser-webpack-plugin": "^5.2.5", - "webpack": "^5.64.4", - "webpack-dev-server": "^4.6.0", - "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" - }, - "bin": { - "react-scripts": "bin/react-scripts.js" + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - }, - "peerDependencies": { - "react": ">= 16", - "typescript": "^3.2.1 || ^4" + "node": ">=12.20" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length/node_modules/char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", + "license": "MIT", + "engines": { + "node": ">=12.20" } }, - "node_modules/react-scripts/node_modules/@babel/eslint-parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", - "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + "node": ">=12" }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/react-scripts/node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/jest-watch-typeahead/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/react-scripts/node_modules/@babel/eslint-parser/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "license": "MIT", + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-cascade-layers": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", - "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", "dependencies": { - "@csstools/selector-specificity": "^2.0.2", - "postcss-selector-parser": "^6.0.10" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">= 10.13.0" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-color-function": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", - "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" + "has-flag": "^4.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "peerDependencies": { - "postcss": "^8.2" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-font-format-keywords": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", - "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=10" }, "peerDependencies": { - "postcss": "^8.2" + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-hwb-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", - "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", - "dependencies": { - "postcss-value-parser": "^4.2.0" + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-ic-unit": { + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", - "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-is-pseudo-class": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", - "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", "dependencies": { - "@csstools/selector-specificity": "^2.0.0", - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "universalify": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.2" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-nested-calc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", - "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "node_modules/jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, + "node_modules/jsonpath/node_modules/esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=0.4.0" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-normalize-display-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", - "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=4.0" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-oklab-function": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", - "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", - "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-stepped-value-functions": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", - "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "language-subtag-registry": "^0.3.20" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=0.10" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-text-decoration-shorthand": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", - "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "node_modules/launch-editor": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" - }, + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-trigonometric-functions": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", - "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": "^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">= 0.8.0" } }, - "node_modules/react-scripts/node_modules/@csstools/postcss-unset-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", - "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "node": ">=10" } }, - "node_modules/react-scripts/node_modules/@csstools/selector-specificity": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.1.1.tgz", - "integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==", - "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" }, - "peerDependencies": { - "postcss": "^8.4", - "postcss-selector-parser": "^6.0.10" + "engines": { + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", - "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-html-community": "^0.0.8", - "common-path-prefix": "^3.0.0", - "core-js-pure": "^3.23.3", - "error-stack-parser": "^2.0.6", - "find-up": "^5.0.0", - "html-entities": "^2.1.0", - "loader-utils": "^2.0.4", - "schema-utils": "^3.0.0", - "source-map": "^0.7.3" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" }, "engines": { - "node": ">= 10.13" - }, - "peerDependencies": { - "@types/webpack": "4.x || 5.x", - "react-refresh": ">=0.10.0 <1.0.0", - "sockjs-client": "^1.4.0", - "type-fest": ">=0.17.0 <4.0.0", - "webpack": ">=4.43.0 <6.0.0", - "webpack-dev-server": "3.x || 4.x", - "webpack-hot-middleware": "2.x", - "webpack-plugin-serve": "0.x || 1.x" - }, - "peerDependenciesMeta": { - "@types/webpack": { - "optional": true - }, - "sockjs-client": { - "optional": true - }, - "type-fest": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - }, - "webpack-hot-middleware": { - "optional": true - }, - "webpack-plugin-serve": { - "optional": true - } + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" - }, - "node_modules/react-scripts/node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" - }, - "node_modules/react-scripts/node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } }, - "node_modules/react-scripts/node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } }, - "node_modules/react-scripts/node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dependencies": { - "@xtuc/long": "4.2.2" - } + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/react-scripts/node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "tslib": "^2.0.3" } }, - "node_modules/react-scripts/node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/react-scripts/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/react-scripts/node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "peerDependencies": { - "acorn": "^8" + "yallist": "^3.0.2" } }, - "node_modules/react-scripts/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" } }, - "node_modules/react-scripts/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "semver": "^6.0.0" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "optional": true, - "peer": true, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" + "tmpl": "1.0.5" } }, - "node_modules/react-scripts/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "license": "CC0-1.0" }, - "node_modules/react-scripts/node_modules/autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 0.6" } }, - "node_modules/react-scripts/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "license": "Unlicense", "dependencies": { - "fill-range": "^7.0.1" + "fs-monkey": "^1.0.4" }, "engines": { - "node": ">=8" + "node": ">= 4.0.0" } }, - "node_modules/react-scripts/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.10.0" } }, - "node_modules/react-scripts/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/react-scripts/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 8" } }, - "node_modules/react-scripts/node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">= 0.6" } }, - "node_modules/react-scripts/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">= 8" + "node": ">=8.6" } }, - "node_modules/react-scripts/node_modules/css-blank-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", - "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { - "css-blank-pseudo": "dist/cli.cjs" + "mime": "cli.js" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/css-declaration-sorter": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", - "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.0.9" + "node": ">= 0.6" } }, - "node_modules/react-scripts/node_modules/css-has-pseudo": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", - "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "bin": { - "css-has-pseudo": "dist/cli.cjs" + "mime-db": "1.52.0" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/css-loader": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "node_modules/mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "license": "MIT", "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.19", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" }, "engines": { "node": ">= 12.13.0" @@ -21853,265 +12702,273 @@ "webpack": "^5.0.0" } }, - "node_modules/react-scripts/node_modules/css-minimizer-webpack-plugin": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", - "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "dependencies": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "postcss": "^8.3.5", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 12.13.0" - }, + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@parcel/css": { - "optional": true - }, - "clean-css": { - "optional": true - }, - "csso": { - "optional": true - }, - "esbuild": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" } }, - "node_modules/react-scripts/node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "minimist": "^1.2.6" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "bin": { + "mkdirp": "bin/cmd.js" } }, - "node_modules/react-scripts/node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3" + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" }, - "peerDependencies": { - "ajv": "^8.8.2" + "bin": { + "multicast-dns": "cli.js" } }, - "node_modules/react-scripts/node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" } }, - "node_modules/react-scripts/node_modules/css-prefers-color-scheme": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "bin": { - "css-prefers-color-scheme": "dist/cli.cjs" + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/react-scripts/node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "license": "MIT" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/react-scripts/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "node_modules/react-scripts/node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node": ">= 6.13.0" } }, - "node_modules/react-scripts/node_modules/cssnano": { - "version": "5.1.15", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", - "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", + "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", + "dev": true, + "license": "MIT", "dependencies": { - "cssnano-preset-default": "^5.2.14", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=10" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/react-scripts/node_modules/cssnano-preset-default": { - "version": "5.2.14", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", - "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", - "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^3.1.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^5.3.1", - "postcss-convert-values": "^5.1.3", - "postcss-discard-comments": "^5.1.2", - "postcss-discard-duplicates": "^5.1.0", - "postcss-discard-empty": "^5.1.1", - "postcss-discard-overridden": "^5.1.0", - "postcss-merge-longhand": "^5.1.7", - "postcss-merge-rules": "^5.1.4", - "postcss-minify-font-values": "^5.1.0", - "postcss-minify-gradients": "^5.1.1", - "postcss-minify-params": "^5.1.4", - "postcss-minify-selectors": "^5.2.1", - "postcss-normalize-charset": "^5.1.0", - "postcss-normalize-display-values": "^5.1.0", - "postcss-normalize-positions": "^5.1.1", - "postcss-normalize-repeat-style": "^5.1.1", - "postcss-normalize-string": "^5.1.0", - "postcss-normalize-timing-functions": "^5.1.0", - "postcss-normalize-unicode": "^5.1.1", - "postcss-normalize-url": "^5.1.0", - "postcss-normalize-whitespace": "^5.1.1", - "postcss-ordered-values": "^5.1.3", - "postcss-reduce-initial": "^5.1.2", - "postcss-reduce-transforms": "^5.1.0", - "postcss-svgo": "^5.1.0", - "postcss-unique-selectors": "^5.1.1" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "url": "https://opencollective.com/nodemon" } }, - "node_modules/react-scripts/node_modules/cssnano-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", - "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "has-flag": "^3.0.0" }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "engines": { + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/react-scripts/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "node_modules/react-scripts/node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -22119,782 +12976,772 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/eslint": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz", - "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@eslint/eslintrc": "^2.0.0", - "@eslint/js": "8.35.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" }, "bin": { - "eslint": "bin/eslint.js" + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 4" } }, - "node_modules/react-scripts/node_modules/eslint-config-react-app": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", - "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", + "node_modules/npm-run-all/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.0" + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "node_modules/npm-run-all/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", "dependencies": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@babel/plugin-syntax-flow": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.9", - "eslint": "^8.1.0" + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" } }, - "node_modules/react-scripts/node_modules/eslint-plugin-testing-library": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.2.tgz", - "integrity": "sha512-f1DmDWcz5SDM+IpCkEX0lbFqrrTs8HRsEElzDEqN/EBI0hpRj8Cns5+IVANXswE8/LeybIJqPAOQIFu2j5Y5sw==", + "node_modules/npm-run-all/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^5.43.0" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0", - "npm": ">=6" - }, - "peerDependencies": { - "eslint": "^7.5.0 || ^8.0.0" + "node": ">=4.8" + } + }, + "node_modules/npm-run-all/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" } }, - "node_modules/react-scripts/node_modules/eslint-utils": { + "node_modules/npm-run-all/node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/eslint-webpack-plugin": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", - "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint": "^7.29.0 || ^8.4.1", - "jest-worker": "^28.0.2", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "webpack": "^5.0.0" + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/eslint-webpack-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "isexe": "^2.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "bin": { + "which": "bin/which" } }, - "node_modules/react-scripts/node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3" + "path-key": "^3.0.0" }, - "peerDependencies": { - "ajv": "^8.8.2" + "engines": { + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/eslint-webpack-plugin/node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "boolbase": "^1.0.0" }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz", + "integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==", + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/eslint-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">= 6" } }, - "node_modules/react-scripts/node_modules/eslint-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-scripts/node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" } }, - "node_modules/react-scripts/node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "license": "MIT", "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/react-scripts/node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-scripts/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/react-scripts/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-scripts/node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz", + "integrity": "sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A==", + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "array.prototype.reduce": "^1.0.6", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "gopd": "^1.0.1", + "safe-array-concat": "^1.1.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/react-scripts/node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "node_modules/react-scripts/node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "optional": true, - "peer": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" + "node": ">= 0.8" }, - "engines": { - "node": ">=10" - } - }, - "node_modules/react-scripts/node_modules/get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-scripts/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" }, "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" } }, - "node_modules/react-scripts/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-scripts/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" + "node": ">= 0.8" } }, - "node_modules/react-scripts/node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" } }, - "node_modules/react-scripts/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-scripts/node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=6" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, "engines": { - "node": ">= 4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, "engines": { - "node": ">=0.12.0" + "node": ">= 0.8.0" } }, - "node_modules/react-scripts/node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "devOptional": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" }, "engines": { - "node": ">=10" + "node": ">=16.17" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" }, - "node_modules/react-scripts/node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" + "dot-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/react-scripts/node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, "engines": { - "node": ">=6.11.5" + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/react-scripts/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/mini-css-extract-plugin": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", - "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", "dependencies": { - "schema-utils": "^4.0.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">=16 || 14 >=14.18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/react-scripts/node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" }, - "node_modules/react-scripts/node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" }, - "node_modules/react-scripts/node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "node_modules/path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", "engines": { - "node": ">= 12.13.0" + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/react-scripts/node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true, + "license": "MIT", "bin": { - "nanoid": "bin/nanoid.cjs" + "pidtree": "bin/pidtree.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=0.10" } }, - "node_modules/react-scripts/node_modules/node-sass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.3.tgz", - "integrity": "sha512-8MIlsY/4dXUkJDYht9pIWBhMil3uHmE8b/AdJPjmFn1nBx9X9BASzfzmsCy0uCCb8eqI3SYYzVPDswWqSx7gjw==", - "hasInstallScript": true, - "optional": true, - "peer": true, - "dependencies": { - "async-foreach": "^0.1.3", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "gaze": "^1.0.0", - "get-stdin": "^4.0.1", - "glob": "^7.0.3", - "lodash": "^4.17.15", - "meow": "^9.0.0", - "nan": "^2.13.2", - "node-gyp": "^8.4.1", - "npmlog": "^5.0.0", - "request": "^2.88.0", - "sass-graph": "^4.0.1", - "stdout-stream": "^1.4.0", - "true-case-path": "^1.0.2" - }, - "bin": { - "node-sass": "bin/node-sass" - }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "optional": true, - "peer": true, - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "license": "MIT", + "engines": { + "node": ">= 6" } }, - "node_modules/react-scripts/node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0" + "find-up": "^4.0.0" }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "engines": { + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "find-up": "^3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "locate-path": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6" } }, - "node_modules/react-scripts/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/react-scripts/node_modules/picocolors": { + "node_modules/possible-typed-array-names": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/react-scripts/node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "funding": [ { "type": "opencollective", @@ -22903,21 +13750,27 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, - "node_modules/react-scripts/node_modules/postcss-attribute-case-insensitive": { + "node_modules/postcss-attribute-case-insensitive": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.10" }, @@ -22932,10 +13785,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-browser-comments": { + "node_modules/postcss-browser-comments": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "license": "CC0-1.0", "engines": { "node": ">=8" }, @@ -22944,10 +13798,11 @@ "postcss": ">=8" } }, - "node_modules/react-scripts/node_modules/postcss-calc": { + "node_modules/postcss-calc": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.9", "postcss-value-parser": "^4.2.0" @@ -22956,10 +13811,11 @@ "postcss": "^8.2.2" } }, - "node_modules/react-scripts/node_modules/postcss-clamp": { + "node_modules/postcss-clamp": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -22970,10 +13826,11 @@ "postcss": "^8.4.6" } }, - "node_modules/react-scripts/node_modules/postcss-color-functional-notation": { + "node_modules/postcss-color-functional-notation": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "license": "CC0-1.0", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -22988,10 +13845,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-color-hex-alpha": { + "node_modules/postcss-color-hex-alpha": { "version": "8.0.4", "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23006,10 +13864,11 @@ "postcss": "^8.4" } }, - "node_modules/react-scripts/node_modules/postcss-color-rebeccapurple": { + "node_modules/postcss-color-rebeccapurple": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "license": "CC0-1.0", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23024,10 +13883,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-colormin": { + "node_modules/postcss-colormin": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -23041,10 +13901,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-convert-values": { + "node_modules/postcss-convert-values": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -23056,10 +13917,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-custom-media": { + "node_modules/postcss-custom-media": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23074,10 +13936,11 @@ "postcss": "^8.3" } }, - "node_modules/react-scripts/node_modules/postcss-custom-properties": { + "node_modules/postcss-custom-properties": { "version": "12.1.11", "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23092,10 +13955,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-custom-selectors": { + "node_modules/postcss-custom-selectors": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -23110,10 +13974,11 @@ "postcss": "^8.3" } }, - "node_modules/react-scripts/node_modules/postcss-dir-pseudo-class": { + "node_modules/postcss-dir-pseudo-class": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "license": "CC0-1.0", "dependencies": { "postcss-selector-parser": "^6.0.10" }, @@ -23128,10 +13993,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-discard-comments": { + "node_modules/postcss-discard-comments": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -23139,10 +14005,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-discard-duplicates": { + "node_modules/postcss-discard-duplicates": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -23150,10 +14017,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-discard-empty": { + "node_modules/postcss-discard-empty": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -23161,10 +14029,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-discard-overridden": { + "node_modules/postcss-discard-overridden": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -23172,10 +14041,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-double-position-gradients": { + "node_modules/postcss-double-position-gradients": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "license": "CC0-1.0", "dependencies": { "@csstools/postcss-progressive-custom-properties": "^1.1.0", "postcss-value-parser": "^4.2.0" @@ -23191,10 +14061,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-env-function": { + "node_modules/postcss-env-function": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "license": "CC0-1.0", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23205,18 +14076,20 @@ "postcss": "^8.4" } }, - "node_modules/react-scripts/node_modules/postcss-flexbugs-fixes": { + "node_modules/postcss-flexbugs-fixes": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "license": "MIT", "peerDependencies": { "postcss": "^8.1.4" } }, - "node_modules/react-scripts/node_modules/postcss-focus-visible": { + "node_modules/postcss-focus-visible": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "license": "CC0-1.0", "dependencies": { "postcss-selector-parser": "^6.0.9" }, @@ -23227,10 +14100,11 @@ "postcss": "^8.4" } }, - "node_modules/react-scripts/node_modules/postcss-focus-within": { + "node_modules/postcss-focus-within": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "license": "CC0-1.0", "dependencies": { "postcss-selector-parser": "^6.0.9" }, @@ -23241,18 +14115,20 @@ "postcss": "^8.4" } }, - "node_modules/react-scripts/node_modules/postcss-font-variant": { + "node_modules/postcss-font-variant": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "license": "MIT", "peerDependencies": { "postcss": "^8.1.0" } }, - "node_modules/react-scripts/node_modules/postcss-gap-properties": { + "node_modules/postcss-gap-properties": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "license": "CC0-1.0", "engines": { "node": "^12 || ^14 || >=16" }, @@ -23264,10 +14140,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-image-set-function": { + "node_modules/postcss-image-set-function": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "license": "CC0-1.0", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23282,18 +14159,56 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-initial": { + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "license": "MIT", "peerDependencies": { "postcss": "^8.0.0" } }, - "node_modules/react-scripts/node_modules/postcss-lab-function": { + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-lab-function": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "license": "CC0-1.0", "dependencies": { "@csstools/postcss-progressive-custom-properties": "^1.1.0", "postcss-value-parser": "^4.2.0" @@ -23309,31 +14224,149 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "postcss": "^7.0.0 || ^8.0.1", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/react-scripts/node_modules/postcss-logical": { + "node_modules/postcss-logical": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "license": "CC0-1.0", "engines": { "node": "^12 || ^14 || >=16" }, @@ -23341,10 +14374,11 @@ "postcss": "^8.4" } }, - "node_modules/react-scripts/node_modules/postcss-media-minmax": { + "node_modules/postcss-media-minmax": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -23352,10 +14386,11 @@ "postcss": "^8.1.0" } }, - "node_modules/react-scripts/node_modules/postcss-merge-longhand": { + "node_modules/postcss-merge-longhand": { "version": "5.1.7", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^5.1.1" @@ -23367,10 +14402,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-merge-rules": { + "node_modules/postcss-merge-rules": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -23384,10 +14420,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-minify-font-values": { + "node_modules/postcss-minify-font-values": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23398,10 +14435,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-minify-gradients": { + "node_modules/postcss-minify-gradients": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "license": "MIT", "dependencies": { "colord": "^2.9.1", "cssnano-utils": "^3.1.0", @@ -23414,10 +14452,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-minify-params": { + "node_modules/postcss-minify-params": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "cssnano-utils": "^3.1.0", @@ -23430,10 +14469,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-minify-selectors": { + "node_modules/postcss-minify-selectors": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.5" }, @@ -23444,10 +14484,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -23455,10 +14496,11 @@ "postcss": "^8.1.0" } }, - "node_modules/react-scripts/node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -23471,10 +14513,11 @@ "postcss": "^8.1.0" } }, - "node_modules/react-scripts/node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "license": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -23485,24 +14528,51 @@ "postcss": "^8.1.0" } }, - "node_modules/react-scripts/node_modules/postcss-modules-values": { + "node_modules/postcss-modules-values": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0" + "postcss-selector-parser": "^6.1.1" }, "engines": { - "node": "^10 || ^12 || >= 14" + "node": ">=12.0" }, "peerDependencies": { - "postcss": "^8.1.0" + "postcss": "^8.2.14" } }, - "node_modules/react-scripts/node_modules/postcss-nesting": { + "node_modules/postcss-nesting": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "license": "CC0-1.0", "dependencies": { "@csstools/selector-specificity": "^2.0.0", "postcss-selector-parser": "^6.0.10" @@ -23518,10 +14588,11 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-normalize": { + "node_modules/postcss-normalize": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "license": "CC0-1.0", "dependencies": { "@csstools/normalize.css": "*", "postcss-browser-comments": "^4", @@ -23535,10 +14606,11 @@ "postcss": ">= 8" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-charset": { + "node_modules/postcss-normalize-charset": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "license": "MIT", "engines": { "node": "^10 || ^12 || >=14.0" }, @@ -23546,10 +14618,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-display-values": { + "node_modules/postcss-normalize-display-values": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23560,10 +14633,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-positions": { + "node_modules/postcss-normalize-positions": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23574,10 +14648,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-repeat-style": { + "node_modules/postcss-normalize-repeat-style": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23588,10 +14663,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-string": { + "node_modules/postcss-normalize-string": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23602,10 +14678,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-timing-functions": { + "node_modules/postcss-normalize-timing-functions": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23616,10 +14693,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-unicode": { + "node_modules/postcss-normalize-unicode": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -23631,10 +14709,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-url": { + "node_modules/postcss-normalize-url": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "license": "MIT", "dependencies": { "normalize-url": "^6.0.1", "postcss-value-parser": "^4.2.0" @@ -23646,10 +14725,11 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-normalize-whitespace": { + "node_modules/postcss-normalize-whitespace": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -23660,7 +14740,7 @@ "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-opacity-percentage": { + "node_modules/postcss-opacity-percentage": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", @@ -23674,6 +14754,7 @@ "url": "https://liberapay.com/mrcgrtz" } ], + "license": "MIT", "engines": { "node": "^12 || ^14 || >=16" }, @@ -23681,646 +14762,1105 @@ "postcss": "^8.2" } }, - "node_modules/react-scripts/node_modules/postcss-ordered-values": { + "node_modules/postcss-ordered-values": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "license": "MIT", "dependencies": { "cssnano-utils": "^3.1.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "license": "CC0-1.0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "license": "CC0-1.0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "license": "CC0-1.0", + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "license": "CC0-1.0", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/postcss-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/postcss-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "license": "CC0-1.0" + }, + "node_modules/postcss-svgo/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/react-scripts/node_modules/postcss-overflow-shorthand": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", - "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "postcss-selector-parser": "^6.0.5" }, "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": "^10 || ^12 || >=14.0" }, "peerDependencies": { - "postcss": "^8.2" + "postcss": "^8.2.15" } }, - "node_modules/react-scripts/node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "peerDependencies": { - "postcss": "^8" + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "license": "MIT", + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/react-scripts/node_modules/postcss-place": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", - "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", - "dependencies": { - "postcss-value-parser": "^4.2.0" + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=14" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/react-scripts/node_modules/postcss-preset-env": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", - "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", - "dependencies": { - "@csstools/postcss-cascade-layers": "^1.1.1", - "@csstools/postcss-color-function": "^1.1.1", - "@csstools/postcss-font-format-keywords": "^1.0.1", - "@csstools/postcss-hwb-function": "^1.0.2", - "@csstools/postcss-ic-unit": "^1.0.1", - "@csstools/postcss-is-pseudo-class": "^2.0.7", - "@csstools/postcss-nested-calc": "^1.0.0", - "@csstools/postcss-normalize-display-values": "^1.0.1", - "@csstools/postcss-oklab-function": "^1.1.1", - "@csstools/postcss-progressive-custom-properties": "^1.3.0", - "@csstools/postcss-stepped-value-functions": "^1.0.1", - "@csstools/postcss-text-decoration-shorthand": "^1.0.0", - "@csstools/postcss-trigonometric-functions": "^1.0.2", - "@csstools/postcss-unset-value": "^1.0.2", - "autoprefixer": "^10.4.13", - "browserslist": "^4.21.4", - "css-blank-pseudo": "^3.0.3", - "css-has-pseudo": "^3.0.4", - "css-prefers-color-scheme": "^6.0.3", - "cssdb": "^7.1.0", - "postcss-attribute-case-insensitive": "^5.0.2", - "postcss-clamp": "^4.1.0", - "postcss-color-functional-notation": "^4.2.4", - "postcss-color-hex-alpha": "^8.0.4", - "postcss-color-rebeccapurple": "^7.1.1", - "postcss-custom-media": "^8.0.2", - "postcss-custom-properties": "^12.1.10", - "postcss-custom-selectors": "^6.0.3", - "postcss-dir-pseudo-class": "^6.0.5", - "postcss-double-position-gradients": "^3.1.2", - "postcss-env-function": "^4.0.6", - "postcss-focus-visible": "^6.0.4", - "postcss-focus-within": "^5.0.4", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.5", - "postcss-image-set-function": "^4.0.7", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.2.1", - "postcss-logical": "^5.0.4", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.2.0", - "postcss-opacity-percentage": "^1.1.2", - "postcss-overflow-shorthand": "^3.0.4", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.5", - "postcss-pseudo-class-any-link": "^7.1.6", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^6.0.1", - "postcss-value-parser": "^4.2.0" - }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/postcss-pseudo-class-any-link": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", - "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.10" + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/react-scripts/node_modules/postcss-reduce-initial": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", - "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "license": "MIT", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "react": ">=0.14.0" } }, - "node_modules/react-scripts/node_modules/postcss-reduce-transforms": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", - "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "node": ">= 0.10" } }, - "node_modules/react-scripts/node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "peerDependencies": { - "postcss": "^8.0.3" + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" } }, - "node_modules/react-scripts/node_modules/postcss-selector-not": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", - "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "node_modules/psl": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.10.0.tgz", + "integrity": "sha512-KSKHEbjAnpUuAUserOq0FxGXCUrzC3WniuSJhvdbs102rL55266ZcHBqLWOsG30spQMlPdpy7icATiAQehg/iA==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", "dependencies": { - "postcss-selector-parser": "^6.0.10" + "side-channel": "^1.0.6" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=0.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/react-scripts/node_modules/postcss-svgo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", - "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "performance-now": "^2.1.0" } }, - "node_modules/react-scripts/node_modules/postcss-unique-selectors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", - "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "node_modules/ramda": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz", + "integrity": "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "safe-buffer": "^5.1.0" } }, - "node_modules/react-scripts/node_modules/prelude-ls": { + "node_modules/range-parser": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">= 0.6" } }, - "node_modules/react-scripts/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "optional": true, - "peer": true, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 0.8" } }, - "node_modules/react-scripts/node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "engines": { - "node": ">=8" + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "loose-envify": "^1.1.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/sass-loader": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", - "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "node_modules/react-app-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", + "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "license": "MIT", "dependencies": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" + "core-js": "^3.19.2", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.9", + "whatwg-fetch": "^3.6.2" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=14" + } + }, + "node_modules/react-app-polyfill/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/react-bootstrap": { + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz", + "integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.9", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" }, "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" }, "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { + "@types/react": { "optional": true } } }, - "node_modules/react-scripts/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=14" } }, - "node_modules/react-scripts/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dependencies": { - "randombytes": "^2.1.0" + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" } }, - "node_modules/react-scripts/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/react-scripts/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/source-map-loader": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", - "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", "dependencies": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "optional": true, - "peer": true, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-scripts/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "react": "^18.3.1" } }, - "node_modules/react-scripts/node_modules/style-loader": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", - "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", + "license": "MIT" + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "license": "MIT", "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "node": ">=0.10.0" } }, - "node_modules/react-scripts/node_modules/stylehacks": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", - "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "node_modules/react-router": { + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.0.tgz", + "integrity": "sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==", + "license": "MIT", "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" + "@remix-run/router": "1.21.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=14.0.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "react": ">=16.8" } }, - "node_modules/react-scripts/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/react-router-dom": { + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.0.tgz", + "integrity": "sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@remix-run/router": "1.21.0", + "react-router": "6.28.0" }, "engines": { - "node": ">=8" + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" } }, - "node_modules/react-scripts/node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "node_modules/react-scripts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "license": "MIT", "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", + "react-refresh": "^0.11.0", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" }, "bin": { - "svgo": "bin/svgo" + "react-scripts": "bin/react-scripts.js" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + }, + "peerDependencies": { + "react": ">= 16", + "typescript": "^3.2.1 || ^4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/react-scripts/node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "node_modules/react-scripts/node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/react-scripts/node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, "engines": { - "node": ">=6" + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" } }, - "node_modules/react-scripts/node_modules/terser": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz", - "integrity": "sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==", + "node_modules/react-scripts/node_modules/babel-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "license": "MIT", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">=10" + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/react-scripts/node_modules/terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "node_modules/react-scripts/node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.14", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 12.13.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.1.0" + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" }, "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { + "@rspack/core": { "optional": true }, - "uglify-js": { + "webpack": { "optional": true } } }, - "node_modules/react-scripts/node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/react-scripts/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/react-scripts/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" }, "engines": { - "node": ">=8.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, - "node_modules/react-scripts/node_modules/true-case-path": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", - "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", - "optional": true, - "peer": true, + "node_modules/react-scripts/node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", "dependencies": { - "glob": "^7.1.2" + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/react-scripts/node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/react-scripts/node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1" + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" } }, - "node_modules/react-scripts/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/react-scripts/node_modules/style-loader": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 12.13.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-scripts/node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, - "engines": { - "node": ">=10.13.0" + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/react-scripts/node_modules/webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "node_modules/react-scripts/node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">= 12.13.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, "node_modules/react-scripts/node_modules/webpack-dev-server": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", - "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -24328,7 +15868,7 @@ "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", @@ -24341,6 +15881,7 @@ "html-entities": "^2.3.2", "http-proxy-middleware": "^2.0.3", "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", "open": "^8.0.9", "p-retry": "^4.5.0", "rimraf": "^3.0.2", @@ -24349,8 +15890,8 @@ "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" @@ -24366,108 +15907,19 @@ "webpack": "^4.37.0 || ^5.0.0" }, "peerDependenciesMeta": { + "webpack": { + "optional": true + }, "webpack-cli": { "optional": true } } }, - "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/react-scripts/node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/react-scripts/node_modules/webpack-manifest-plugin": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", - "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", - "dependencies": { - "tapable": "^2.0.0", - "webpack-sources": "^2.2.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "peerDependencies": { - "webpack": "^4.44.2 || ^5.47.0" - } - }, - "node_modules/react-scripts/node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", - "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", - "dependencies": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/react-scripts/node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/react-scripts/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/react-scripts/node_modules/ws": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", - "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -24484,54 +15936,28 @@ } } }, - "node_modules/react-scripts/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/react-smooth": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.2.tgz", - "integrity": "sha512-pgqSp1q8rAGtF1bXQE0m3CHGLNfZZh5oA5o1tsPLXRHnKtkujMIJ8Ws5nO1mTySZf1c4vgwlEk+pHi3Ln6eYLw==", - "dependencies": { - "fast-equals": "^4.0.3", - "react-transition-group": "2.9.0" - }, - "peerDependencies": { - "prop-types": "^15.6.0", - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-smooth/node_modules/dom-helpers": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", - "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", - "dependencies": { - "@babel/runtime": "^7.1.2" - } - }, - "node_modules/react-smooth/node_modules/react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "license": "MIT", "dependencies": { - "dom-helpers": "^3.4.0", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-lifecycles-compat": "^3.0.4" + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" }, "peerDependencies": { - "react": ">=15.0.0", - "react-dom": ">=15.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-tooltip": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.20.0.tgz", - "integrity": "sha512-LWBIHEZjwDW9ZJ/Dn2xeZrsz+WKMii61CIsx2XPfs1IiIRnWyvKJXrgy6uEGOXYvrnCd4jiEvurn8Y+zJ1bw5Q==", + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.0.tgz", + "integrity": "sha512-R5cO3JPPXk6FRbBHMO0rI9nkUG/JKfalBSQfZedZYzmqaZQgq7GLzF8vcCWx6IhUCKg0yPqJhXIzmIO5ff15xg==", + "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.0.0", + "@floating-ui/dom": "^1.6.1", "classnames": "^2.3.0" }, "peerDependencies": { @@ -24543,6 +15969,7 @@ "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -24558,162 +15985,94 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", "dependencies": { "pify": "^2.3.0" } }, - "node_modules/read-cache/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "pify": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "node": ">=4" } }, - "node_modules/read-pkg/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "engines": { - "node": ">=8" - } - }, - "node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "node": ">= 6" } }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/recast": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", - "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", - "dev": true, - "dependencies": { - "ast-types": "0.12.4", - "esprima": "~4.0.0", - "private": "^0.1.8", - "source-map": "~0.6.1" + "picomatch": "^2.2.1" }, "engines": { - "node": ">= 4" + "node": ">=8.10.0" } }, "node_modules/recharts": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.4.3.tgz", - "integrity": "sha512-/hkRHTQShEOKDYd2OlKLIvGA0X9v/XVO/mNeRoDHg0lgFRL2KbGzeqVnStI3mMfORUZ6Hak4JbQ+uDiin1Foqg==", + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.13.3.tgz", + "integrity": "sha512-YDZ9dOfK9t3ycwxgKbrnDlRC4BHdjlY73fet3a0C1+qGMjXVZe6+VXmpOIIhzkje5MMEL8AN4hLIe4AMskBzlA==", + "license": "MIT", "dependencies": { - "classnames": "^2.2.5", + "clsx": "^2.0.0", "eventemitter3": "^4.0.1", - "lodash": "^4.17.19", - "react-is": "^16.10.2", - "react-resize-detector": "^7.1.2", - "react-smooth": "^2.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.0", "recharts-scale": "^0.4.4", - "reduce-css-calc": "^2.1.8", + "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" }, "engines": { - "node": ">=12" + "node": ">=14" }, "peerDependencies": { - "prop-types": "^15.6.0", "react": "^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } @@ -24722,26 +16081,35 @@ "version": "0.4.5", "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", "dependencies": { "decimal.js-light": "^2.4.1" } }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, + "license": "MIT", "dependencies": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/recursive-readdir": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "license": "MIT", "dependencies": { "minimatch": "^3.0.5" }, @@ -24749,41 +16117,38 @@ "node": ">=6.0.0" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "license": "MIT", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" }, "engines": { - "node": ">=8" - } - }, - "node_modules/reduce-css-calc": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", - "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", - "dependencies": { - "css-unit-converter": "^1.1.1", - "postcss-value-parser": "^3.3.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/reduce-css-calc/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -24792,43 +16157,36 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" }, "node_modules/regenerator-transform": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regex-parser": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", + "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", + "license": "MIT" }, "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -24838,22 +16196,28 @@ } }, "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=6.5.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, "node_modules/regexpu-core": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.1.tgz", - "integrity": "sha512-nCOzW2V/X15XpLsK2rlgdwrysrBq+AauCn+omItIz4R1pIcmeot5zvjdmOBRLzEH/CkC6IxMJVmxDe3QcMuNVQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", + "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -24861,43 +16225,38 @@ "node": ">=4" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.2.tgz", + "integrity": "sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==", + "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "license": "MIT", "engines": { "node": ">= 0.10" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "optional": true - }, "node_modules/renderkid": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "license": "MIT", "dependencies": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", @@ -24906,202 +16265,11 @@ "strip-ansi": "^6.0.1" } }, - "node_modules/renderkid/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/renderkid/node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/renderkid/node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/renderkid/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/renderkid/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/renderkid/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "optional": true, - "peer": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "optional": true, - "peer": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "optional": true, - "peer": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "optional": true, - "peer": true, - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -25110,168 +16278,71 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==", - "dev": true, - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-dir/node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-dir/node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", - "dev": true, + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-path": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz", - "integrity": "sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==", - "devOptional": true, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "license": "MIT", "dependencies": { - "http-errors": "~1.6.2", - "path-is-absolute": "1.0.1" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/resolve-path/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "devOptional": true, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/resolve-path/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "devOptional": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/resolve-path/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "devOptional": true - }, - "node_modules/resolve-path/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "devOptional": true - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated" - }, "node_modules/resolve-url-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "license": "MIT", "dependencies": { "adjust-sourcemap-loader": "^4.0.0", "convert-source-map": "^1.7.0", @@ -25295,38 +16366,58 @@ } } }, - "node_modules/resolve.exports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", - "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", - "engines": { - "node": ">=10" - } + "node_modules/resolve-url-loader/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/resolve-url-loader/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "license": "ISC" + }, + "node_modules/resolve-url-loader/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=8" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "license": "MIT", "engines": { - "node": ">=0.12" + "node": ">=10" } }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -25335,35 +16426,33 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rollup": { "version": "2.79.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -25379,6 +16468,7 @@ "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", "jest-worker": "^26.2.1", @@ -25389,29 +16479,11 @@ "rollup": "^2.0.0" } }, - "node_modules/rollup-plugin-terser/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/rollup-plugin-terser/node_modules/jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -25421,40 +16493,26 @@ "node": ">= 10.13.0" } }, - "node_modules/rollup-plugin-terser/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-terser/node_modules/terser": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz", - "integrity": "sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==", + "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "license": "BSD-3-Clause", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" + "randombytes": "^2.1.0" } }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/run-parallel": { @@ -25475,27 +16533,27 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, - "node_modules/run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", - "dependencies": { - "aproba": "^1.1.1" - } - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "license": "MIT", "dependencies": { - "tslib": "^1.9.0" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" }, "engines": { - "npm": ">=2.0.0" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/safe-buffer": { @@ -25515,25 +16573,22 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", - "dependencies": { - "ret": "~0.1.10" - } + ], + "license": "MIT" }, "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", "is-regex": "^1.1.4" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -25541,96 +16596,115 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/sanitize.css": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", - "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==", + "license": "CC0-1.0" }, - "node_modules/sass-graph": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.1.tgz", - "integrity": "sha512-5YCfmGBmxoIRYHnKK2AKzrAkCoQ8ozO+iumT8K4tXJXRVCPf+7s1/9KxTSW3Rbvf+7Y7b4FR3mWyLnQr3PHocA==", + "node_modules/sass": { + "version": "1.80.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.6.tgz", + "integrity": "sha512-ccZgdHNiBF1NHBsWvacvT5rju3y1d/Eu+8Ex6c21nHp2lZGLBEtuwc415QfiI1PJa1TpCo3iXwwSRjRpn2Ckjg==", + "devOptional": true, + "license": "MIT", "dependencies": { - "glob": "^7.0.0", - "lodash": "^4.17.11", - "scss-tokenizer": "^0.4.3", - "yargs": "^17.2.1" + "chokidar": "^4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { - "sassgraph": "bin/sassgraph" + "sass": "sass.js" }, "engines": { - "node": ">=12" - } - }, - "node_modules/sass-graph/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/sass-graph/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "node": ">=14.0.0" }, - "engines": { - "node": ">=12" + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "node_modules/sass-graph/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "klona": "^2.0.4", + "neo-async": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } } }, - "node_modules/sass-graph/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "devOptional": true, + "license": "MIT", "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "readdirp": "^4.0.1" }, "engines": { - "node": ">=12" + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/sass-graph/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "node_modules/sass/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "license": "ISC" }, "node_modules/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" }, @@ -25639,57 +16713,80 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 8.9.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/scss-tokenizer": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.4.3.tgz", - "integrity": "sha512-raKLgf1LI5QMQnG+RxHz6oK0sL3x3I4FN2UDLqgLOGO8hodECNnNh5BXn7fAyBxrA8zVzdQizQ6XjNJQ+uBwMw==", + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", "dependencies": { - "js-base64": "^2.4.9", - "source-map": "^0.7.3" + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/scss-tokenizer/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" - } + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "license": "MIT" }, "node_modules/selfsigned": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", - "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "license": "MIT", "dependencies": { + "@types/node-forge": "^1.3.0", "node-forge": "^1" }, "engines": { @@ -25697,17 +16794,22 @@ } }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/send": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -25731,6 +16833,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -25738,40 +16841,23 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -25780,6 +16866,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -25797,6 +16884,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -25805,6 +16893,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -25813,6 +16902,7 @@ "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -25826,22 +16916,35 @@ "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -25852,23 +16955,11 @@ "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -25881,475 +16972,245 @@ "node": ">= 0.4" } }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", - "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, - "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", "dependencies": { - "semver": "~7.0.0" + "kind-of": "^6.0.2" }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/snapdragon/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/snapdragon/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, - "node_modules/snapdragon/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" } }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "license": "MIT" }, "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "node_modules/source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "license": "MIT", "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" } }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated" + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "license": "MIT" }, "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==" + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -26365,6 +17226,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -26374,367 +17236,169 @@ "wbuf": "^1.7.3" } }, - "node_modules/spdy-transport/node_modules/readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/spdy-transport/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "optional": true, - "peer": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssri": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.1.tgz", - "integrity": "sha512-w+daCzXN89PseTL99MkA+fxJEcU3wfaE/ah0i0lnOlpG1CYLJ2ZjzEry68YBKfLs4JfoTShrTEsJkAZuNZ/stw==", - "dev": true, - "dependencies": { - "figgy-pudding": "^3.5.1", - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" }, "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/stackframe": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stdout-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", - "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", - "dependencies": { - "readable-stream": "^2.0.1" - } - }, - "node_modules/stdout-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/stdout-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stdout-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "license": "MIT" }, - "node_modules/stdout-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dependencies": { - "internal-slot": "^1.0.4" - }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "node_modules/stream-browserify": { + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, + "node_modules/static-eval": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", + "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "license": "MIT", "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" + "escodegen": "^1.8.1" } }, - "node_modules/stream-browserify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/static-eval/node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "license": "BSD-2-Clause", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/stream-browserify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/stream-browserify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" + "node_modules/static-eval/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "node_modules/stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "node_modules/static-eval/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "license": "MIT", "dependencies": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "node_modules/static-eval/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "license": "MIT", "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/stream-http/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "node_modules/static-eval/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/stream-http/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "node_modules/static-eval/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/stream-http/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/static-eval/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -26743,34 +17407,17 @@ "node": ">=10" } }, - "node_modules/string-length/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string-natural-compare": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "license": "MIT" }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -26780,52 +17427,112 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { "node": ">=8" } }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, "node_modules/string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.padend": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz", - "integrity": "sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -26835,26 +17542,31 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -26864,6 +17576,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "license": "BSD-2-Clause", "dependencies": { "get-own-enumerable-property-symbols": "^3.0.0", "is-obj": "^1.0.1", @@ -26874,64 +17587,62 @@ } }, "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/strip-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "engines": { - "node": ">=10" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true, + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -26940,96 +17651,130 @@ } }, "node_modules/style-loader": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.27.0" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "license": "MIT", "dependencies": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" }, "engines": { - "node": ">= 0.12.0" + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" } }, - "node_modules/style-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" }, "bin": { - "json5": "lib/cli.js" + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" } }, - "node_modules/style-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", "engines": { - "node": ">=4.0.0" + "node": ">= 6" } }, - "node_modules/style-loader/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">= 4" + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/styled-jsx": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.2.tgz", - "integrity": "sha512-FI5r0a5ED2/+DSdG2ZRz3a4FtNQnKPLadauU5v76a9QsscwZrWggQKOmyxGGP5EWKbyY3bsuWAJYzyKaDAVAcw==", - "dev": true, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", "dependencies": { - "client-only": "0.0.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 12.0.0" + "node": ">=16 || 14 >=14.17" }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/supports-hyperlinks": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -27038,29 +17783,11 @@ "node": ">=8" } }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -27071,13 +17798,15 @@ "node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "license": "MIT" }, "node_modules/svgo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "license": "MIT", "dependencies": { "chalk": "^2.4.1", "coa": "^2.0.2", @@ -27100,339 +17829,193 @@ "node": ">=4.0.0" } }, - "node_modules/svgo/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" - }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/table/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/table/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tailwindcss": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz", - "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==", - "dependencies": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "detective": "^5.2.1", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "lilconfig": "^2.0.6", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.0.9", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/tailwindcss/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tailwindcss/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/tailwindcss/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tailwindcss/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/tailwindcss/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/tailwindcss/node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/tailwindcss/node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/tailwindcss/node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/tailwindcss/node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/tailwindcss/node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "node_modules/svgo/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "color-convert": "^1.9.0" }, - "peerDependencies": { - "postcss": "^8.4.21" + "engines": { + "node": ">=4" } }, - "node_modules/tailwindcss/node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "node_modules/svgo/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } + "node": ">=4" } }, - "node_modules/tailwindcss/node_modules/postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", + "node_modules/svgo/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, + "color-name": "1.1.3" + } + }, + "node_modules/svgo/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/svgo/node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/svgo/node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "license": "BSD-2-Clause", "engines": { - "node": ">=12.0" + "node": ">= 6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/tailwindcss/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/svgo/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" - }, + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/svgo/node_modules/domutils/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "license": "BSD-2-Clause" + }, + "node_modules/svgo/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", "engines": { - "node": ">=8.0" + "node": ">=0.8.0" } }, - "node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "node_modules/svgo/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "node_modules/svgo/node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/svgo/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/tar/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, "engines": { - "node": ">=10" + "node": ">=14.0.0" } }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/temp-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "license": "MIT", "engines": { "node": ">=8" } @@ -27441,6 +18024,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "license": "MIT", "dependencies": { "is-stream": "^2.0.0", "temp-dir": "^2.0.0", @@ -27454,21 +18038,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tempy/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tempy/node_modules/type-fest": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -27480,6 +18054,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" @@ -27492,257 +18067,195 @@ } }, "node_modules/terser": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", - "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "license": "BSD-2-Clause", "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" + "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" } }, "node_modules/terser-webpack-plugin": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", - "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", - "dev": true, + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "license": "MIT", "dependencies": { - "cacache": "^13.0.1", - "find-cache-dir": "^3.3.1", - "jest-worker": "^25.4.0", - "p-limit": "^2.3.0", - "schema-utils": "^2.6.6", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.6.12", - "webpack-sources": "^1.4.3" + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" }, "engines": { - "node": ">= 8.9.0" + "node": ">= 10.13.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "webpack": "^5.1.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "node_modules/throat": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", - "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } } }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", "dependencies": { - "setimmediate": "^1.0.4" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">=0.6.0" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", "dependencies": { - "os-tmpdir": "~1.0.2" + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" }, "engines": { - "node": ">=0.6.0" + "node": ">=8" } }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" - }, - "node_modules/to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "license": "MIT" }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "any-promise": "^1.0.0" } }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "thenify": ">= 3.1.0 < 4" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.8" } }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "devOptional": true, + "license": "Unlicense", "engines": { - "node": ">=0.10.0" + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" } }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", + "license": "MIT" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0" } }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } }, - "node_modules/topo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", - "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", - "deprecated": "This module has moved and is now available at @hapi/topo. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", - "devOptional": true, - "dependencies": { - "hoek": "6.x.x" - } - }, "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dependencies": { - "nopt": "~1.0.10" - }, + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", "bin": { "nodetouch": "bin/nodetouch.js" } }, - "node_modules/touch/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -27757,6 +18270,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", "engines": { "node": ">= 4.0.0" } @@ -27765,6 +18279,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "license": "MIT", "dependencies": { "punycode": "^2.1.1" }, @@ -27772,28 +18287,40 @@ "node": ">=8" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "devOptional": true, + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/true-case-path": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-2.2.1.tgz", - "integrity": "sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==" - }, "node_modules/tryer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "license": "MIT" + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -27805,6 +18332,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -27812,24 +18340,26 @@ "json5": "lib/cli.js" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", - "devOptional": true, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", "engines": { - "node": ">=0.6.x" + "node": ">=4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -27840,37 +18370,19 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "optional": true, - "peer": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "optional": true, - "peer": true + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" }, "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "license": "MIT", "dependencies": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" }, "engines": { "node": ">= 0.8.0" @@ -27880,6 +18392,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", "engines": { "node": ">=4" } @@ -27888,6 +18401,7 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -27899,6 +18413,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -27907,28 +18422,84 @@ "node": ">= 0.6" } }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" } @@ -27937,6 +18508,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "license": "Apache-2.0", "peer": true, "bin": { "tsc": "bin/tsc", @@ -27950,6 +18522,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -27964,6 +18537,7 @@ "version": "7.2.1", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.6.3", "@types/react": ">=16.9.11", @@ -27977,12 +18551,27 @@ "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", "engines": { "node": ">=4" } @@ -27991,6 +18580,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -28000,9 +18590,10 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "license": "MIT", "engines": { "node": ">=4" } @@ -28011,52 +18602,16 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/union-value/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, "node_modules/unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "license": "MIT", "dependencies": { "crypto-random-string": "^2.0.0" }, @@ -28065,9 +18620,10 @@ } }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -28076,6 +18632,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -28083,79 +18640,23 @@ "node_modules/unquote": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==", + "license": "MIT" }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "license": "MIT", "engines": { "node": ">=4", "yarn": "*" } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -28164,86 +18665,54 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" } }, - "node_modules/update-browserslist-db/node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", - "deprecated": "Please see https://github.com/lydell/urix#deprecated" - }, - "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dependencies": { - "inherits": "2.0.3" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/util.promisify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "license": "MIT", "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.2", @@ -28254,20 +18723,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - }, "node_modules/utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -28276,19 +18742,16 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" - }, "node_modules/v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "license": "ISC", "dependencies": { "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", @@ -28298,18 +18761,18 @@ "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" - } + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -28319,36 +18782,16 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "engines": [ - "node >=0.6.0" - ], - "optional": true, - "peer": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "optional": true, - "peer": true - }, "node_modules/victory-vendor": { - "version": "36.6.8", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.8.tgz", - "integrity": "sha512-H3kyQ+2zgjMPvbPqAl7Vwm2FD5dU7/4bCTQakFQnpIsfDljeOMDojRsrmJfwh4oAlNnWhpAf+mbAoLh8u7dwyQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", @@ -28366,16 +18809,12 @@ "d3-timer": "^3.0.1" } }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "license": "MIT", "dependencies": { "browser-process-hrtime": "^1.0.0" } @@ -28384,6 +18823,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "license": "MIT", "dependencies": { "xml-name-validator": "^3.0.0" }, @@ -28395,6 +18835,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } @@ -28403,850 +18844,435 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" } }, "node_modules/watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", - "dependencies": { - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - }, - "optionalDependencies": { - "chokidar": "^3.4.1", - "watchpack-chokidar2": "^2.0.1" - } - }, - "node_modules/watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", - "optional": true, - "dependencies": { - "chokidar": "^2.1.8" - } - }, - "node_modules/watchpack-chokidar2/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "optional": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/watchpack-chokidar2/node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "optional": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", - "optional": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/watchpack-chokidar2/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", - "optional": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "optional": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", - "optional": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "optional": true - }, - "node_modules/watchpack-chokidar2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "optional": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/watchpack-chokidar2/node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "optional": true, + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" }, "engines": { - "node": ">=0.10" - } - }, - "node_modules/watchpack-chokidar2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true - }, - "node_modules/watchpack-chokidar2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, - "dependencies": { - "safe-buffer": "~5.1.0" + "node": ">=10.13.0" } }, "node_modules/wbuf": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } }, "node_modules/web-vitals": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", - "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "license": "Apache-2.0" }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "license": "BSD-2-Clause", "engines": { "node": ">=10.4" } }, "node_modules/webpack": { - "version": "4.37.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.37.0.tgz", - "integrity": "sha512-iJPPvL7XpbcbwOthbzpa2BSPlmGp8lGDokAj/LdWtK80rsPoPOdANSbDBf2GAVLKZD3GhCuQ/gGkgN9HWs0Keg==", - "dependencies": { - "@webassemblyjs/ast": "1.8.5", - "@webassemblyjs/helper-module-context": "1.8.5", - "@webassemblyjs/wasm-edit": "1.8.5", - "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.2.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^1.0.0", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" }, "bin": { "webpack": "bin/webpack.js" }, "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/webpack-cli": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.6.tgz", - "integrity": "sha512-0vEa83M7kJtxK/jUhlpZ27WHIOndz5mghWL2O53kiDoA9DIxSKnfqB92LoqEn77cT4f3H2cZm1BMEat/6AZz3A==", - "dev": true, - "dependencies": { - "chalk": "2.4.2", - "cross-spawn": "6.0.5", - "enhanced-resolve": "4.1.0", - "findup-sync": "3.0.0", - "global-modules": "2.0.0", - "import-local": "2.0.0", - "interpret": "1.2.0", - "loader-utils": "1.2.3", - "supports-color": "6.1.0", - "v8-compile-cache": "2.0.3", - "yargs": "13.2.4" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=6.11.5" - }, - "peerDependencies": { - "webpack": "4.x.x" - } - }, - "node_modules/webpack-cli/node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/webpack-cli/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/webpack-cli/node_modules/emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/webpack-cli/node_modules/enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/webpack-cli/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-cli/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-cli/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/webpack-cli/node_modules/loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/webpack-cli/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-cli/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-cli/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-cli/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-cli/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" + "node": ">=10.13.0" }, - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } } }, - "node_modules/webpack-cli/node_modules/v8-compile-cache": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", - "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", - "dev": true - }, - "node_modules/webpack-cli/node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=6" + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } } }, - "node_modules/webpack-cli/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/webpack-cli/node_modules/yargs": { - "version": "13.2.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", - "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.0" + "license": "MIT", + "engines": { + "node": ">=14" } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", + "devOptional": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", + "memfs": "^4.6.0", "mime-types": "^2.1.31", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "node_modules/webpack-dev-middleware/node_modules/memfs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", + "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", + "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" }, "funding": { "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/streamich" } }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "node_modules/webpack-dev-server": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.1.0.tgz", + "integrity": "sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.19.2", + "graceful-fs": "^4.2.6", + "html-entities": "^2.4.0", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-plugin-serve": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/webpack-plugin-serve/-/webpack-plugin-serve-0.8.0.tgz", - "integrity": "sha512-aQxQWqdnl+3v6Uf8krRB+cJ9faOPDWfrbHFmf5/oVFiqFeulL5q38V6SWdLlqlA7Biq6VKvXd7odAjd7XPIgDQ==", - "devOptional": true, - "dependencies": { - "chalk": "^2.4.1", - "connect-history-api-fallback": "^1.5.0", - "http-proxy-middleware": "^0.19.0", - "is-promise": "^2.1.0", - "joi": "^14.3.0", - "koa": "^2.5.3", - "koa-compress": "^3.0.0", - "koa-connect": "^2.0.1", - "koa-route": "^3.2.0", - "koa-static": "^5.0.0", - "loglevelnext": "^3.0.0", - "nanoid": "^2.0.0", - "onetime": "^3.0.0", - "opn": "^5.4.0", - "p-defer": "^1.0.0", - "strip-ansi": "^5.0.0", - "ws": "^6.0.0" - }, - "engines": { - "node": ">= 8.0.0 < 9.0.0 || >= 10.0.0 < 10.14.0 || >= 10.15.0" }, "peerDependencies": { - "webpack": "^4.20.2" - } - }, - "node_modules/webpack-plugin-serve/node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "devOptional": true, - "engines": { - "node": ">=4" + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } } }, - "node_modules/webpack-plugin-serve/node_modules/onetime": { + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-3.0.0.tgz", - "integrity": "sha512-t2j1nTo7vb2m/ZQAq5rcWjQgAglF/2rnvlO0cxkZ1GFOSEt0sQBHaytm5tC1ZNUlmKZAp5XF44kolGL9W/XJ2w==", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "devOptional": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-serve": { + "node_modules/webpack-dev-server/node_modules/is-wsl": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/webpack-serve/-/webpack-serve-3.1.0.tgz", - "integrity": "sha512-pSt5ryMSLNELP2nuzdeBWuiS/ZH9CEcgQ2QTHNUWZAJzWTlq28O5tnVR4p7VdATCO4E6PquswQDntk1glEsMYA==", - "dev": true, + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "devOptional": true, + "license": "MIT", "dependencies": { - "chalk": "^2.4.2", - "decamelize": "^3.0.0", - "import-local": "^2.0.0", - "is-plain-obj": "^1.1.0", - "object-path": "^0.11.4", - "pkg-conf": "^3.0.0", - "rechoir": "^0.7.0", - "v8-compile-cache": "^2.0.2", - "webpack-plugin-serve": "^0.8.0", - "yargs-parser": "^13.0.0" - }, - "bin": { - "webpack-serve": "bin/webpack-serve" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">= 8.0.0 < 9.0.0 || >= 10.0.0 < 10.14.0 || >= 10.15.0" - }, - "peerDependencies": { - "webpack": "^4.29.0" - } - }, - "node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/webpack/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "bin": { - "acorn": "bin/acorn" + "node": ">=16" }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/webpack/node_modules/cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", - "dependencies": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "devOptional": true, + "license": "MIT", "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" }, "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/webpack/node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" + "node": ">=18" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">=6" - } - }, - "node_modules/webpack/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/webpack/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "node": ">=10.0.0" }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/webpack/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" }, - "engines": { - "node": ">=6" + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/webpack/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "node_modules/webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "license": "MIT", "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/webpack/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/webpack/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" + "node": ">=12.22.0" }, - "engines": { - "node": ">=6" + "peerDependencies": { + "webpack": "^4.44.2 || ^5.47.0" } }, - "node_modules/webpack/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "node_modules/webpack-manifest-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/webpack/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "license": "MIT", "dependencies": { - "find-up": "^3.0.0" + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=6" + "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" }, "engines": { - "node": ">= 4" + "node": ">=10.0.0" } }, - "node_modules/webpack/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/ssri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", "dependencies": { - "figgy-pudding": "^3.5.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "node_modules/webpack/node_modules/terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", "dependencies": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">= 6.9.0" + "node": ">= 10.13.0" }, - "peerDependencies": { - "webpack": "^4.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/webpack/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -29260,6 +19286,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } @@ -29268,24 +19295,40 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "license": "MIT", "dependencies": { "iconv-lite": "0.4.24" } }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" }, "node_modules/whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "license": "MIT" }, "node_modules/whatwg-url": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "license": "MIT", "dependencies": { "lodash": "^4.7.0", "tr46": "^2.1.0", @@ -29296,20 +19339,25 @@ } }, "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { - "which": "bin/which" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -29321,37 +19369,61 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "node_modules/which-builtin-type": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "license": "MIT", "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", - "dev": true + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -29360,43 +19432,46 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" }, "node_modules/word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/workbox-background-sync": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.5.4.tgz", - "integrity": "sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.6.0.tgz", + "integrity": "sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==", + "license": "MIT", "dependencies": { "idb": "^7.0.1", - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-broadcast-update": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.5.4.tgz", - "integrity": "sha512-I/lBERoH1u3zyBosnpPEtcAVe5lwykx9Yg1k6f8/BGEPGaMMgZrwVrqL1uA9QZ1NGGFoyE6t9i7lBjOlDhFEEw==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.6.0.tgz", + "integrity": "sha512-nm+v6QmrIFaB/yokJmQ/93qIJ7n72NICxIwQwe5xsZiV2aI93MGGyEyzOzDPVz5THEr5rC3FJSsO3346cId64Q==", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-build": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.5.4.tgz", - "integrity": "sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.6.0.tgz", + "integrity": "sha512-Tjf+gBwOTuGyZwMz2Nk/B13Fuyeo0Q84W++bebbVsfr9iLkDSo6j6PST8tET9HYA58mlRXwlMGpyWO8ETJiXdQ==", + "license": "MIT", "dependencies": { "@apideck/better-ajv-errors": "^0.3.1", "@babel/core": "^7.11.1", @@ -29420,21 +19495,21 @@ "strip-comments": "^2.0.1", "tempy": "^0.6.0", "upath": "^1.2.0", - "workbox-background-sync": "6.5.4", - "workbox-broadcast-update": "6.5.4", - "workbox-cacheable-response": "6.5.4", - "workbox-core": "6.5.4", - "workbox-expiration": "6.5.4", - "workbox-google-analytics": "6.5.4", - "workbox-navigation-preload": "6.5.4", - "workbox-precaching": "6.5.4", - "workbox-range-requests": "6.5.4", - "workbox-recipes": "6.5.4", - "workbox-routing": "6.5.4", - "workbox-strategies": "6.5.4", - "workbox-streams": "6.5.4", - "workbox-sw": "6.5.4", - "workbox-window": "6.5.4" + "workbox-background-sync": "6.6.0", + "workbox-broadcast-update": "6.6.0", + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-google-analytics": "6.6.0", + "workbox-navigation-preload": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-range-requests": "6.6.0", + "workbox-recipes": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0", + "workbox-streams": "6.6.0", + "workbox-sw": "6.6.0", + "workbox-window": "6.6.0" }, "engines": { "node": ">=10.0.0" @@ -29444,6 +19519,7 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "license": "MIT", "dependencies": { "json-schema": "^0.4.0", "jsonpointer": "^5.0.0", @@ -29457,14 +19533,15 @@ } }, "node_modules/workbox-build/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -29475,6 +19552,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -29488,12 +19566,14 @@ "node_modules/workbox-build/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, "node_modules/workbox-build/node_modules/source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "license": "BSD-3-Clause", "dependencies": { "whatwg-url": "^7.0.0" }, @@ -29505,6 +19585,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "license": "MIT", "dependencies": { "punycode": "^2.1.0" } @@ -29512,12 +19593,14 @@ "node_modules/workbox-build/node_modules/webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "license": "BSD-2-Clause" }, "node_modules/workbox-build/node_modules/whatwg-url": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "license": "MIT", "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", @@ -29525,117 +19608,132 @@ } }, "node_modules/workbox-cacheable-response": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.5.4.tgz", - "integrity": "sha512-DCR9uD0Fqj8oB2TSWQEm1hbFs/85hXXoayVwFKLVuIuxwJaihBsLsp4y7J9bvZbqtPJ1KlCkmYVGQKrBU4KAug==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.6.0.tgz", + "integrity": "sha512-JfhJUSQDwsF1Xv3EV1vWzSsCOZn4mQ38bWEBR3LdvOxSPgB65gAM6cS2CX8rkkKHRgiLrN7Wxoyu+TuH67kHrw==", + "deprecated": "workbox-background-sync@6.6.0", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-core": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.4.tgz", - "integrity": "sha512-OXYb+m9wZm8GrORlV2vBbE5EC1FKu71GGp0H4rjmxmF4/HLbMCoTFws87M3dFwgpmg0v00K++PImpNQ6J5NQ6Q==" + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz", + "integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ==", + "license": "MIT" }, "node_modules/workbox-expiration": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.5.4.tgz", - "integrity": "sha512-jUP5qPOpH1nXtjGGh1fRBa1wJL2QlIb5mGpct3NzepjGG2uFFBn4iiEBiI9GUmfAFR2ApuRhDydjcRmYXddiEQ==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.6.0.tgz", + "integrity": "sha512-baplYXcDHbe8vAo7GYvyAmlS4f6998Jff513L4XvlzAOxcl8F620O91guoJ5EOf5qeXG4cGdNZHkkVAPouFCpw==", + "license": "MIT", "dependencies": { "idb": "^7.0.1", - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-google-analytics": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.5.4.tgz", - "integrity": "sha512-8AU1WuaXsD49249Wq0B2zn4a/vvFfHkpcFfqAFHNHwln3jK9QUYmzdkKXGIZl9wyKNP+RRX30vcgcyWMcZ9VAg==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.6.0.tgz", + "integrity": "sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==", + "deprecated": "It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained", + "license": "MIT", "dependencies": { - "workbox-background-sync": "6.5.4", - "workbox-core": "6.5.4", - "workbox-routing": "6.5.4", - "workbox-strategies": "6.5.4" + "workbox-background-sync": "6.6.0", + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" } }, "node_modules/workbox-navigation-preload": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.5.4.tgz", - "integrity": "sha512-IIwf80eO3cr8h6XSQJF+Hxj26rg2RPFVUmJLUlM0+A2GzB4HFbQyKkrgD5y2d84g2IbJzP4B4j5dPBRzamHrng==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.6.0.tgz", + "integrity": "sha512-utNEWG+uOfXdaZmvhshrh7KzhDu/1iMHyQOV6Aqup8Mm78D286ugu5k9MFD9SzBT5TcwgwSORVvInaXWbvKz9Q==", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-precaching": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.5.4.tgz", - "integrity": "sha512-hSMezMsW6btKnxHB4bFy2Qfwey/8SYdGWvVIKFaUm8vJ4E53JAY+U2JwLTRD8wbLWoP6OVUdFlXsTdKu9yoLTg==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.6.0.tgz", + "integrity": "sha512-eYu/7MqtRZN1IDttl/UQcSZFkHP7dnvr/X3Vn6Iw6OsPMruQHiVjjomDFCNtd8k2RdjLs0xiz9nq+t3YVBcWPw==", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4", - "workbox-routing": "6.5.4", - "workbox-strategies": "6.5.4" + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" } }, "node_modules/workbox-range-requests": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.5.4.tgz", - "integrity": "sha512-Je2qR1NXCFC8xVJ/Lux6saH6IrQGhMpDrPXWZWWS8n/RD+WZfKa6dSZwU+/QksfEadJEr/NfY+aP/CXFFK5JFg==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.6.0.tgz", + "integrity": "sha512-V3aICz5fLGq5DpSYEU8LxeXvsT//mRWzKrfBOIxzIdQnV/Wj7R+LyJVTczi4CQ4NwKhAaBVaSujI1cEjXW+hTw==", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-recipes": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.5.4.tgz", - "integrity": "sha512-QZNO8Ez708NNwzLNEXTG4QYSKQ1ochzEtRLGaq+mr2PyoEIC1xFW7MrWxrONUxBFOByksds9Z4//lKAX8tHyUA==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.6.0.tgz", + "integrity": "sha512-TFi3kTgYw73t5tg73yPVqQC8QQjxJSeqjXRO4ouE/CeypmP2O/xqmB/ZFBBQazLTPxILUQ0b8aeh0IuxVn9a6A==", + "license": "MIT", "dependencies": { - "workbox-cacheable-response": "6.5.4", - "workbox-core": "6.5.4", - "workbox-expiration": "6.5.4", - "workbox-precaching": "6.5.4", - "workbox-routing": "6.5.4", - "workbox-strategies": "6.5.4" + "workbox-cacheable-response": "6.6.0", + "workbox-core": "6.6.0", + "workbox-expiration": "6.6.0", + "workbox-precaching": "6.6.0", + "workbox-routing": "6.6.0", + "workbox-strategies": "6.6.0" } }, "node_modules/workbox-routing": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.4.tgz", - "integrity": "sha512-apQswLsbrrOsBUWtr9Lf80F+P1sHnQdYodRo32SjiByYi36IDyL2r7BH1lJtFX8fwNHDa1QOVY74WKLLS6o5Pg==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz", + "integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-strategies": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.4.tgz", - "integrity": "sha512-DEtsxhx0LIYWkJBTQolRxG4EI0setTJkqR4m7r4YpBdxtWJH1Mbg01Cj8ZjNOO8etqfA3IZaOPHUxCs8cBsKLw==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz", + "integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4" + "workbox-core": "6.6.0" } }, "node_modules/workbox-streams": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.5.4.tgz", - "integrity": "sha512-FXKVh87d2RFXkliAIheBojBELIPnWbQdyDvsH3t74Cwhg0fDheL1T8BqSM86hZvC0ZESLsznSYWw+Va+KVbUzg==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.6.0.tgz", + "integrity": "sha512-rfMJLVvwuED09CnH1RnIep7L9+mj4ufkTyDPVaXPKlhi9+0czCu+SJggWCIFbPpJaAZmp2iyVGLqS3RUmY3fxg==", + "license": "MIT", "dependencies": { - "workbox-core": "6.5.4", - "workbox-routing": "6.5.4" + "workbox-core": "6.6.0", + "workbox-routing": "6.6.0" } }, "node_modules/workbox-sw": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.5.4.tgz", - "integrity": "sha512-vo2RQo7DILVRoH5LjGqw3nphavEjK4Qk+FenXeUsknKn14eCNedHOXWbmnvP4ipKhlE35pvJ4yl4YYf6YsJArA==" + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.6.0.tgz", + "integrity": "sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==", + "license": "MIT" }, "node_modules/workbox-webpack-plugin": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.5.4.tgz", - "integrity": "sha512-LmWm/zoaahe0EGmMTrSLUi+BjyR3cdGEfU3fS6PN1zKFYbqAKuQ+Oy/27e4VSXsyIwAw8+QDfk1XHNGtZu9nQg==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.0.tgz", + "integrity": "sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==", + "license": "MIT", "dependencies": { "fast-json-stable-stringify": "^2.1.0", "pretty-bytes": "^5.4.1", "upath": "^1.2.0", "webpack-sources": "^1.4.3", - "workbox-build": "6.5.4" + "workbox-build": "6.6.0" }, "engines": { "node": ">=10.0.0" @@ -29644,27 +19742,40 @@ "webpack": "^4.4.0 || ^5.9.0" } }, - "node_modules/workbox-window": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.5.4.tgz", - "integrity": "sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==", + "node_modules/workbox-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "license": "MIT", "dependencies": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.5.4" + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" } }, - "node_modules/worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "node_modules/workbox-window": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.6.0.tgz", + "integrity": "sha512-L4N9+vka17d16geaJXXRjENLFldvkWy7JyGxElRD0JvBxvFEd8LOhr+uXCcar/NzAmIBRv9EZ+M+Qr4mOoBITw==", + "license": "MIT", "dependencies": { - "errno": "~0.1.7" + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.6.0" } }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -29677,75 +19788,35 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -29753,57 +19824,44 @@ "typedarray-to-buffer": "^3.1.5" } }, - "node_modules/write/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "devOptional": true, - "dependencies": { - "async-limiter": "~1.0.0" + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "license": "Apache-2.0" }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" - }, - "node_modules/xregexp": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", - "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", - "dev": true, - "dependencies": { - "@babel/runtime-corejs3": "^7.12.1" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", "engines": { "node": ">=10" } @@ -29811,12 +19869,14 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", "engines": { "node": ">= 6" } @@ -29825,6 +19885,7 @@ "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -29839,45 +19900,19 @@ } }, "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs-parser/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", "engines": { "node": ">=10" } }, - "node_modules/ylru": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.3.2.tgz", - "integrity": "sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==", - "devOptional": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/modules/lo_dash_react_components/package.json b/modules/lo_dash_react_components/package.json index 09a9a0c0f..33ce92deb 100644 --- a/modules/lo_dash_react_components/package.json +++ b/modules/lo_dash_react_components/package.json @@ -2,83 +2,61 @@ "name": "lo_dash_react_components", "version": "0.0.1", "description": "React and Dash components for Learning Observer dashboards", - "repository": { - "type": "git", - "url": "git://github.com/ETS-Next-Gen/lo-dash-react-components.git" - }, - "bugs": { - "url": "https://github.com/ETS-Next-Gen/lo-dash-react-components/issues" - }, - "homepage": "https://github.com/ETS-Next-Gen/lo-dash-react-components", "main": "build/index.js", "scripts": { - "webpack-start": "webpack-serve --config ./webpack.serve.config.js --open", - "describe-webpack-start": "echo Run react app (without dash) with WebPack, which is Dash's default.", + "webpack-start": "webpack serve --config ./webpack.serve.config.js --open", "react-start": "react-scripts start", - "describe-react-start": "echo Run react app (without dash) with React Scripts, which probably gives the most rapid workflow.", "dash-start": "nodemon", - "describe-dash-start": "echo Run full dash app with nodemon. This requires a rebuild each time files change.", - "validate-init": "python _validate_init.py", - "prepublishOnly": "npm run validate-init", "build:js": "webpack --mode production", "build:backends": "dash-generate-components ./src/lib/components lo_dash_react_components -p package-info.json --r-prefix '' --jl-prefix '' --ignore \\.test\\.", - "build:backends-activated": "(. venv/bin/activate || venv\\scripts\\activate && npm run build:py_and_r)", "build": "npm run build-css && npm run build:js && npm run build:backends", - "build:activated": "npm run build:js && npm run build:backends-activated", - "build-css": "node-sass --recursive src/lib -o lo_dash_react_components/css", - "watch-css": "node-sass --recursive src/lib -o lo_dash_react_components/css --watch", + "build-css": "sass --load-path=node_modules src/lib:lo_dash_react_components/css && postcss lo_dash_react_components/css/*.css --replace", + "watch-css": "sass --load-path=node_modules src/lib:lo_dash_react_components/css --watch", "start-all": "npm-run-all --parallel watch-css react-start webpack-start dash-start", - "clean-build": "rm -rf dist/ && rm -rf build/", - "build:python": "npm run clean-build && python setup.py sdist bdist_wheel" + "clean-build:python": "rm -rf dist/ && rm -rf build/", + "build:python": "npm run clean-build:python && python setup.py sdist bdist_wheel" }, "author": "Piotr Mitros ", "license": "AGPL-3.0", + "engines": { + "node": ">=22.0.0" + }, "dependencies": { - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", - "bootstrap": "^5.2.3", - "node-sass": "^9.0.0", - "nodemon": "^2.0.21", - "ramda": "^0.26.1", - "react": "^18.2.0", - "react-bootstrap": "^2.7.2", - "react-dom": "^18.2.0", - "react-router": "^6.8.2", - "react-router-dom": "^6.8.2", + "bootstrap": "^5.3.3", + "ramda": "^0.30.1", + "react": "^18.3.1", + "react-bootstrap": "^2.10.5", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0", "react-scripts": "^5.0.1", - "react-tooltip": "^5.20.0", - "recharts": "^2.4.3", - "web-vitals": "^2.1.4" + "react-tooltip": "^5.28.0", + "recharts": "^2.13.3", + "web-vitals": "^4.2.4" }, "devDependencies": { - "@babel/core": "^7.5.4", - "@babel/plugin-proposal-object-rest-spread": "^7.5.4", - "@babel/preset-env": "^7.5.4", - "@babel/preset-react": "^7.0.0", - "@plotly/dash-component-plugins": "^1.2.0", - "@plotly/webpack-dash-dynamic-import": "^1.2.0", - "babel-eslint": "^10.0.2", - "babel-loader": "^8.0.6", - "copyfiles": "^2.1.1", - "css-loader": "^3.0.0", - "eslint": "^6.0.1", - "eslint-config-prettier": "^6.0.0", - "eslint-plugin-import": "^2.18.0", - "eslint-plugin-react": "^7.14.2", + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "@babel/preset-react": "^7.25.9", + "autoprefixer": "^10.4.20", + "babel-loader": "^9.2.1", + "css-loader": "^7.1.2", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.0.0", + "eslint-plugin-standard": "^4.1.0", + "nodemon": "^3.1.7", "npm-run-all": "^4.1.5", - "prop-types": "^15.7.2", - "react-docgen": "^4.1.1", - "style-loader": "^0.23.1", - "styled-jsx": "^5.1.2", - "terser-webpack-plugin": "^2.3.0", - "webpack": "4.37.0", - "webpack-cli": "3.3.6", - "webpack-serve": "3.1.0" - }, - "engines": { - "npm": ">=8.11.0", - "node": ">=16.0.0 <17.0.0" + "postcss": "^8.4.47", + "postcss-loader": "^8.1.1", + "prettier": "^3.3.3", + "sass": "^1.80.6", + "style-loader": "^4.0.0", + "tailwindcss": "^3.4.14", + "webpack": "^5.96.1", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.1.0" }, "browserslist": { "production": [ @@ -87,8 +65,8 @@ "not op_mini all" ], "development": [ - "last 1 firefox version", "last 1 chrome version", + "last 1 firefox version", "last 1 safari version" ] } diff --git a/modules/lo_dash_react_components/src/lib/components/DAProblemDisplay.react.js b/modules/lo_dash_react_components/src/lib/components/DAProblemDisplay.react.js index 3e18b9f44..871fe60b8 100644 --- a/modules/lo_dash_react_components/src/lib/components/DAProblemDisplay.react.js +++ b/modules/lo_dash_react_components/src/lib/components/DAProblemDisplay.react.js @@ -418,7 +418,7 @@ class DAProblemDisplay extends React.Component { return (
- + {/**/} diff --git a/modules/lo_dash_react_components/src/lib/components/WOAnnotatedText.react.js b/modules/lo_dash_react_components/src/lib/components/WOAnnotatedText.react.js index 27593c548..a50e35e20 100644 --- a/modules/lo_dash_react_components/src/lib/components/WOAnnotatedText.react.js +++ b/modules/lo_dash_react_components/src/lib/components/WOAnnotatedText.react.js @@ -9,7 +9,7 @@ import 'react-tooltip/dist/react-tooltip.css'; * WOAnnotatedText */ export default class WOAnnotatedText extends Component { - constructor(props) { + constructor (props) { super(props); this.state = { selectedItem: null @@ -22,14 +22,14 @@ export default class WOAnnotatedText extends Component { return split.map((line, index) => ( {line} - {split.length-1 === index ? :
} + {split.length - 1 === index ? :
}
)); } return str; - } + }; - render() { + render () { const { breakpoints, text, className } = this.props; const breaks = new Set(); @@ -53,13 +53,13 @@ export default class WOAnnotatedText extends Component { matchingBreaks.forEach(b => { ids[b] = ids[b].concat({ tooltip: obj.tooltip, style: obj.style }); }); - }) + }); const chunks = Array(breaksList.length - 1); let curr, textChunk; for (let i = 0; i < chunks.length; i++) { curr = ids[breaksList[i]]; - textChunk = text.substring(breaksList[i], breaksList[i+1]); + textChunk = text.substring(breaksList[i], breaksList[i + 1]); if (curr.length === 0) { chunks[i] = { text: textChunk, @@ -79,7 +79,7 @@ export default class WOAnnotatedText extends Component { if (chunks.length === 0) { return
{this.replaceNewLines(text)} -
+
; } // TODO figure out how empty breakpoints @@ -93,8 +93,7 @@ export default class WOAnnotatedText extends Component {
{chunks.map((chunk, index) => ( chunk.annotated - ? - HTML DOM Events
- - - - - - - - - Writing Analysis - - - -
+ + + + + + + + + + + + Writing Analysis + + + + +
- +
-
- - +
+ + + \ No newline at end of file diff --git a/learning_observer/learning_observer/static/webapp.js b/learning_observer/learning_observer/static/webapp.js index d1626e706..e69082753 100644 --- a/learning_observer/learning_observer/static/webapp.js +++ b/learning_observer/learning_observer/static/webapp.js @@ -31,6 +31,18 @@ function ajax(config) } } +function initializeBurgerMenu() { + document.querySelectorAll('.navbar-burger').forEach(burger => { + burger.addEventListener('click', () => { + const target = burger.dataset.target; + const targetMenu = document.getElementById(target); + burger.classList.toggle('is-active'); + targetMenu.classList.toggle('is-active'); + }); + }); +} + + requirejs( // TODO: Clean up absolute paths. We hardcoded these for now, due to refactor. @@ -52,11 +64,12 @@ requirejs( function(config, tool_list, d3, mustache, showdown, fontawesome, unauth, login, courses, course, tool, navbar_li, info, auth_info) { // Parse client configuration. config = JSON.parse(config); - console.log(tool_list); + // console.log(tool_list); tool_list = JSON.parse(tool_list); - console.log(tool_list); - console.log(auth_info); - console.log(JSON.stringify(auth_info)); + // console.log(tool_list); + // console.log(auth_info); + // console.log(JSON.stringify(auth_info)); + // Add libraries config.d3 = d3; config.ajax = ajax(config); @@ -152,7 +165,7 @@ requirejs( // * course_json are the course properties // Merged, we can render tools for courses! joined = Object.assign({}, course_json, tool_list[i]); - console.log(joined); + // console.log(joined); tools += mustache.render(tool, joined); } course_json['tools'] = tools; @@ -225,10 +238,16 @@ requirejs( } function loggedin_navbar_menu() { - d3.select(".main-navbar-menu").html(mustache.render(navbar_li, { - 'user_name': user_info()['name'], - 'user_picture': user_info()['picture'] - })); + const navbarMenu = d3.select("#mainNavbar"); + const navbarBurger = d3.select(".navbar-burger"); + + navbarMenu.html(mustache.render(navbar_li, { + 'user_name': user_info()['name'], + 'user_picture': user_info()['picture'] + })); + navbarMenu.classed("is-hidden", false); + navbarBurger.classed("is-hidden", false); + initializeBurgerMenu(); } function setup_page() { From 760c5e1f9600a40bfccd1fcb997b548f2074b8d6 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 1 Apr 2025 11:20:18 -0400 Subject: [PATCH 033/327] =?UTF-8?q?added=20new=20options=20to=20llm=20dash?= =?UTF-8?q?board=20-=20students=20per=20row,=20height,=20indivi=E2=80=A6?= =?UTF-8?q?=20(#216)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improvements to both dashboards: - set students per row, student tile height, and hide headers - document selector component for fetching docs from latest, by assignment, or by timestamp - linted js code AI Assistant dashboard specific improvements: - ability to add custom placeholders - ability to upload files (pdf, md, txt, docx) for the placeholder value Communication protocol - updated to return `students.` instead of `` --- .gitignore | 4 +- VERSION | 2 +- learning_observer/VERSION | 2 +- learning_observer/learning_observer/cache.py | 6 +- .../communication_protocol/executor.py | 5 +- .../communication_protocol/util.py | 1 - .../learning_observer/dashboard.py | 10 +- learning_observer/learning_observer/google.py | 13 + .../learning_observer/rosters.py | 4 +- learning_observer/learning_observer/routes.py | 2 + .../LODocumentSourceSelectorAIO.py | 167 +++++++ .../lo_dash_react_components/__init__.py | 1 + modules/lo_dash_react_components/package.json | 2 +- .../src/lib/components/LOPanelLayout.react.js | 5 +- modules/wo_bulk_essay_analysis/VERSION | 1 + modules/wo_bulk_essay_analysis/pyproject.toml | 3 + modules/wo_bulk_essay_analysis/setup.cfg | 5 +- modules/wo_bulk_essay_analysis/setup.py | 13 - .../wo_bulk_essay_analysis/assets/scripts.js | 429 +++++++++++++----- .../wo_bulk_essay_analysis/assets/styles.css | 15 + .../dashboard/layout.py | 313 +++++++++---- .../wo_bulk_essay_analysis/gpt.py | 1 + .../wo_bulk_essay_analysis/module.py | 39 +- modules/wo_classroom_text_highlighter/VERSION | 2 +- .../assets/scripts.js | 140 +++--- .../dash_dashboard.py | 25 +- modules/writing_observer/VERSION | 2 +- .../writing_observer/aggregator.py | 24 +- .../writing_observer/document_timestamps.py | 11 +- .../writing_observer/module.py | 52 ++- 30 files changed, 943 insertions(+), 356 deletions(-) create mode 100644 modules/lo_dash_react_components/lo_dash_react_components/LODocumentSourceSelectorAIO.py create mode 100644 modules/wo_bulk_essay_analysis/VERSION create mode 100644 modules/wo_bulk_essay_analysis/pyproject.toml delete mode 100644 modules/wo_bulk_essay_analysis/setup.py create mode 100644 modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css diff --git a/.gitignore b/.gitignore index d951ebd57..65002d617 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,6 @@ LanguageTool-5.4 package-lock.json learning_observer/learning_observer/static_data/google/ learning_observer/learning_observer/static_data/admins.yaml -.ipynb_checkpoints/ \ No newline at end of file +.ipynb_checkpoints/ +.eggs/ +.next/ \ No newline at end of file diff --git a/VERSION b/VERSION index 3b7eea53e..2e2f7e4a0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.04.01T14.51.04.751Z.f8ffbdbc.berickson.course.list.homepage.improvements +0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates diff --git a/learning_observer/VERSION b/learning_observer/VERSION index 3b7eea53e..0abb94587 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.04.01T14.51.04.751Z.f8ffbdbc.berickson.course.list.homepage.improvements +0.1.0+2025.03.27T20.51.04.053Z.57041e9f.berickson.022025.gpt.dashboard.updates diff --git a/learning_observer/learning_observer/cache.py b/learning_observer/learning_observer/cache.py index 180bb7aaf..ab11259cd 100644 --- a/learning_observer/learning_observer/cache.py +++ b/learning_observer/learning_observer/cache.py @@ -8,8 +8,8 @@ cache_backend = None -def create_key_from_args(*args, **kwargs): - key_dict = {'args': args, 'kwargs': kwargs} +def create_key_from_args(func, *args, **kwargs): + key_dict = {'func': str(func), 'args': args, 'kwargs': kwargs} key_str = json.dumps(key_dict, sort_keys=True) return key_str @@ -37,7 +37,7 @@ async def wrapper(*args, **kwargs): return await func(*args, **kwargs) # process item if the cache is present - key = create_key_from_args(args, kwargs) + key = create_key_from_args(func, args, kwargs) if key in await cache_backend.keys(): return await cache_backend[key] result = await func(*args, **kwargs) diff --git a/learning_observer/learning_observer/communication_protocol/executor.py b/learning_observer/learning_observer/communication_protocol/executor.py index 3b0fd0ea9..c161ecf73 100644 --- a/learning_observer/learning_observer/communication_protocol/executor.py +++ b/learning_observer/learning_observer/communication_protocol/executor.py @@ -93,6 +93,9 @@ async def call_dispatch(functions, function_name, args, kwargs): ... learning_observer.communication_protocol.exception.DAGExecutionException: ('Function double did not execute properly during call.', 'call_dispatch', {'function_name': 'double', 'args': [None], 'kwargs': {}, 'error': 'Input cannot be None'}, ...) """ + # TODO add in provenance to the call + # this probably requires switching to an async generator instead of regular return + provenance = {'function_name': function_name, 'args': args, 'kwargs': kwargs} try: function = functions[function_name] result = function(*args, **kwargs) @@ -528,6 +531,7 @@ async def hack_handle_keys(function, STUDENTS=None, STUDENTS_path=None, RESOURCE We create a list of fields needed for the `make_key()` function as well as the provenance associated with each. These are zipped together and returned to the user. """ + # TODO do something if `func` is not found func = next((item for item in learning_observer.module_loader.reducers() if item['id'] == function), None) fields_and_provenances = None if STUDENTS is not None and RESOURCES is None: @@ -703,7 +707,6 @@ async def visit(node_name): # We've already done this one. if node_name in visited: return nodes[node_name] - # Execute all the child nodes await walk_dict(nodes[node_name]) diff --git a/learning_observer/learning_observer/communication_protocol/util.py b/learning_observer/learning_observer/communication_protocol/util.py index fc3f8f8c4..b48eb9c71 100644 --- a/learning_observer/learning_observer/communication_protocol/util.py +++ b/learning_observer/learning_observer/communication_protocol/util.py @@ -2,7 +2,6 @@ This file provides utility functions specific to the communication protocol. ''' -import inspect import learning_observer.communication_protocol.query as q import learning_observer.communication_protocol.exception diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index cc11a3862..8c83b7746 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -560,10 +560,15 @@ def _find_student_or_resource(d): provenance = d['provenance'] output = [] if 'STUDENT' in provenance: + output.append('students') output.append(provenance['STUDENT']['user_id']) if 'RESOURCE' in provenance: - output.append('documents') - output.append(provenance['RESOURCE']['doc_id']) + if 'doc_id' in provenance['RESOURCE']: + output.append('documents') + output.append(provenance['RESOURCE']['doc_id']) + if 'assignment_id' in provenance['RESOURCE']: + output.append('assignments') + output.append(provenance['RESOURCE']['assignment_id']) if output: return output return _find_student_or_resource(provenance) @@ -629,6 +634,7 @@ async def _execute_dag(dag_query, target, params): await _drive_generator(generator, dag_query['kwargs']) # Handle rescheduling the execution of the DAG for fresh data + # TODO add some way to specific specific endpoint delays dag_delay = dag_query['kwargs'].get('rerun_dag_delay', 10) if dag_delay < 0: # if dag_delay is negative, we skip repeated execution diff --git a/learning_observer/learning_observer/google.py b/learning_observer/learning_observer/google.py index 60cf3ebd6..f1e45f899 100644 --- a/learning_observer/learning_observer/google.py +++ b/learning_observer/learning_observer/google.py @@ -381,6 +381,19 @@ def clean_course_list(google_json): return courses +@register_cleaner('course_work', 'assignments') +def clean_course_work(google_json): + ''' + Google's course work is one object deeper than we'd like, and update_time + sort order is nicer. This will clean it up a bit + ''' + assignments = google_json.get('courseWork', []) + assignments.sort( + key=lambda x: x.get('update_time', 0) + ) + return assignments + + # Google Docs def _force_text_length(text, length): ''' diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 4329eb5bf..6e66baf3b 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -446,9 +446,9 @@ async def memoize_courseroster_runtime(runtime, course_id): individual nodes are handled: static, dynamic (current), or memoized. ''' @learning_observer.cache.async_memoization() - async def memoization_layer(c): + async def course_roster_memoization_layer(c): return await courseroster_runtime(runtime, c) - return await memoization_layer(course_id) + return await course_roster_memoization_layer(course_id) async def courseroster(request, course_id): diff --git a/learning_observer/learning_observer/routes.py b/learning_observer/learning_observer/routes.py index 5034b81bb..b1fa0adc4 100644 --- a/learning_observer/learning_observer/routes.py +++ b/learning_observer/learning_observer/routes.py @@ -240,6 +240,8 @@ def register_auth_webapp_views(app): debug_log("Running with Google authentication") app.add_routes([ aiohttp.web.get( + # TODO only allow the available sign-in options found in pmss + # '/auth/login/{provider:google|canvas|schoology}', '/auth/login/{provider:google}', handler=learning_observer.auth.social_handler), ]) diff --git a/modules/lo_dash_react_components/lo_dash_react_components/LODocumentSourceSelectorAIO.py b/modules/lo_dash_react_components/lo_dash_react_components/LODocumentSourceSelectorAIO.py new file mode 100644 index 000000000..8025ba28f --- /dev/null +++ b/modules/lo_dash_react_components/lo_dash_react_components/LODocumentSourceSelectorAIO.py @@ -0,0 +1,167 @@ +''' +This file creates an All-In-One component for the Learning +Observer server connection. This handles updating data from the +server (based on individual tree updates), storing any errors +that occured, and showing the time since it was last updated. +''' +from dash import html, dcc, clientside_callback, Output, Input, State, MATCH +import dash_bootstrap_components as dbc +import datetime +import uuid + +class LODocumentSourceSelectorAIO(dbc.Card): + class ids: + source_selector = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'source_selector', + 'aio_id': aio_id + } + assignment_wrapper = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'assignment_wrapper', + 'aio_id': aio_id + } + assignment_input = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'assignment_input', + 'aio_id': aio_id + } + datetime_wrapper = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'datetime_wrapper', + 'aio_id': aio_id + } + date_input = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'date_input', + 'aio_id': aio_id + } + timestamp_input = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'timestamp_input', + 'aio_id': aio_id + } + kwargs_store = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'kwargs_store', + 'aio_id': aio_id + } + apply = lambda aio_id: { + 'component': 'LODocumentSourceSelectorAIO', + 'subcomponent': 'apply', + 'aio_id': aio_id + } + + ids = ids + + def __init__(self, aio_id=None): + if aio_id is None: + aio_id = str(uuid.uuid4()) + + + card_body = dbc.CardBody([ + dbc.Label('Source'), + dbc.RadioItems( + id=self.ids.source_selector(aio_id), + options={'latest': 'Latest Document', + 'assignment': 'Assignment', + 'timestamp': 'Specific Time'}, + inline=True, + value='latest'), + html.Div('Additional Arguments'), + html.Div([ + dbc.RadioItems(id=self.ids.assignment_input(aio_id)), + ], id=self.ids.assignment_wrapper(aio_id)), + html.Div([ + dbc.InputGroup([ + dcc.DatePickerSingle( + id=self.ids.date_input(aio_id), + date=datetime.date.today()), + dbc.Input( + type='time', + id=self.ids.timestamp_input(aio_id), + value=datetime.datetime.now().strftime("%H:%M")) + ]) + ], id=self.ids.datetime_wrapper(aio_id)), + dbc.Button('Apply', id=self.ids.apply(aio_id), class_name='mt-1', n_clicks=0), + dcc.Store(id=self.ids.kwargs_store(aio_id), data={'src': 'latest'}) + ]) + component = [ + dbc.CardHeader('Document Source'), + card_body + ] + super().__init__(component) + + # Update data + clientside_callback( + '''function (clicks, src, assignment, date, time) { + if (clicks === 0) { return window.dash_clientside.no_update; } + let kwargs = {}; + if (src === 'assignment') { + kwargs.assignment = assignment; + } else if (src === 'timestamp') { + kwargs.requested_timestamp = new Date(`${date}T${time}`).getTime().toString() + } + return {src, kwargs}; + } + ''', + Output(ids.kwargs_store(MATCH), 'data'), + Input(ids.apply(MATCH), 'n_clicks'), + State(ids.source_selector(MATCH), 'value'), + State(ids.assignment_input(MATCH), 'value'), + State(ids.date_input(MATCH), 'date'), + State(ids.timestamp_input(MATCH), 'value'), + ) + + clientside_callback( + '''function (src) { + if (src === 'assignment') { + return ['d-none', '']; + } else if (src === 'timestamp') { + return ['', 'd-none'] + } + return ['d-none', 'd-none']; + } + ''', + Output(ids.datetime_wrapper(MATCH), 'className'), + Output(ids.assignment_wrapper(MATCH), 'className'), + Input(ids.source_selector(MATCH), 'value'), + ) + + clientside_callback( + '''async function (id, hash) { + if (hash.length === 0) { return window.dash_clientside.no_update; } + const decoded = decode_string_dict(hash.slice(1)); + if (!decoded.course_id) { return window.dash_clientside.no_update; } + const response = await fetch(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/google/course_work/${decoded.course_id}`); + const data = await response.json(); + const options = data.courseWork.map(function (item) { + return { label: item.title, value: item.id }; + }); + return options; + } + ''', + Output(ids.assignment_input(MATCH), 'options'), + Input(ids.source_selector(MATCH), 'id'), + Input('_pages_location', 'hash'), + ) + + clientside_callback( + '''function (src, assignment, date, time, current) { + if (src === 'assignment' & (assignment === undefined | current.kwargs?.assignment === assignment)) { + return true; + } + if (src === 'timestamp' & current.kwargs?.requested_timestamp === new Date(`${date}T${time}`).getTime().toString()) { + return true; + } + if (src === 'latest' & current.src === 'latest') { return true; } + return false; + } + ''', + Output(ids.apply(MATCH), 'disabled'), + Input(ids.source_selector(MATCH), 'value'), + Input(ids.assignment_input(MATCH), 'value'), + Input(ids.date_input(MATCH), 'date'), + Input(ids.timestamp_input(MATCH), 'value'), + Input(ids.kwargs_store(MATCH), 'data'), + ) diff --git a/modules/lo_dash_react_components/lo_dash_react_components/__init__.py b/modules/lo_dash_react_components/lo_dash_react_components/__init__.py index 4c6fecb3a..f22c1ea64 100644 --- a/modules/lo_dash_react_components/lo_dash_react_components/__init__.py +++ b/modules/lo_dash_react_components/lo_dash_react_components/__init__.py @@ -12,6 +12,7 @@ from .LOConnectionStatusAIO import LOConnectionStatusAIO from .LOConnectionAIO import LOConnectionAIO +from .LODocumentSourceSelectorAIO import LODocumentSourceSelectorAIO from .ProfileSidebarAIO import ProfileSidebarAIO if not hasattr(_dash, '__plotly_dash') and not hasattr(_dash, 'development'): diff --git a/modules/lo_dash_react_components/package.json b/modules/lo_dash_react_components/package.json index 8c2fe18f9..9679e22d4 100644 --- a/modules/lo_dash_react_components/package.json +++ b/modules/lo_dash_react_components/package.json @@ -14,7 +14,7 @@ "watch-css": "sass src/lib:lo_dash_react_components/css --watch", "start-all": "npm-run-all --parallel watch-css react-start webpack-start dash-start", "clean-build:python": "rm -rf dist/ && rm -rf build/", - "build:python": "npm run clean-build:python && python setup.py sdist bdist_wheel" + "build:python": "npm run clean-build:python && npm run build && python setup.py sdist bdist_wheel" }, "author": "Piotr Mitros ", "license": "AGPL-3.0", diff --git a/modules/lo_dash_react_components/src/lib/components/LOPanelLayout.react.js b/modules/lo_dash_react_components/src/lib/components/LOPanelLayout.react.js index e794cac0c..deb6282a4 100644 --- a/modules/lo_dash_react_components/src/lib/components/LOPanelLayout.react.js +++ b/modules/lo_dash_react_components/src/lib/components/LOPanelLayout.react.js @@ -24,7 +24,7 @@ export default class LOPanelLayout extends Component { {leftPanels.map(panel =>
{panel.children} @@ -36,7 +36,7 @@ export default class LOPanelLayout extends Component { {rightPanels.map(panel =>
{panel.children} @@ -77,6 +77,7 @@ LOPanelLayout.propTypes = { width: PropTypes.string, offset: PropTypes.number, side: PropTypes.string, + className: PropTypes.string, id: PropTypes.string.isRequired })), diff --git a/modules/wo_bulk_essay_analysis/VERSION b/modules/wo_bulk_essay_analysis/VERSION new file mode 100644 index 000000000..2e2f7e4a0 --- /dev/null +++ b/modules/wo_bulk_essay_analysis/VERSION @@ -0,0 +1 @@ +0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates diff --git a/modules/wo_bulk_essay_analysis/pyproject.toml b/modules/wo_bulk_essay_analysis/pyproject.toml new file mode 100644 index 000000000..8fe2f47af --- /dev/null +++ b/modules/wo_bulk_essay_analysis/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/modules/wo_bulk_essay_analysis/setup.cfg b/modules/wo_bulk_essay_analysis/setup.cfg index 524a8e0b1..a4db1fe6d 100644 --- a/modules/wo_bulk_essay_analysis/setup.cfg +++ b/modules/wo_bulk_essay_analysis/setup.cfg @@ -2,12 +2,15 @@ name = Writing Observer Automated Essay Feedback description = Dashboard for interfacing a classroom of essays with automated feedback url = https://github.com/ETS-Next-Gen/writing_observer -version = 0.1 +version = file:VERSION [options] packages = find: include_package_data = true +[options.package_data] +wo_bulk_essay_analysis = assets/* + [options.entry_points] lo_modules = wo_bulk_essay_analysis = wo_bulk_essay_analysis.module diff --git a/modules/wo_bulk_essay_analysis/setup.py b/modules/wo_bulk_essay_analysis/setup.py deleted file mode 100644 index e562a4cba..000000000 --- a/modules/wo_bulk_essay_analysis/setup.py +++ /dev/null @@ -1,13 +0,0 @@ -''' -Rather minimalistic install script. To install, run `python -setup.py develop` or just install via requirements.txt -''' - -from setuptools import setup, find_packages - -setup( - name="wo_bulk_essay_analysis", - package_data={ - 'wo_bulk_essay_analysis': ['assets/*'], - } -) diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js index fe5c7756a..6a00a5647 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js @@ -8,17 +8,11 @@ if (!window.dash_clientside) { pdfjsLib.GlobalWorkerOptions.workerSrc = '/static/3rd_party/pdf.worker.min.js'; -const createStudentCard = async function (s, prompt) { - // TODO this ought to come from the comm protocol - const document = Object.keys(s.documents)[0]; - const student = s.documents[document]; +const createStudentCard = async function (s, prompt, width, height, showHeader) { + const selectedDocument = s.doc_id || Object.keys(s.documents || {})[0] || ''; + const student = s.documents?.[selectedDocument] ?? {}; const promptHash = await hashObject({ prompt }); - const header = { - namespace: 'dash_bootstrap_components', - type: 'CardHeader', - props: { children: student.profile.name.full_name } - }; const studentText = { namespace: 'lo_dash_react_components', type: 'WOAnnotatedText', @@ -32,8 +26,8 @@ const createStudentCard = async function (s, prompt) { } }; const feedbackMessage = { - namespace: 'dash_html_components', - type: 'Div', + namespace: DASH_CORE_COMPONENTS, + type: 'Markdown', props: { children: student?.feedback ? student.feedback : '', className: student?.feedback ? 'p-1 overflow-auto' : '', @@ -58,40 +52,56 @@ const createStudentCard = async function (s, prompt) { }; const feedback = promptHash === student.option_hash ? feedbackMessage : feedbackLoading; const feedbackOrError = 'error' in student ? errorMessage : feedback; - const body = { - namespace: 'lo_dash_react_components', - type: 'LOPanelLayout', - props: { - children: studentText, - panels: [{ children: feedbackOrError, id: 'feedback-text', width: '40%' }], - shown: ['feedback-text'], - className: 'overflow-auto p-1' + const userId = student?.user_id || '0'; + const studentTile = createDashComponent( + LO_DASH_REACT_COMPONENTS, 'WOStudentTextTile', + { + showHeader, + studentInfo: formatStudentData(s, []), + selectedDocument, + childComponent: studentText, + id: { type: 'WOAIAssistStudentTileText', index: userId }, + currentOptionHash: promptHash, + style: { height: `${height}px` } } - }; - const card = { - namespace: 'dash_bootstrap_components', - type: 'Card', - props: { - children: [header, body], - style: { maxHeight: '375px' } - } - }; - return { - namespace: 'dash_bootstrap_components', - type: 'Col', - props: { - children: card, - id: student.user_id, - xs: 12, - lg: 6, - xxl: 4 + ); + const tileWrapper = createDashComponent( + DASH_HTML_COMPONENTS, 'Div', + { + className: 'position-relative mb-2', + children: [ + studentTile, + createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Card', + { children: feedbackOrError, body: true } + ), + createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Button', + { + id: { type: 'WOAIAssistStudentTileExpand', index: userId }, + children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-expand' }), + class_name: 'position-absolute top-0 end-0 m-1', + color: 'transparent' + } + ) + ], + id: { type: 'WOAIAssistStudentTile', index: userId }, + style: { width: `${(100 - width) / width}%` } } - }; + ); + return tileWrapper; }; +/** + * Check for if we should trigger loading on a student or not. + * @param {*} s student + * @param {*} promptHash current hash of prompts + * @returns true if student's selected document's hash is the same as promptHash + */ const checkForResponse = function (s, promptHash) { - const document = Object.keys(s.documents)[0]; - const student = s.documents[document]; + if (!('documents' in s)) { return false; } + const selectedDocument = s.doc_id || Object.keys(s.documents || {})[0] || ''; + const student = s.documents[selectedDocument]; return promptHash === student.option_hash; }; @@ -103,36 +113,58 @@ const charactersAfterChar = function (str, char) { return str.slice(commaIndex + 1).trim(); }; +// Helper functions for extracting text from files const extractPDF = async function (base64String) { - const pdfData = atob(charactersAfterChar(base64String, ',')) + const pdfData = atob(charactersAfterChar(base64String, ',')); // Use PDF.js to load and parse the PDF - const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise + const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise; - const totalPages = pdf.numPages - const allTextPromises = [] + const totalPages = pdf.numPages; + const allTextPromises = []; for (let pageNumber = 1; pageNumber <= totalPages; pageNumber++) { const pageTextPromise = pdf.getPage(pageNumber).then(function (page) { - return page.getTextContent() + return page.getTextContent(); }).then(function (textContent) { - return textContent.items.map(item => item.str).join(' ') - }) + return textContent.items.map(item => item.str).join(' '); + }); - allTextPromises.push(pageTextPromise) + allTextPromises.push(pageTextPromise); } - const allTexts = await Promise.all(allTextPromises) - const allText = allTexts.join('\n') + const allTexts = await Promise.all(allTextPromises); + const allText = allTexts.join('\n'); + + return allText; +}; + +const extractTXT = async function (base64String) { + return atob(charactersAfterChar(base64String, ',')); +}; + +const extractMD = async function (base64String) { + return atob(charactersAfterChar(base64String, ',')); +}; - return allText +const extractDOCX = async function (base64String) { + const arrayBuffer = Uint8Array.from(atob(charactersAfterChar(base64String, ',')), c => c.charCodeAt(0)).buffer; + const result = await mammoth.extractRawText({ arrayBuffer }); + return result.value; // The raw text +}; + +const fileTextExtractors = { + pdf: extractPDF, + txt: extractTXT, + md: extractMD, + docx: extractDOCX }; window.dash_clientside.bulk_essay_feedback = { /** * Sends data to server via websocket */ - send_to_loconnection: async function (state, hash, clicks, docSrc, docDate, docTime, query, systemPrompt, tags) { + send_to_loconnection: async function (state, hash, clicks, docKwargs, query, systemPrompt, tags) { if (state === undefined) { return window.dash_clientside.no_update; } @@ -143,11 +175,11 @@ window.dash_clientside.bulk_essay_feedback = { decoded.gpt_prompt = ''; decoded.message_id = ''; - decoded.doc_source = docSrc; - decoded.requested_timestamp = new Date(`${docDate}T${docTime}`).getTime().toString(); + decoded.doc_source = docKwargs.src; + decoded.doc_source_kwargs = docKwargs.kwargs; // TODO what is a reasonable time to wait inbetween subsequent calls for // the same arguments - decoded.rerun_dag_delay = 120; + decoded.rerun_dag_delay = 30; const trig = window.dash_clientside.callback_context.triggered[0]; if (trig.prop_id.includes('bulk-essay-analysis-submit-btn')) { @@ -161,8 +193,8 @@ window.dash_clientside.bulk_essay_feedback = { const message = { wo: { - execution_dag: 'wo_bulk_essay_analysis', - target_exports: ['gpt_bulk'], + execution_dag: 'writing_observer', + target_exports: ['gpt_bulk', 'document_list', 'document_sources'], kwargs: decoded } }; @@ -195,9 +227,9 @@ window.dash_clientside.bulk_essay_feedback = { */ update_input_history_on_query_submission: async function (clicks, query, history) { if (clicks > 0) { - return ['', history.concat(query)] + return history.concat(query); } - return [query, window.dash_clientside.no_update] + return window.dash_clientside.no_update; }, /** @@ -221,50 +253,51 @@ window.dash_clientside.bulk_essay_feedback = { /** * update student cards based on new data in storage */ - updateStudentGridOutput: async function (wsStorageData, history) { + updateStudentGridOutput: async function (wsStorageData, history, width, height, showHeader) { if (!wsStorageData) { return 'No students'; } const currPrompt = history.length > 0 ? history[history.length - 1] : ''; let output = []; - for (const student in wsStorageData) { - output = output.concat(await createStudentCard(wsStorageData[student], currPrompt)); + for (const student in wsStorageData.students) { + output = output.concat(await createStudentCard(wsStorageData.students[student], currPrompt, width, height, showHeader)); } return output; }, /** - * show attachment panel upon uploading document and populate fields - * - * updates the following - * - extracted text from uploaded file - * - default attachment name (based on filename) - * - whether we show the attachment upload panel + * Uploads file content as str */ - open_and_populate_attachment_panel: async function (contents, filename, timestamp, shown) { + handleFileUploadToTextField: async function (contents, filename, timestamp) { if (filename === undefined) { - return ['', '', shown]; + return ''; } - let data = '' - if (filename.endsWith('.pdf')) { - data = await extractPDF(contents); + let data = ''; + try { + const filetype = charactersAfterChar(filename, '.'); + if (filetype in fileTextExtractors) { + data = await fileTextExtractors[filetype](contents); + } else { + console.error('Unsupported file type'); + } + } catch (error) { + console.error('Error extracting text from file:', error); } - // TODO add support for docx-like files - return [data, filename.slice(0, filename.lastIndexOf('.')), shown.concat('attachment')]; + return data; }, /** * append tag in curly braces to input */ add_tag_to_input: function (clicks, curr, store) { - const trig = window.dash_clientside.callback_context.triggered[0] - const trigProp = trig.prop_id - const trigJSON = JSON.parse(trigProp.slice(0, trigProp.lastIndexOf('.'))) + const trig = window.dash_clientside.callback_context.triggered[0]; + const trigProp = trig.prop_id; + const trigJSON = JSON.parse(trigProp.slice(0, trigProp.lastIndexOf('.'))); if (trig.value > 0) { - return curr.concat(` {${trigJSON.index}}`) + return curr.concat(` {${trigJSON.index}}`); } - return window.dash_clientside.no_update + return window.dash_clientside.no_update; }, /** @@ -300,13 +333,36 @@ window.dash_clientside.bulk_essay_feedback = { * - save button disbaled status * - helper text for why we are disabled */ - disable_attachment_save_button: function (label, tags) { - if (label.length === 0) { - return [true, 'Please add a unique label to your attachment'] - } else if (tags.includes(label)) { - return [true, `Label ${label} is already in use.`] + disableAttachmentSaveButton: function (label, content, currentTagStore, replacementId) { + const tags = Object.keys(currentTagStore); + if (label.length === 0 & content.length === 0) { + return [true, '']; + } else if (label.length === 0) { + return [true, 'Add a label for your content']; + } else if (content.length === 0) { + return [true, 'Add content for your label']; + } else if ((!replacementId | replacementId !== label) & tags.includes(label)) { + return [true, `Label ${label} is already in use.`]; } - return [false, ''] + return [false, '']; + }, + + /** + * Opens the tag modal when users want to add a new one or edit an + * existing tag. + */ + openTagAddModal: function (clicks, editClicks, currentTagStore, ids) { + const triggeredItem = window.dash_clientside.callback_context?.triggered_id ?? null; + if (!triggeredItem) { return window.dash_clientside.no_update; } + if (triggeredItem === 'bulk-essay-analysis-tags-add-open-btn') { + return [true, null, '', '']; + } + const id = triggeredItem.index; + const index = ids.findIndex(item => item.index === id); + if (editClicks[index]) { + return [true, id, id, currentTagStore[id]]; + } + return window.dash_clientside.no_update; }, /** @@ -315,32 +371,81 @@ window.dash_clientside.bulk_essay_feedback = { update_tag_buttons: function (tagStore) { const tagLabels = Object.keys(tagStore); const tags = tagLabels.map((val) => { - const button = { - namespace: 'dash_bootstrap_components', - type: 'Button', - props: { + const isStudentText = val === 'student_text'; + const button = createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Button', + { children: val, - id: { type: 'bulk-essay-analysis-tag', index: val }, + id: { type: 'bulk-essay-analysis-tags-tag', index: val }, n_clicks: 0, - size: 'sm', - color: 'secondary' + color: isStudentText ? 'warning' : 'info' } - }; - return button; + ); + const editButton = createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Button', + { + children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-edit' }), + id: { type: 'bulk-essay-analysis-tags-tag-edit', index: val }, + n_clicks: 0, + color: 'info' + } + ); + const deleteButton = createDashComponent( + DASH_CORE_COMPONENTS, 'ConfirmDialogProvider', + { + children: createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Button', + { + children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-trash' }), + color: 'info' + } + ), + id: { type: 'bulk-essay-analysis-tags-tag-delete', index: val }, + message: `Are you sure you want to delete the \`${val}\` placeholder?` + } + ); + const buttons = isStudentText ? [button] : [button, editButton, deleteButton]; + const buttonGroup = createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'ButtonGroup', + { + children: buttons, + class_name: `${isStudentText ? '' : 'prompt-variable-tag'} ms-1 mb-1` + } + ); + return buttonGroup; }); return tags; }, /** - * Save attachment to tag storage + * Save placeholder to browser storage and close edit placeholder modal */ - save_attachment: function (clicks, label, text, tagStore, shown) { + savePlaceholder: function (clicks, label, text, replacementId, tagStore) { if (clicks > 0) { - const newStore = tagStore - newStore[label] = text - return [newStore, shown.filter(item => item !== 'attachment')] + const newStore = tagStore; + if (!!replacementId & replacementId !== label) { + delete newStore[replacementId]; + } + newStore[label] = text; + return [newStore, false]; + } + return window.dash_clientside.no_update; + }, + + /** + * Remove placeholder from store on confirm dialogue yes + */ + removePlaceholder: function (clicks, tagStore, ids) { + const triggeredItem = window.dash_clientside.callback_context?.triggered_id ?? null; + if (!triggeredItem) { return window.dash_clientside.no_update; } + const id = triggeredItem.index; + const index = ids.findIndex(item => item.index === id); + if (clicks[index]) { + const newStore = tagStore; + delete newStore[id]; + return newStore; } - return tagStore + return window.dash_clientside.no_update; }, /** @@ -364,13 +469,10 @@ window.dash_clientside.bulk_essay_feedback = { return [text, true, error]; }, - disable_doc_src_datetime: function (value) { - if (value === 'ts') { - return [false, false]; - } - return [true, true]; - }, - + /** + * Iterate over students and figure out if any of them have not loaded + * yet. We hash the last history item to compare to. + */ updateLoadingInformation: async function (wsStorageData, history) { const noLoading = [false, 0, '']; if (!wsStorageData) { @@ -378,11 +480,118 @@ window.dash_clientside.bulk_essay_feedback = { } const currentPrompt = history.length > 0 ? history[history.length - 1] : ''; const promptHash = await hashObject({ prompt: currentPrompt }); - const returnedResponses = Object.values(wsStorageData).filter(student => checkForResponse(student, promptHash)).length; - const totalStudents = Object.keys(wsStorageData).length; + const returnedResponses = Object.values(wsStorageData.students).filter(student => checkForResponse(student, promptHash)).length; + const totalStudents = Object.keys(wsStorageData.students).length; if (totalStudents === returnedResponses) { return noLoading; } const loadingProgress = returnedResponses / totalStudents + 0.1; const outputText = `Fetching responses from server. This will take a few minutes. (${returnedResponses}/${totalStudents} received)`; return [true, loadingProgress, outputText]; + }, + + adjustTileSize: function (width, height, studentIds) { + const total = studentIds.length; + return [ + Array(total).fill({ width: `${(100 - width) / width}%` }), + Array(total).fill({ height: `${height}px` }) + ]; + }, + + selectStudentForExpansion: function (clicks, shownPanels, ids) { + const triggeredItem = window.dash_clientside.callback_context?.triggered_id ?? null; + if (!triggeredItem) { return window.dash_clientside.no_update; } + let id = null; + if (triggeredItem?.type === 'WOAIAssistStudentTileExpand') { + id = triggeredItem?.index; + if (clicks[ids.findIndex(item => item.index === id)]) { + shownPanels = shownPanels.concat('bulk-essay-analysis-expanded-student-panel'); + } + } else { + return window.dash_clientside.no_update; + } + return [id, shownPanels]; + }, + + expandSelectedStudent: async function (selectedStudent, wsData, showHeader, history) { + console.log('wsData', wsData); + if (!selectedStudent | !(selectedStudent in wsData.students)) { + return window.dash_clientside.no_update; + } + const prompt = history.length > 0 ? history[history.length - 1] : ''; + const s = wsData.students[selectedStudent]; + const selectedDocument = s.doc_id || Object.keys(s.documents || {})[0] || ''; + const document = Object.keys(s.documents)[0]; + const student = s.documents[document]; + const promptHash = await hashObject({ prompt }); + + const studentText = { + namespace: 'lo_dash_react_components', + type: 'WOAnnotatedText', + props: { text: student.text, breakpoints: [], className: 'border-end' } + }; + const errorMessage = { + namespace: 'dash_html_components', + type: 'Div', + props: { + children: 'An error occurred while processing the text.' + } + }; + const feedbackMessage = { + namespace: DASH_CORE_COMPONENTS, + type: 'Markdown', + props: { + children: student?.feedback ? student.feedback : '', + className: student?.feedback ? 'p-1 overflow-auto' : '', + style: { whiteSpace: 'pre-line' } + } + }; + const feedbackLoading = { + namespace: 'dash_html_components', + type: 'Div', + props: { + children: [{ + namespace: 'dash_bootstrap_components', + type: 'Spinner', + props: {} + }, { + namespace: 'dash_html_components', + type: 'Div', + props: { children: 'Waiting for a response.' } + }], + className: 'text-center' + } + }; + const feedback = promptHash === student.option_hash ? feedbackMessage : feedbackLoading; + const feedbackOrError = 'error' in student ? errorMessage : feedback; + const studentTile = createDashComponent( + LO_DASH_REACT_COMPONENTS, 'WOStudentTextTile', + { + showHeader, + studentInfo: formatStudentData(s, []), + selectedDocument, + childComponent: studentText, + id: { type: 'WOAIAssistStudentTileText', index: student.user_id }, + currentOptionHash: promptHash + } + ); + const individualWrapper = createDashComponent( + DASH_HTML_COMPONENTS, 'Div', + { + className: '', + children: [ + studentTile, + createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Card', + { children: feedbackOrError, body: true, className: 'individual-student-feedback' } + ) + ] + } + ); + return individualWrapper; + }, + + closeExpandedStudent: function (clicks, shown) { + if (!clicks) { return window.dash_clientside.no_update; } + shown = shown.filter(item => item !== 'bulk-essay-analysis-expanded-student-panel'); + return shown; } }; diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css new file mode 100644 index 000000000..9e9d73472 --- /dev/null +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css @@ -0,0 +1,15 @@ +.individual-student-feedback { + position: -webkit-sticky; + position: sticky; + bottom: 0; + min-height: 250px; +} + +.prompt-variable-tag button:last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.prompt-variable-tag>div:last-child { + display: inline; +} diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py index 45123ef2c..5df3c0f7e 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py @@ -6,6 +6,7 @@ from dash_renderjson import DashRenderjson import datetime import lo_dash_react_components as lodrc +import random from dash import html, dcc, clientside_callback, ClientsideFunction, Output, Input, State, ALL @@ -24,28 +25,63 @@ panel_layout = f'{prefix}-panel-layout' -_advanced_toggle = f'{prefix}-advanced-toggle' -_advanced_collapse = f'{prefix}-advanced-collapse' +_advanced = f'{prefix}-advanced' +_advanced_doc_src = f'{_advanced}-document-source' +_advanced_toggle = f'{_advanced}-toggle' +_advanced_collapse = f'{_advanced}-collapse' +_advanced_width = f'{_advanced}-width' +_advanced_height = f'{_advanced}-height' +_advanced_hide_header = f'{_advanced}-hide-header' -system_input = f'{prefix}-system-prompt-input' -# document source DOM ids -doc_src = f'{prefix}-doc-src' -doc_src_date = f'{prefix}-doc-src-date' -doc_src_timestamp = f'{prefix}-doc-src-timestamp' - -# attachment upload DOM ids -attachment_upload = f'{prefix}-attachment-upload' -attachment_label = f'{prefix}-attachment-label' -attachment_extracted_text = f'{prefix}-attachment-extracted-text' -attachment_save = f'{prefix}-attachment-save' -attachment_warning_message = f'{prefix}-attachment-warning-message' -attachment_store = f'{prefix}-attachment-store' +_system_input = f'{prefix}-system-prompt-input' +_system_input_tooltip = f'{_system_input}-tooltip' # placeholder DOM ids -tags = f'{prefix}-tags' -placeholder_tooltip = f'{prefix}-placeholder-tooltip' -tag = f'{prefix}-tag' -tag_store = f'{prefix}-tags-store' +_tags = f'{prefix}-tags' +placeholder_tooltip = f'{_tags}-placeholder-tooltip' +tag = f'{_tags}-tag' +_tag_edit = f'{tag}-edit' +_tag_delete = f'{tag}-delete' +tag_store = f'{_tags}-tags-store' +_tag_add = f'{_tags}-add' +_tag_replacement_id = f'{_tag_add}-replacement-id' +_tag_add_modal = f'{_tag_add}-modal' +_tag_add_open = f'{_tag_add}-open-btn' +_tag_add_label = f'{_tag_add}-label' +_tag_add_text = f'{_tag_add}-text' +_tag_add_upload = f'{_tag_add}-upload' +_tag_add_warning = f'{_tag_add}-warning' +_tag_add_save = f'{_tag_add}-save' +tag_modal = dbc.Modal([ + dbc.ModalHeader('Add Placeholder'), + dbc.ModalBody([ + dbc.Input(id=_tag_replacement_id, class_name='d-none'), + dbc.Label('Label'), + dbc.Input( + placeholder='Name your placeholder (e.g., "Narrative Grade 8 Rubric")', + id=_tag_add_label, + value='' + ), + dbc.Label('Contents'), + dbc.Textarea( + placeholder='Enter text here... Uploading a file replaces this content', + id=_tag_add_text, + style={'height': '300px'}, + value='' + ), + dbc.Button( + dcc.Upload( + [html.I(className='fas fa-plus me-1'), 'Upload'], + accept='.txt,.md,.pdf,.docx', + id=_tag_add_upload + ) + ) + ]), + dbc.ModalFooter([ + html.Small(id=_tag_add_warning, className='text-danger'), + dbc.Button('Save', class_name='ms-auto', id=_tag_add_save), + ]) +], id=_tag_add_modal, is_open=False) # prompt history DOM ids history_body = f'{prefix}-history-body' @@ -60,13 +96,41 @@ submit = f'{prefix}-submit-btn' submit_warning_message = f'{prefix}-submit-warning-msg' +_student_data_wrapper = f'{prefix}-student-data' grid = f'{prefix}-essay-grid' +# Expanded student +_expanded_student = f'{prefix}-expanded-student' +_expanded_student_selected = f'{_expanded_student}-selected' +_expanded_student_panel = f'{_expanded_student}-panel' +_expanded_student_child = f'{_expanded_student}-child' +_expanded_student_close = f'{_expanded_student}-close' +expanded_student_component = html.Div([ + html.Div([ + html.H3('Individual Student', className='d-inline-block'), + dbc.Button( + html.I(className='fas fa-close'), + className='float-end', id=_expanded_student_close, + color='transparent'), + ]), + dbc.Input(id=_expanded_student_selected, class_name='d-none'), + html.Div(id=_expanded_student_child) +], className='p-2') + # default prompts -system_prompt = 'You are an assistant to a language arts teacher in a school setting. '\ - 'Your task is to help the teacher assess, understand, and provide feedback on student essays.' +system_prompt = 'You are a helpful assistant for grade school teachers. Your task is to analyze '\ + 'student writing and provide clear, constructive, and age-appropriate feedback. '\ + 'Focus on key writing traits such as clarity, creativity, grammar, and organization. '\ + 'When summarizing, highlight the main ideas and key details. Always maintain a '\ + 'positive and encouraging tone to support student growth.' -starting_prompt = 'Provide 3 bullet points summarizing the following text:\n{student_text}' +starting_prompt = [ + 'Provide 3 bullet points summarizing this text:\n{student_text}', + 'List 3 strengths in this student\'s writing. Use bullet points and focus on creativity or clear ideas:\n{student_text}', + 'Find 2-3 grammar or spelling errors in this text. For each, quote the sentence and suggest a fix:\n{student_text}', + 'Identify 1) Main theme 2) Best sentence 3) One area to improve. Use numbered responses:\n{student_text}', + 'Give one specific compliment and one gentle suggestion to improve this story:\n{student_text}' +] def layout(): @@ -76,19 +140,18 @@ def layout(): # advanced menu for system prompt advanced = [ html.Div([ - dbc.Label('System prompt'), - dbc.Textarea(id=system_input, value=system_prompt) - ]), - html.Div([ - dbc.Label('Document Source'), - dbc.RadioItems(options=[ - {'label': 'Latest Document', 'value': 'latest' }, - {'label': 'Specific Time', 'value': 'ts'}, - ], value='latest', id=doc_src), - dbc.InputGroup([ - dcc.DatePickerSingle(id=doc_src_date, date=datetime.date.today()), - dbc.Input(type='time', id=doc_src_timestamp, value=datetime.datetime.now().strftime("%H:%M")) - ]) + lodrc.LODocumentSourceSelectorAIO(aio_id=_advanced_doc_src), + dbc.Card([ + dbc.CardHeader('View Options'), + dbc.CardBody([ + dbc.Label('Students per row'), + dbc.Input(type='number', min=1, max=10, value=3, step=1, id=_advanced_width), + dbc.Label('Height of student tile'), + dcc.Slider(min=100, max=800, marks=None, value=350, id=_advanced_height), + dbc.Label('Student name headers'), + dbc.Switch(value=True, id=_advanced_hide_header, label='Show/Hide'), + ]) + ]), ]) ] @@ -99,45 +162,38 @@ def layout(): dcc.Store(id=history_store, data=[]) ], class_name='h-100') - # attachment information panel - attachment_panel = dbc.Card([ - dbc.CardHeader('Upload'), - dbc.CardBody([ - dbc.Label('What is this?'), - dbc.Input(placeholder='e.g. argumentative attachment', id=attachment_label, value=''), - dbc.Label('Extracted text from attachment'), - dbc.Textarea(value='', id=attachment_extracted_text, style={'height': '300px'}) - ]), - dbc.CardFooter([ - html.Small(id=attachment_warning_message, className='text-danger'), - dbc.Button('Save', id=attachment_save, color='primary', n_clicks=0, class_name='float-end') - ]), - dcc.Store(id=attachment_store, data='') - ], class_name='h-100') - # query creator panel input_panel = dbc.Card([ dbc.CardHeader('Prompt Input'), - # TODO figure out the proper way to create new tags/upload docs - # then remove the `class_name='d-none'` from this button. - dbc.Button(dcc.Upload([html.I(className='fas fa-plus me-1'), 'Upload'], accept='.pdf', id=attachment_upload), class_name='d-none'), dbc.CardBody([ - dbc.Textarea(id=query_input, value=starting_prompt, class_name='h-100', style={'minHeight': '150px'}), + dbc.Label([ + 'System prompt', + html.I(className='fas fa-circle-question ms-1', id=_system_input_tooltip) + ]), + dbc.Tooltip( + "A system prompt guides the AI's responses. It sets the context for how the AI should analyze or summarize student text.", + target=_system_input_tooltip + ), + dbc.Textarea(id=_system_input, value=system_prompt, style={'minHeight': '120px'}), + dbc.Label('Query'), + dbc.Textarea(id=query_input, value=random.choice(starting_prompt), class_name='h-100', style={'minHeight': '150px'}), html.Div([ html.Span([ 'Placeholders', html.I(className='fas fa-circle-question ms-1', id=placeholder_tooltip) ], className='me-1'), - html.Span([], id=tags), + html.Span([], id=_tags), + dbc.Button([html.I(className='fas fa-add me-1'), 'Add'], id=_tag_add_open, class_name='ms-1 mb-1') ], className='mt-1'), dbc.Tooltip( - 'Click a placeholder to insert it into your prompt. Upon submission, it will be replaced with the corresponding value.', + 'Click a placeholder to insert it into your query. Upon submission, it will be replaced with the corresponding value.', target=placeholder_tooltip ), + tag_modal, dcc.Store(id=tag_store, data={'student_text': ''}), ]), dbc.CardFooter([ - html.Small(id=submit_warning_message, className='text-danger'), + html.Small(id=submit_warning_message, className='text-secondary'), dbc.Button('Submit', color='primary', id=submit, n_clicks=0, class_name='float-end') ]) ]) @@ -154,7 +210,7 @@ def layout(): # overall container cont = dbc.Container([ - html.H2('Writing Observer - AskGPT'), + html.H1('Writing Observer - Classroom AI Feedback Assistant'), dbc.InputGroup([ dbc.InputGroupText(lodrc.LOConnectionAIO(aio_id=_websocket)), dbc.Button([html.I(className='fas fa-cog me-1'), 'Advanced'], id=_advanced_toggle), @@ -165,7 +221,6 @@ def layout(): input_panel, panels=[ {'children': history_favorite_panel, 'width': '30%', 'id': 'history-favorite'}, - {'children': attachment_panel, 'width': '40%', 'id': 'attachment'}, ], shown=['history-favorite'], id=panel_layout @@ -173,19 +228,19 @@ def layout(): alert_component, html.H3('Student Text', className='mt-1'), loading_component, - dbc.Row(id=grid, class_name='g-4'), + lodrc.LOPanelLayout( + html.Div(id=grid, className='d-flex justify-content-between flex-wrap'), + panels=[ + {'children': expanded_student_component, + 'width': '30%', 'id': _expanded_student_panel, + 'side': 'right', 'className': 'vh-100 overflow-auto'} + ], + id=_student_data_wrapper, shown=[] + ), ], fluid=True) return html.Div(cont) -# disbale document date/time options -clientside_callback( - ClientsideFunction(namespace='bulk_essay_feedback', function_name='disable_doc_src_datetime'), - Output(doc_src_date, 'disabled'), - Output(doc_src_timestamp, 'disabled'), - Input(doc_src, 'value') -) - # Toggle if the advanced menu collapse is open or not clientside_callback( ClientsideFunction(namespace=_namespace, function_name='toggleAdvanced'), @@ -201,11 +256,9 @@ def layout(): Input(lodrc.LOConnectionAIO.ids.websocket(_websocket), 'state'), # used for initial setup Input('_pages_location', 'hash'), Input(submit, 'n_clicks'), - Input(doc_src, 'value'), - Input(doc_src_date, 'date'), - Input(doc_src_timestamp, 'value'), + Input(lodrc.LODocumentSourceSelectorAIO.ids.kwargs_store(_advanced_doc_src), 'data'), State(query_input, 'value'), - State(system_input, 'value'), + State(_system_input, 'value'), State(tag_store, 'data'), ) @@ -217,13 +270,12 @@ def layout(): Output(submit_warning_message, 'children'), Input(query_input, 'value'), Input(_loading_collapse, 'is_open'), - State(tag_store, 'data') + Input(tag_store, 'data') ) # add submitted query to history and clear input clientside_callback( ClientsideFunction(namespace='bulk_essay_feedback', function_name='update_input_history_on_query_submission'), - Output(query_input, 'value'), Output(history_store, 'data'), Input(submit, 'n_clicks'), State(query_input, 'value'), @@ -238,16 +290,27 @@ def layout(): Input(history_store, 'data') ) +# Toggle if the add placeholder is open or not +clientside_callback( + ClientsideFunction(namespace=_namespace, function_name='openTagAddModal'), + Output(_tag_add_modal, 'is_open'), + Output(_tag_replacement_id, 'value'), + Output(_tag_add_label, 'value'), + Output(_tag_add_text, 'value'), + Input(_tag_add_open, 'n_clicks'), + Input({'type': _tag_edit, 'index': ALL}, 'n_clicks'), + State(tag_store, 'data'), + State({'type': _tag_edit, 'index': ALL}, 'id'), +) + # show attachment panel upon uploading document and populate fields clientside_callback( - ClientsideFunction(namespace='bulk_essay_feedback', function_name='open_and_populate_attachment_panel'), - Output(attachment_extracted_text, 'value'), - Output(attachment_label, 'value'), - Output(panel_layout, 'shown'), - Input(attachment_upload, 'contents'), - Input(attachment_upload, 'filename'), - Input(attachment_upload, 'last_modified'), - State(panel_layout, 'shown') + ClientsideFunction(namespace='bulk_essay_feedback', function_name='handleFileUploadToTextField'), + Output(_tag_add_text, 'value', allow_duplicate=True), + Input(_tag_add_upload, 'contents'), + Input(_tag_add_upload, 'filename'), + Input(_tag_add_upload, 'last_modified'), + prevent_initial_call=True ) clientside_callback( @@ -263,7 +326,10 @@ def layout(): ClientsideFunction(namespace=_namespace, function_name='updateStudentGridOutput'), Output(grid, 'children'), Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), - Input(history_store, 'data') + Input(history_store, 'data'), + Input(_advanced_width, 'value'), + Input(_advanced_height, 'value'), + Input(_advanced_hide_header, 'value') ) # append tag in curly braces to input @@ -278,30 +344,42 @@ def layout(): # enable/disable the save attachment button if tag is already in use/blank clientside_callback( - ClientsideFunction(namespace='bulk_essay_feedback', function_name='disable_attachment_save_button'), - Output(attachment_save, 'disabled'), - Output(attachment_warning_message, 'children'), - Input(attachment_label, 'value'), - State({'type': tag, 'index': ALL}, 'value') + ClientsideFunction(namespace='bulk_essay_feedback', function_name='disableAttachmentSaveButton'), + Output(_tag_add_save, 'disabled'), + Output(_tag_add_warning, 'children'), + Input(_tag_add_label, 'value'), + Input(_tag_add_text, 'value'), + State(tag_store, 'data'), + State(_tag_replacement_id, 'value') ) # populate word bank of tags clientside_callback( ClientsideFunction(namespace='bulk_essay_feedback', function_name='update_tag_buttons'), - Output(tags, 'children'), + Output(_tags, 'children'), Input(tag_store, 'data') ) -# save attachment to tag storage +# save placeholder to storage clientside_callback( - ClientsideFunction(namespace='bulk_essay_feedback', function_name='save_attachment'), + ClientsideFunction(namespace='bulk_essay_feedback', function_name='savePlaceholder'), Output(tag_store, 'data'), - Output(panel_layout, 'shown', allow_duplicate=True), - Input(attachment_save, 'n_clicks'), - State(attachment_label, 'value'), - State(attachment_extracted_text, 'value'), + Output(_tag_add_modal, 'is_open', allow_duplicate=True), + Input(_tag_add_save, 'n_clicks'), + State(_tag_add_label, 'value'), + State(_tag_add_text, 'value'), + State(_tag_replacement_id, 'value'), State(tag_store, 'data'), - State(panel_layout, 'shown'), + prevent_initial_call=True +) + +# remove placeholder from storage +clientside_callback( + ClientsideFunction(namespace='bulk_essay_feedback', function_name='removePlaceholder'), + Output(tag_store, 'data', allow_duplicate=True), + Input({'type': _tag_delete, 'index': ALL}, 'submit_n_clicks'), + State(tag_store, 'data'), + State({'type': _tag_delete, 'index': ALL}, 'id'), prevent_initial_call=True ) @@ -314,3 +392,44 @@ def layout(): Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), Input(history_store, 'data') ) + +# Adjust student tile size +clientside_callback( + ClientsideFunction(namespace=_namespace, function_name='adjustTileSize'), + Output({'type': 'WOAIAssistStudentTile', 'index': ALL}, 'style', allow_duplicate=True), + Output({'type': 'WOAIAssistStudentTileText', 'index': ALL}, 'style', allow_duplicate=True), + Input(_advanced_width, 'value'), + Input(_advanced_height, 'value'), + State({'type': 'WOAIAssistStudentTile', 'index': ALL}, 'id'), + prevent_initial_call=True +) + +# Expand a single student +clientside_callback( + ClientsideFunction(namespace=_namespace, function_name='selectStudentForExpansion'), + Output(_expanded_student_selected, 'value'), + Output(_student_data_wrapper, 'shown', allow_duplicate=True), + Input({'type': 'WOAIAssistStudentTileExpand', 'index': ALL}, 'n_clicks'), + State(_student_data_wrapper, 'shown'), + State({'type': 'WOAIAssistStudentTile', 'index': ALL}, 'id'), + prevent_initial_call=True +) + +# Update expanded children based on selected student +clientside_callback( + ClientsideFunction(namespace=_namespace, function_name='expandSelectedStudent'), + Output(_expanded_student_child, 'children'), + Input(_expanded_student_selected, 'value'), + Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), + Input(_advanced_hide_header, 'value'), + Input(history_store, 'data'), +) + +# Close expanded student +clientside_callback( + ClientsideFunction(namespace=_namespace, function_name='closeExpandedStudent'), + Output(_student_data_wrapper, 'shown', allow_duplicate=True), + Input(_expanded_student_close, 'n_clicks'), + State(_student_data_wrapper, 'shown'), + prevent_initial_call=True +) diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py index c2790fa07..7562f9ef8 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/gpt.py @@ -1,4 +1,5 @@ import learning_observer.communication_protocol.integration +import learning_observer.cache import learning_observer.prestartup import learning_observer.settings diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/module.py b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/module.py index d4c9f951c..0f180f754 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/module.py +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/module.py @@ -6,15 +6,15 @@ import wo_bulk_essay_analysis.dashboard.layout -NAME = "Writing Observer - AskGPT" +NAME = "Writing Observer - Classroom AI Feedback Assistant" DASH_PAGES = [ { "MODULE": wo_bulk_essay_analysis.dashboard.layout, "LAYOUT": wo_bulk_essay_analysis.dashboard.layout.layout, "ASSETS": 'assets', - "TITLE": "AskGPT", - "DESCRIPTION": "The AskGPT is a robust educational tool that leverages AI to simultaneously analyze and provide feedback on large batches of essays, delivering comprehensive insights and constructive critiques for educators in diverse group settings.", + "TITLE": "Classroom AI Feedback Assistant", + "DESCRIPTION": "The Classroom AI Feedback Assistant is a robust educational tool that leverages AI to simultaneously analyze and provide feedback on large batches of essays, delivering comprehensive insights and constructive critiques for educators in diverse group settings.", "SUBPATH": "bulk-essay-analysis", "CSS": [ thirdparty_url("css/bootstrap.min.css"), @@ -22,34 +22,15 @@ ], "SCRIPTS": [ thirdparty_url('pdf.js'), - thirdparty_url('pdf.worker.js') + thirdparty_url('pdf.worker.js'), + thirdparty_url('mammoth.js') ] } ] -gpt_bulk_essay = q.call('wo_bulk_essay_analysis.gpt_essay_prompt') - -EXECUTION_DAG = { - 'execution_dag': { - 'gpt_map': q.map( - gpt_bulk_essay, - values=q.variable('writing_observer.docs'), - value_path='text', - func_kwargs={'prompt': q.parameter('gpt_prompt'), 'system_prompt': q.parameter('system_prompt'), 'tags': q.parameter('tags', required=False, default={})}, - parallel=True - ), - 'gpt_bulk': q.join(LEFT=q.variable('gpt_map'), LEFT_ON='provenance.provenance.provenance.STUDENT.value.user_id', RIGHT=q.variable('writing_observer.roster'), RIGHT_ON='user_id') - }, - 'exports': { - 'gpt_bulk': { - 'returns': 'gpt_bulk', - 'parameters': ['course_id', 'gpt_prompt', 'system_prompt'], - 'output': '' - } - } -} THIRD_PARTY = { + # PDF parser for reading in files clientside 'pdf.js': { 'url': 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.9.179/pdf.min.js', 'hash': { @@ -64,6 +45,14 @@ '3ebb7dad9946bd3d00bdcd29527dc753fde4b950b2a7a052bd8f66ee643bb736767' } }, + # Docx parser for reading in files clientside + 'mammoth.js': { + 'url': 'https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.9.0/mammoth.browser.min.js', + 'hash': { + '1.9.0': '7e77162c6d0103528615896ba72fcca385ab2f64699cd06d744a6d740c16179' + '322e02e2d45adf1c4d8720f6c8ac7c54e19c6a061eb0814f2abb4b80738d8766a' + } + }, "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, "webfonts/fa-solid-900.woff2": d.FONTAWESOME_WOFF2, diff --git a/modules/wo_classroom_text_highlighter/VERSION b/modules/wo_classroom_text_highlighter/VERSION index e5a2081ce..2e2f7e4a0 100644 --- a/modules/wo_classroom_text_highlighter/VERSION +++ b/modules/wo_classroom_text_highlighter/VERSION @@ -1 +1 @@ -0.1.0+2025.02.26T16.23.19.270Z.e6d405f7.master +0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js index 134662c72..683081ea0 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js @@ -8,6 +8,7 @@ if (!window.dash_clientside) { } const DASH_HTML_COMPONENTS = 'dash_html_components'; +const DASH_CORE_COMPONENTS = 'dash_core_components'; const DASH_BOOTSTRAP_COMPONENTS = 'dash_bootstrap_components'; const LO_DASH_REACT_COMPONENTS = 'lo_dash_react_components'; @@ -57,49 +58,43 @@ function simpleHash (str) { // TODO some of this will move to the communication protocol, but for now // it lives here -// Currently the system only handles grabbing the first document available -// from the student and populates it under latest. We shouldn't hardcode -// anything like latest here and instead pull it from the communication protocol function formatStudentData (student, selectedHighlights) { - // TODO this ought to come from the comm protocol - const document = Object.keys(student.documents)[0]; - - // TODO make sure the comm protocol is providing the doc id - const highlightBreakpoints = selectedHighlights.reduce((acc, option) => { - const offsets = student.documents[document][option.id]?.offsets || []; - if (offsets) { - const modifiedOffsets = offsets.map(offset => { - return { - id: '', - tooltip: option.label, - start: offset[0], - offset: offset[1], - style: { backgroundColor: option.types.highlight.color } - }; - }); - acc = acc.concat(modifiedOffsets); - } - return acc; - }, []); - // const availableDocuments = Object.keys(student.docs).map(id => ({ - // id, - // title: student.docs[id].title || id - // })); - // availableDocuments.push({ id: 'latest', title: 'Latest' }); - const availableDocuments = [{ id: 'latest', title: 'Latest' }] - // TODO currently we only populate the latest data of the student documents - // this is currently the muddiest part of the data flow and ought to be - // cleaned up. + let profile = {}; + const documents = {}; + for (const document in student.documents || []) { + const breakpoints = selectedHighlights.reduce((acc, option) => { + const offsets = student.documents[document][option.id]?.offsets || []; + if (offsets) { + const modifiedOffsets = offsets.map(offset => { + return { + id: '', + tooltip: option.label, + start: offset[0], + offset: offset[1], + style: { backgroundColor: option.types.highlight.color } + }; + }); + acc = acc.concat(modifiedOffsets); + } + return acc; + }, []); + const text = student.documents[document].text; + const optionHash = student.documents[document].option_hash; + profile = student.documents[document].profile; + documents[document] = { text, optionHash, breakpoints }; + } + let availableDocuments = []; + if ('availableDocuments' in student) { + availableDocuments = Object.keys(student.availableDocuments).map(id => ({ + id, + title: student.availableDocuments[id].title || id, + last_access: student.availableDocuments[id].last_access || null + })); + } return { - profile: student.documents[document].profile, + profile, availableDocuments, - documents: { - latest: { - text: student.documents[document].text, - breakpoints: highlightBreakpoints, - optionHash: student.documents[document].option_hash - } - } + documents }; } @@ -114,7 +109,7 @@ window.dash_clientside.wo_classroom_text_highlighter = { * @param {string} urlHash query string from hash for determining course id * @returns stringified json object that is sent to the communication protocl */ - sendToLOConnection: async function (wsReadyState, urlHash, fullOptions) { + sendToLOConnection: async function (wsReadyState, urlHash, docKwargs, fullOptions) { if (wsReadyState === undefined) { return window.dash_clientside.no_update; } @@ -127,11 +122,12 @@ window.dash_clientside.wo_classroom_text_highlighter = { const nlpOptions = determineSelectedNLPOptionsList(fullOptions); decodedParams.nlp_options = nlpOptions; decodedParams.option_hash = optionsHash; + decodedParams.doc_source = docKwargs.src; + decodedParams.doc_source_kwargs = docKwargs.kwargs; const outgoingMessage = { wo_classroom_text_highlighter_query: { execution_dag: 'writing_observer', - // TODO add `doc_list` here when available - target_exports: ['docs_with_nlp_annotations'], + target_exports: ['docs_with_nlp_annotations', 'document_sources', 'document_list'], kwargs: decodedParams } }; @@ -151,11 +147,11 @@ window.dash_clientside.wo_classroom_text_highlighter = { if (!clicks) { return window.dash_clientside.no_update; } - const optionPrefix = 'wo-classroom-text-highlighter-options' + const optionPrefix = 'wo-classroom-text-highlighter-options'; if (shown.includes(optionPrefix)) { shown = shown.filter(item => item !== optionPrefix); } else { - shown = shown.concat(optionPrefix); + shown = shown.concat(optionPrefix); } return shown; }, @@ -163,7 +159,7 @@ window.dash_clientside.wo_classroom_text_highlighter = { closeOptions: function (clicks, shown) { if (!clicks) { return window.dash_clientside.no_update; } shown = shown.filter(item => item !== 'wo-classroom-text-highlighter-options'); - return shown + return shown; }, adjustTileSize: function (width, height, studentIds) { @@ -189,7 +185,7 @@ window.dash_clientside.wo_classroom_text_highlighter = { */ populateOutput: async function (wsStorageData, options, width, height, showHeader) { // console.log('wsStorageData', wsStorageData); - if (!wsStorageData) { + if (!wsStorageData?.students) { return 'No students'; } let output = []; @@ -202,16 +198,15 @@ window.dash_clientside.wo_classroom_text_highlighter = { const selectedMetrics = options.filter(option => option.types?.metric?.value); const optionHash = await hashObject(options); - - for (const student in wsStorageData) { + const students = wsStorageData.students; + for (const student in students) { + const selectedDocument = students[student].doc_id || Object.keys(students[student].documents || {})[0] || ''; const studentTile = createDashComponent( LO_DASH_REACT_COMPONENTS, 'WOStudentTextTile', { showHeader, - studentInfo: formatStudentData(wsStorageData[student], selectedHighlights), - // TODO the selectedDocument ought to remain the same upon updating the student object - // i.e. it should be pulled from the current client student state - selectedDocument: 'latest', + studentInfo: formatStudentData(students[student], selectedHighlights), + selectedDocument, childComponent: createDashComponent(LO_DASH_REACT_COMPONENTS, 'WOAnnotatedText', {}), id: { type: 'WOStudentTextTile', index: student }, currentOptionHash: optionHash, @@ -227,17 +222,17 @@ window.dash_clientside.wo_classroom_text_highlighter = { createDashComponent( DASH_BOOTSTRAP_COMPONENTS, 'Button', { - id: { type: 'WOStudentTileExpand', index: student}, - children: createDashComponent(DASH_HTML_COMPONENTS, 'I', {className: 'fas fa-expand'}), + id: { type: 'WOStudentTileExpand', index: student }, + children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-expand' }), class_name: 'position-absolute top-0 end-0 m-1', - color: 'light' + color: 'transparent' } ) ], - id: { type: 'WOStudentTile', index: student}, + id: { type: 'WOStudentTile', index: student }, style: styleStudentTile(width, height) } - ) + ); output = output.concat(tileWrapper); } return output; @@ -271,12 +266,13 @@ window.dash_clientside.wo_classroom_text_highlighter = { updateLoadingInformation: async function (wsStorageData, nlpOptions) { const noLoading = [false, 0, '']; - if (!wsStorageData) { + if (!wsStorageData?.students) { return noLoading; } + const students = wsStorageData.students; const promptHash = await hashObject(nlpOptions); - const returnedResponses = Object.values(wsStorageData).filter(student => checkForResponse(student, promptHash)).length; - const totalStudents = Object.keys(wsStorageData).length; + const returnedResponses = Object.values(students).filter(student => checkForResponse(student, promptHash)).length; + const totalStudents = Object.keys(students).length; if (totalStudents === returnedResponses) { return noLoading; } const loadingProgress = returnedResponses / totalStudents + 0.1; const outputText = `Fetching responses from server. This will take a few minutes. (${returnedResponses}/${totalStudents} received)`; @@ -292,44 +288,44 @@ window.dash_clientside.wo_classroom_text_highlighter = { if (!currentChild) { return window.dash_clientside.no_update; } id = currentChild?.props.id.index; } else if (triggeredItem?.type === 'WOStudentTileExpand') { - id = triggeredItem?.index + id = triggeredItem?.index; shownPanels = shownPanels.concat('wo-classroom-text-highlighter-expanded-student-panel'); } else { return window.dash_clientside.no_update; } - index = ids.findIndex(item => item.index === id); - child = children[index][0] - return [child, shownPanels] + const index = ids.findIndex(item => item.index === id); + child = children[index][0]; + return [child, shownPanels]; }, closeExpandedStudent: function (clicks, shown) { if (!clicks) { return window.dash_clientside.no_update; } shown = shown.filter(item => item !== 'wo-classroom-text-highlighter-expanded-student-panel'); - return shown + return shown; }, updateLegend: function (options) { const selectedHighlights = options.filter(option => option.types?.highlight?.value); if (selectedHighlights.length === 0) { - return ['No options selected. Click on the `Highlight Options` to select them.', 0] + return ['No options selected. Click on the `Highlight Options` to select them.', 0]; } let output = selectedHighlights.map(highlight => { - const color = highlight.types.highlight.color + const color = highlight.types.highlight.color; const legendItem = createDashComponent( DASH_HTML_COMPONENTS, 'Div', { children: [ createDashComponent( DASH_HTML_COMPONENTS, 'Span', - { style: { width: '0.875rem', height: '0.875rem', backgroundColor: color, display: 'inline-block', marginRight: '0.5rem' }} + { style: { width: '0.875rem', height: '0.875rem', backgroundColor: color, display: 'inline-block', marginRight: '0.5rem' } } ), highlight.label ] } - ) - return legendItem + ); + return legendItem; }); - output = output.concat('Note: words in the student text may have multiple highlights. Hover over a word for the full list of which options apply') + output = output.concat('Note: words in the student text may have multiple highlights. Hover over a word for the full list of which options apply'); return [output, selectedHighlights.length]; } }; diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py index add6b385f..c02c9c0f0 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py @@ -36,6 +36,7 @@ _options_close = f'{_prefix}-options-close' # TODO abstract these into a more generic options component _options_prefix = f'{_prefix}-options' +_options_doc_src = f'{_options_prefix}-document-source' _options_width = f'{_options_prefix}-width' _options_height = f'{_options_prefix}-height' _options_hide_header = f'{_options_prefix}-hide-names' @@ -49,13 +50,18 @@ className='float-end', id=_options_close, color='transparent'), ]), - html.H4('View Options'), - dbc.Label('Students per row'), - dbc.Input(type='number', min=1, max=10, value=3, step=1, id=_options_width), - dbc.Label('Height of student tile'), - dcc.Slider(min=100, max=800, marks=None, value=500, id=_options_height), - dbc.Label('Student name headers'), - dbc.Switch(value=True, id=_options_hide_header, label='Show/Hide'), + lodrc.LODocumentSourceSelectorAIO(aio_id=_options_doc_src), + dbc.Card([ + dbc.CardHeader('View Options'), + dbc.CardBody([ + dbc.Label('Students per row'), + dbc.Input(type='number', min=1, max=10, value=3, step=1, id=_options_width), + dbc.Label('Height of student tile'), + dcc.Slider(min=100, max=800, marks=None, value=500, id=_options_height), + dbc.Label('Student name headers'), + dbc.Switch(value=True, id=_options_hide_header, label='Show/Hide'), + ]) + ]), html.H4('Highlight Options'), wo_classroom_text_highlighter.preset_component.create_layout(), lodrc.WOSettings(id=_options_text_information, options=wo_classroom_text_highlighter.options.OPTIONS, className='table table-striped align-middle') @@ -127,7 +133,9 @@ def layout(): html.Div(id=_output, className='d-flex justify-content-between flex-wrap'), panels=[ {'children': options_component, 'width': '30%', 'id': _options_prefix, 'side': 'left' }, - {'children': expanded_student_component, 'width': '30%', 'id': _expanded_student_panel, 'side': 'right' } + {'children': expanded_student_component, + 'width': '30%', 'id': _expanded_student_panel, + 'side': 'right', 'className': 'vh-100 overflow-auto'} ], id=_options_collapse, shown=[] ), @@ -143,6 +151,7 @@ def layout(): Output(lodrc.LOConnectionAIO.ids.websocket(_websocket), 'send'), Input(lodrc.LOConnectionAIO.ids.websocket(_websocket), 'state'), # used for initial setup Input('_pages_location', 'hash'), + Input(lodrc.LODocumentSourceSelectorAIO.ids.kwargs_store(_options_doc_src), 'data'), Input(_options_text_information, 'options') ) diff --git a/modules/writing_observer/VERSION b/modules/writing_observer/VERSION index a8ceee523..2e2f7e4a0 100644 --- a/modules/writing_observer/VERSION +++ b/modules/writing_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.01.02T16.11.54.892Z.0ba3c08e.berickson.requirements.cleanup +0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 188de004a..85b3809c5 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -414,7 +414,7 @@ async def latest_data(runtime, student_data, options=None): @learning_observer.communication_protocol.integration.publish_function('google.fetch_assignment_docs') -async def fetch_assignment_docs(runtime, course_id, assignment_id): +async def fetch_assignment_docs(runtime, course_id, kwargs=None): ''' Invoke the Google API to retrieve a list of students, where each student possesses a collection of documents associated with the specified assignment. @@ -422,4 +422,24 @@ async def fetch_assignment_docs(runtime, course_id, assignment_id): I wasn't sure where to put this code, so I just tossed it here for now. This entire file needs a bit of reworking, what's a little more? ''' - return await learning_observer.google.assigned_docs(runtime, courseId=course_id, courseWorkId=assignment_id) + if kwargs is None: + kwargs = {} + assignment_id = kwargs.get('assignment') + output = [] + if assignment_id: + output = await learning_observer.google.assigned_docs(runtime, courseId=course_id, courseWorkId=assignment_id) + async for student in learning_observer.util.ensure_async_generator(output): + s = {} + s['doc_id'] = student['documents'][0]['id'] + # HACK a piece above the source selector in the communication protocol + # expects all items returned to have the same provenance. This mirrors + # the provenance that will be returned by the other sources. + # TODO modify the source selector to handle the provenance + provenance = { + 'provenance': {'STUDENT': { + 'value': {'user_id': student['user_id']}, + 'user_id': student['user_id'] + }} + } + s['provenance'] = provenance + yield s diff --git a/modules/writing_observer/writing_observer/document_timestamps.py b/modules/writing_observer/writing_observer/document_timestamps.py index b7c9f5285..4f872655d 100644 --- a/modules/writing_observer/writing_observer/document_timestamps.py +++ b/modules/writing_observer/writing_observer/document_timestamps.py @@ -13,6 +13,8 @@ def select_source(sources, source): within the protocol, we could make it so the system only runs the requested source node. TODO make this a dispatch type within the protocol + TODO add provenance at this layer. Each source might have a different + provenance structure. This should create one to use. ''' if source not in sources: raise KeyError(f'Source, `{source}`, not found in available sources: {sources.keys()}') @@ -20,15 +22,16 @@ def select_source(sources, source): @learning_observer.communication_protocol.integration.publish_function('writing_observer.fetch_doc_at_timestamp') -async def fetch_doc_at_timestamp(overall_timestamps, requested_timestamp=None): +async def fetch_doc_at_timestamp(overall_timestamps, kwargs=None): ''' Iterate over a list of students and determine their latest document - in reference to the `requested_timestamp`. + in reference to the `kwargs.requested_timestamp`. `requested_timestamp` should be a string of ms since unix epoch ''' - # output = [] - # TODO this should be an async gen + if kwargs is None: + kwargs = {} + requested_timestamp = kwargs.get('requested_timestamp', None) async for student in overall_timestamps: timestamps = student.get('timestamps', {}) student['doc_id'] = '' diff --git a/modules/writing_observer/writing_observer/module.py b/modules/writing_observer/writing_observer/module.py index da1f03ace..2c82bf5d4 100644 --- a/modules/writing_observer/writing_observer/module.py +++ b/modules/writing_observer/writing_observer/module.py @@ -78,6 +78,18 @@ nlp_source = learning_observer.settings.module_setting('writing_observer', setting='nlp_source') lt_single_source = learning_observer.settings.module_setting('writing_observer', setting='languagetool_individual_source') lt_group_source = learning_observer.settings.module_setting('writing_observer', setting='languagetool_source') + +gpt_bulk_essay = q.call('wo_bulk_essay_analysis.gpt_essay_prompt') + +# Document sources +document_sources = source_selector( + sources={'timestamp': q.variable('docs_at_ts'), + 'latest': q.variable('doc_ids'), + 'assignment': q.variable('assignment_docs') + }, + source=q.parameter('doc_source', required=False, default='latest') +) + EXECUTION_DAG = { "execution_dag": { "roster": course_roster(runtime=q.parameter("runtime"), course_id=q.parameter("course_id", required=True)), @@ -122,18 +134,28 @@ 'tagged_doc_list': q.join(LEFT=q.variable('unwind_tags'), RIGHT=q.variable('unwind_doc_list'), LEFT_ON='doc_id', RIGHT_ON='doc.id'), 'grouped_doc_list_by_student': group_docs_by(items=q.variable('tagged_doc_list'), value_path='provenance.provenance.value.user_id'), 'tagged_docs_per_student': q.join(LEFT=q.variable('roster'), RIGHT=q.variable('grouped_doc_list_by_student'), LEFT_ON='user_id', RIGHT_ON='user_id'), + # Student document list + 'document_list': q.select(q.keys('writing_observer.document_list', STUDENTS=q.variable('roster'), STUDENTS_path='user_id'), fields={'docs': 'availableDocuments'}), # the following nodes just fetches docs related to an assignment on Google Classroom - 'assignment_docs': assignment_documents(runtime=q.parameter('runtime'), course_id=q.parameter('course_id', required=True), assignment_id=q.parameter('assignment_id', required=True)), + 'assignment_docs': assignment_documents(runtime=q.parameter('runtime'), course_id=q.parameter('course_id', required=True), kwargs=q.parameter('doc_source_kwargs')), # fetch the doc less than or equal to a timestamp 'timestamped_docs': q.select(q.keys('writing_observer.document_access_timestamps', STUDENTS=q.variable('roster'), STUDENTS_path='user_id'), fields={'timestamps': 'timestamps'}), - 'docs_at_ts': document_access_ts(overall_timestamps=q.variable('timestamped_docs'), requested_timestamp=q.parameter('requested_timestamp')), + 'docs_at_ts': document_access_ts(overall_timestamps=q.variable('timestamped_docs'), kwargs=q.parameter('doc_source_kwargs')), # figure out where to source document ids from # current options include `ts` for a given timestamp # or `latest` for the most recently accessed - 'doc_sources': source_selector(sources={'ts': q.variable('docs_at_ts'), 'latest': q.variable('doc_ids')}, source=q.parameter('doc_source', required=False, default='latest')), + 'doc_sources': document_sources, + 'gpt_map': q.map( + gpt_bulk_essay, + values=q.variable('docs'), + value_path='text', + func_kwargs={'prompt': q.parameter('gpt_prompt'), 'system_prompt': q.parameter('system_prompt'), 'tags': q.parameter('tags', required=False, default={})}, + parallel=True + ), + 'gpt_bulk': q.join(LEFT=q.variable('gpt_map'), LEFT_ON='provenance.provenance.provenance.STUDENT.value.user_id', RIGHT=q.variable('roster'), RIGHT_ON='user_id'), }, "exports": { "docs_with_roster": { @@ -141,6 +163,26 @@ "parameters": ["course_id"], "output": "" }, + "roster": { + "returns": "roster", + "parameters": ["course_id"], + "output": "" + }, + "document_list": { + "returns": "document_list", + "parameters": ["course_id"], + "output": "" + }, + "document_sources": { + "returns": "doc_sources", + "parameters": ["course_id"], + "output": "" + }, + 'gpt_bulk': { + 'returns': 'gpt_bulk', + 'parameters': ['course_id', 'gpt_prompt', 'system_prompt'], + 'output': '' + }, "docs_with_nlp_annotations": { "returns": "nlp_combined", "parameters": ["course_id", "nlp_options"], @@ -165,10 +207,6 @@ 'returns': 'tagged_docs_per_student', 'parameters': ['course_id', 'tag_path'] }, - 'assignment_docs': { - 'returns': 'assignment_docs', - 'parameters': ['course_id', 'assignment_id'] - }, 'latest_doc_ids': { 'returns': 'latest_doc_ids', 'parameters': ['course_id'] From 4470b701eb417cd8d95e7e7e5b20d45d7a891d0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 11:23:36 -0400 Subject: [PATCH 034/327] Bump @babel/helpers in /modules/lo_dash_react_components (#217) Bumps [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers) from 7.26.0 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-helpers) --- updated-dependencies: - dependency-name: "@babel/helpers" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../package-lock.json | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/lo_dash_react_components/package-lock.json b/modules/lo_dash_react_components/package-lock.json index 6e528a352..e3bd2774a 100644 --- a/modules/lo_dash_react_components/package-lock.json +++ b/modules/lo_dash_react_components/package-lock.json @@ -433,25 +433,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", + "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", + "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.10" }, "bin": { "parser": "bin/babel-parser.js" @@ -2031,14 +2031,14 @@ } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" }, "engines": { "node": ">=6.9.0" @@ -2063,9 +2063,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", + "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", From 9eea22fb94dc4042c086e84e424c84dc80df886c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 11:23:54 -0400 Subject: [PATCH 035/327] Bump @babel/runtime in /modules/lo_dash_react_components (#218) Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.26.0 to 7.27.0. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.27.0/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/lo_dash_react_components/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/lo_dash_react_components/package-lock.json b/modules/lo_dash_react_components/package-lock.json index e3bd2774a..eb2735ec8 100644 --- a/modules/lo_dash_react_components/package-lock.json +++ b/modules/lo_dash_react_components/package-lock.json @@ -2019,9 +2019,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", - "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" From 7e282384b6225eb1502faf2bee3bd38d8a1f73c9 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 3 Apr 2025 08:12:41 -0400 Subject: [PATCH 036/327] languagetool startup and highlight dashboard improvements LanguageTool startup is now mostly contained within LanguageTool. Additionally, languagetool now functions with an async generator in the communication protocol. Initially this PR was supposed to integrate LT options with the highlight dashboard but selecting errors to figure out which ones are being made makes zero sense. The options are there but not attached to the highlight dashboard as of now. We likely want some way of informing the teacher which LT items are occurring before presenting them highlight options. --- VERSION | 2 +- .../src/lib/components/WOSettings.react.js | 127 ++++++++++----- modules/wo_classroom_text_highlighter/VERSION | 2 +- .../assets/scripts.js | 59 ++++--- .../dash_dashboard.py | 16 +- .../wo_classroom_text_highlighter/options.py | 24 ++- .../preset_component.py | 3 +- .../writing_observer/awe_nlp.py | 2 +- .../writing_observer/languagetool.py | 60 ++----- .../writing_observer/languagetool_features.py | 128 +++++++++++++++ .../writing_observer/nlp_indicators.py | 147 ++++++++++-------- .../writing_observer/stub_nlp.py | 2 +- 12 files changed, 378 insertions(+), 194 deletions(-) create mode 100644 modules/writing_observer/writing_observer/languagetool_features.py diff --git a/VERSION b/VERSION index 2e2f7e4a0..276855ab5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates +0.1.0+2025.04.02T18.12.55.218Z.4a854783.berickson.languagetool.highlight.integration diff --git a/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js b/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js index 2295b8f0b..9b431e8a2 100644 --- a/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js +++ b/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js @@ -13,81 +13,130 @@ function generateNewHighlightColor () { } function sortOptionsIntoTree (options) { - // Create a map of options by their ids const optionsMap = new Map(); options.forEach(option => optionsMap.set(option.id, option)); - // Initialize an array to store the sorted options const sortedOptions = []; - // Function to recursively add children to the sorted array function addChildren (parentId, depth) { options .filter(option => option.parent === parentId) .forEach(option => { sortedOptions.push({ ...option, depth }); - addChildren(option.id, depth + 1); // Recursively add children + addChildren(option.id, depth + 1); }); } - // Start by adding top-level items (those with an empty parent) addChildren('', 0); return sortedOptions; } -/** - * WOSettings is a generic settings interface. - * User can define - */ export default class WOSettings extends Component { constructor (props) { super(props); + this.state = { + collapsed: {} // Tracks which rows are collapsed + }; this.handleRowEvent = this.handleRowEvent.bind(this); this.renderRow = this.renderRow.bind(this); + this.toggleCollapse = this.toggleCollapse.bind(this); } handleRowEvent (event, key, type, colorPicker = false) { - const { setProps, options } = this.props; - const oldOptions = structuredClone(options); - const current = oldOptions.find(option => option.id === key); + const { setProps, value } = this.props; + const currentValue = structuredClone(value); + if (!(key in currentValue)) { + currentValue[key] = {}; + } if (colorPicker) { - current.types[type].color = event.target.value; + currentValue[key][type].color = event.target.value; } else { const { checked } = event.target; - current.types[type].value = checked; - current.types[type].color = current.types[type].color || generateNewHighlightColor(); + if (!(type in currentValue[key])) { + currentValue[key][type] = {}; + } + currentValue[key][type].value = checked; + if (type === 'highlight') { + currentValue[key][type].color = currentValue[key][type].color || generateNewHighlightColor(); + } } - setProps({ options: oldOptions }); + setProps({ value: currentValue }); + } + + toggleCollapse (id) { + this.setState(prevState => ({ + collapsed: { + ...prevState.collapsed, + [id]: !prevState.collapsed[id] + } + })); } - renderRow (row) { - const highlightCell = (row.types && 'highlight' in row.types) + renderRow (row, allRows) { + const { collapsed } = this.state; + const { value } = this.props; + const hasChildren = allRows.some(option => option.parent === row.id); + const isCollapsed = collapsed[row.id] || false; + + const highlightCell = row.types && 'highlight' in row.types ? (<> - this.handleRowEvent(e, row.id, 'highlight')} /> - {row.types.highlight.value - ? this.handleRowEvent(e, row.id, 'highlight', true)} /> + this.handleRowEvent(e, row.id, 'highlight')} + /> + {value[row.id]?.highlight.value + ? ( this.handleRowEvent(e, row.id, 'highlight', true)} + />) : null} ) : null; const metricCell = (row.types && 'metric' in row.types) - ? this.handleRowEvent(e, row.id, 'metric')} /> + ? this.handleRowEvent(e, row.id, 'metric')} /> : null; + return ( - - {'\u00A0'.repeat(row.depth * 2) + row.label} - {highlightCell} - {/* {metricCell} */} - + <> + + +
{row.label}
+ {hasChildren && ( + + )} + + {highlightCell} + {metricCell} + + {/* Render children rows if not collapsed */} + {!isCollapsed && + allRows + .filter(child => child.parent === row.id) + .map(child => this.renderRow(child, allRows))} + ); } render () { const { id, className, options } = this.props; const rows = sortOptionsIntoTree(options); - // TODO due to a HACK with passing data to the child component of - // the student tiles, we currently only support a single child and - // expect it to be the highlighted text component. + return ( - {/* */} + - {rows.map((r) => this.renderRow(r))} + {rows + .filter(row => row.parent === '') // Start with top-level rows + .map(row => this.renderRow(row, rows))}
Name HighlightMetricMetric
); } -}; +} WOSettings.defaultProps = { id: '', className: '', - options: {} + options: [], + value: {} }; WOSettings.propTypes = { @@ -143,6 +195,11 @@ WOSettings.propTypes = { PropTypes.object, PropTypes.undefined ]) - })) + })), + + /** + * Dictionary of selected items + */ + value: PropTypes.object }; diff --git a/modules/wo_classroom_text_highlighter/VERSION b/modules/wo_classroom_text_highlighter/VERSION index 2e2f7e4a0..276855ab5 100644 --- a/modules/wo_classroom_text_highlighter/VERSION +++ b/modules/wo_classroom_text_highlighter/VERSION @@ -1 +1 @@ -0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates +0.1.0+2025.04.02T18.12.55.218Z.4a854783.berickson.languagetool.highlight.integration diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js index 683081ea0..6ae74e4da 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js @@ -17,11 +17,12 @@ function createDashComponent (namespace, type, props) { return { namespace, type, props }; } -function determineSelectedNLPOptionsList (options) { - return options.filter(option => - (option.types?.highlight?.value === true) || - (option.types?.metric?.value === true) - ).map(option => option.id); +function determineSelectedNLPOptionsList (optionsObj) { + if (optionsObj === undefined | optionsObj === null) { return []; } + return Object.keys(optionsObj).filter(id => + optionsObj[id].highlight?.value === true || + optionsObj[id].metric?.value === true + ); } // TODO this ought to move to a more common place like liblo.js @@ -71,7 +72,7 @@ function formatStudentData (student, selectedHighlights) { tooltip: option.label, start: offset[0], offset: offset[1], - style: { backgroundColor: option.types.highlight.color } + style: { backgroundColor: option.highlight.color } }; }); acc = acc.concat(modifiedOffsets); @@ -109,7 +110,7 @@ window.dash_clientside.wo_classroom_text_highlighter = { * @param {string} urlHash query string from hash for determining course id * @returns stringified json object that is sent to the communication protocl */ - sendToLOConnection: async function (wsReadyState, urlHash, docKwargs, fullOptions) { + sendToLOConnection: async function (wsReadyState, urlHash, docKwargs, nlpValue) { if (wsReadyState === undefined) { return window.dash_clientside.no_update; } @@ -118,8 +119,8 @@ window.dash_clientside.wo_classroom_text_highlighter = { const decodedParams = decode_string_dict(urlHash.slice(1)); if (!decodedParams.course_id) { return window.dash_clientside.no_update; } - const optionsHash = await hashObject(fullOptions); - const nlpOptions = determineSelectedNLPOptionsList(fullOptions); + const optionsHash = await hashObject(nlpValue); + const nlpOptions = determineSelectedNLPOptionsList(nlpValue); decodedParams.nlp_options = nlpOptions; decodedParams.option_hash = optionsHash; decodedParams.doc_source = docKwargs.src; @@ -172,8 +173,8 @@ window.dash_clientside.wo_classroom_text_highlighter = { return Array(total).fill(show ? 'd-none' : ''); }, - updateCurrentOptionHash: async function (options, ids) { - const optionHash = await hashObject(options); + updateCurrentOptionHash: async function (value, ids) { + const optionHash = await hashObject(value); const total = ids.length; return Array(total).fill(optionHash); }, @@ -183,21 +184,33 @@ window.dash_clientside.wo_classroom_text_highlighter = { * @param {*} wsStorageData information stored in the websocket store * @returns Dash object to be displayed on page */ - populateOutput: async function (wsStorageData, options, width, height, showHeader) { + populateOutput: async function (wsStorageData, value, width, height, showHeader, options) { // console.log('wsStorageData', wsStorageData); if (!wsStorageData?.students) { return 'No students'; } let output = []; - const selectedHighlights = options.filter(option => option.types?.highlight?.value); + const selectedHighlights = options.reduce(function(filtered, option) { + if (value?.[option.id]?.highlight?.value) { + const selected = {...option, ...value[option.id]}; + filtered.push(selected); + } + return filtered; + }, []); // TODO do something with the selected metrics/progress bars/etc. // currently due to a HACK with how we pass data to the `childComponent` // we are only able to have a single child and we expect it to be the // `WOAnnotatedText` component. - const selectedMetrics = options.filter(option => option.types?.metric?.value); + const selectedMetrics = options.reduce(function(filtered, option) { + if (value?.[option.id]?.metric?.value) { + const selected = {...option, ...value[option.id]}; + filtered.push(selected); + } + return filtered; + }, []); - const optionHash = await hashObject(options); + const optionHash = await hashObject(value); const students = wsStorageData.students; for (const student in students) { const selectedDocument = students[student].doc_id || Object.keys(students[student].documents || {})[0] || ''; @@ -264,13 +277,13 @@ window.dash_clientside.wo_classroom_text_highlighter = { return data[preset]; }, - updateLoadingInformation: async function (wsStorageData, nlpOptions) { + updateLoadingInformation: async function (wsStorageData, nlpValue) { const noLoading = [false, 0, '']; if (!wsStorageData?.students) { return noLoading; } const students = wsStorageData.students; - const promptHash = await hashObject(nlpOptions); + const promptHash = await hashObject(nlpValue); const returnedResponses = Object.values(students).filter(student => checkForResponse(student, promptHash)).length; const totalStudents = Object.keys(students).length; if (totalStudents === returnedResponses) { return noLoading; } @@ -304,13 +317,19 @@ window.dash_clientside.wo_classroom_text_highlighter = { return shown; }, - updateLegend: function (options) { - const selectedHighlights = options.filter(option => option.types?.highlight?.value); + updateLegend: function (value, options) { + const selectedHighlights = options.reduce(function(filtered, option) { + if (value?.[option.id]?.highlight?.value) { + const selected = {...option, ...value[option.id]}; + filtered.push(selected); + } + return filtered; + }, []); if (selectedHighlights.length === 0) { return ['No options selected. Click on the `Highlight Options` to select them.', 0]; } let output = selectedHighlights.map(highlight => { - const color = highlight.types.highlight.color; + const color = highlight.highlight.color; const legendItem = createDashComponent( DASH_HTML_COMPONENTS, 'Div', { diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py index c02c9c0f0..18712240e 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py @@ -152,7 +152,7 @@ def layout(): Input(lodrc.LOConnectionAIO.ids.websocket(_websocket), 'state'), # used for initial setup Input('_pages_location', 'hash'), Input(lodrc.LODocumentSourceSelectorAIO.ids.kwargs_store(_options_doc_src), 'data'), - Input(_options_text_information, 'options') + Input(_options_text_information, 'value') ) # Build the UI based on what we've received from the @@ -161,10 +161,11 @@ def layout(): ClientsideFunction(namespace=_namespace, function_name='populateOutput'), Output(_output, 'children'), Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), - Input(_options_text_information, 'options'), + Input(_options_text_information, 'value'), Input(_options_width, 'value'), Input(_options_height, 'value'), Input(_options_hide_header, 'value'), + State(_options_text_information, 'options'), ) # Toggle if the options collapse is open or not @@ -206,7 +207,7 @@ def layout(): clientside_callback( ClientsideFunction(namespace=_namespace, function_name='updateCurrentOptionHash'), Output({'type': 'WOStudentTextTile', 'index': ALL}, 'currentOptionHash'), - Input(_options_text_information, 'options'), + Input(_options_text_information, 'value'), State({'type': 'WOStudentTextTile', 'index': ALL}, 'id'), ) @@ -248,14 +249,14 @@ def layout(): Output(wo_classroom_text_highlighter.preset_component._store, 'data'), Input(wo_classroom_text_highlighter.preset_component._add_button, 'n_clicks'), State(wo_classroom_text_highlighter.preset_component._add_input, 'value'), - State(_options_text_information, 'options'), + State(_options_text_information, 'value'), State(wo_classroom_text_highlighter.preset_component._store, 'data') ) # Apply clicked preset clientside_callback( ClientsideFunction(namespace=_namespace, function_name='applyPreset'), - Output(_options_text_information, 'options'), + Output(_options_text_information, 'value'), Input({'type': wo_classroom_text_highlighter.preset_component._set_item, 'index': ALL}, 'n_clicks'), State(wo_classroom_text_highlighter.preset_component._store, 'data'), prevent_initial_call=True @@ -268,7 +269,7 @@ def layout(): Output(_loading_progress, 'value'), Output(_loading_information, 'children'), Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), - Input(_options_text_information, 'options') + Input(_options_text_information, 'value') ) # Update legend @@ -276,5 +277,6 @@ def layout(): ClientsideFunction(namespace=_namespace, function_name='updateLegend'), Output(_legend_children, 'children'), Output(_options_toggle_count, 'children'), - Input(_options_text_information, 'options') + Input(_options_text_information, 'value'), + State(_options_text_information, 'options') ) diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py index 6b29036f1..1ca677c3c 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py @@ -1,18 +1,15 @@ -import copy import writing_observer.nlp_indicators +import writing_observer.languagetool_features parents = [] OPTIONS = [ - {'id': indicator['id'], 'types': {'highlight': {}, 'metric': {}}, 'label': indicator['name'], 'parent': ''} + {'id': indicator['id'], 'types': ['highlight'], 'label': indicator['name'], 'parent': indicator['category']} for indicator in writing_observer.nlp_indicators.INDICATOR_JSONS ] - -# TODO currently each preset is the full list of options with specific -# values being set to true/including a color. We ought to just store -# the true values and their respective colors. -# Though if we keep the entire list in the preset, we can choose colors -# for non-true values before they are selected. +for category, label in writing_observer.nlp_indicators.INDICATOR_CATEGORIES.items(): + OPTIONS.append({'id': category, 'label': label, 'parent': 'text_information'}) +OPTIONS.append({'id': 'text_information', 'label': 'Text Information', 'parent': ''}) # Set of colors to use for highlighting with presets HIGHLIGHTING_COLORS = [ @@ -55,13 +52,10 @@ def add_preset_to_presets(key, value): from the `PRESETS_TO_CREATE` object. ''' color_index = 0 - preset = copy.deepcopy(OPTIONS) - for option in preset: - if option['id'] in value: - option['types']['highlight']['value'] = True - option['types']['highlight']['color'] = HIGHLIGHTING_COLORS[color_index] - color_index += 1 - + preset = {} + for option in value: + preset[option] = {'highlight': {'value': True, 'color': HIGHLIGHTING_COLORS[color_index]}} + color_index += 1 PRESETS[key] = preset diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py index dd9c86c69..5a142d56f 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py @@ -28,8 +28,9 @@ def create_layout(): add_preset, html.Div(id=_tray), # TODO we ought to store the presets on the server instead of browser storage + # TODO we need to migrate the old options to new ones dcc.Store(id=_store, data=wo_classroom_text_highlighter.options.PRESETS, storage_type='local') - ]) + ], id=_prefix) # disabled add preset when name already exists diff --git a/modules/writing_observer/writing_observer/awe_nlp.py b/modules/writing_observer/writing_observer/awe_nlp.py index 8eb616204..b6d286fd9 100644 --- a/modules/writing_observer/writing_observer/awe_nlp.py +++ b/modules/writing_observer/writing_observer/awe_nlp.py @@ -154,7 +154,7 @@ def process_text(text, options=None): if item not in writing_observer.nlp_indicators.INDICATORS: continue indicator = writing_observer.nlp_indicators.INDICATORS[item] - (id, label, infoType, select, filterInfo, summaryType) = indicator + (id, label, infoType, select, filterInfo, summaryType, category) = indicator results[id] = outputIndicator(doc, select, infoType, stype=summaryType, text=text, added_filter=filterInfo) results[id].update({ "label": label, diff --git a/modules/writing_observer/writing_observer/languagetool.py b/modules/writing_observer/writing_observer/languagetool.py index 9a4d3e750..c9fdecd70 100644 --- a/modules/writing_observer/writing_observer/languagetool.py +++ b/modules/writing_observer/writing_observer/languagetool.py @@ -1,5 +1,4 @@ import pmss -import requests import learning_observer.cache import learning_observer.communication_protocol.integration @@ -13,6 +12,10 @@ client = None DEFAULT_PORT = 8081 lt_started = False +# TODO fill this in +STUB_LANGUAGETOOL_OUTPUT = { + 'languagetool_stub': 'This is stub output. It will probably break something until we clean this up.' +} pmss.register_field( name='use_languagetool', @@ -47,46 +50,22 @@ def check_languagetool_running(): if learning_observer.settings.module_setting('writing_observer', 'use_languagetool'): host = learning_observer.settings.module_setting('writing_observer', 'languagetool_host') port = learning_observer.settings.module_setting('writing_observer', 'languagetool_port') + # TODO LanguageTool Client also accepts a full server url, we ought to fetch that from pmss - # HACK the following code is a hack to check if the LanguageTool Server is up and running or not - # We ought to set the LT Client object on startup (here); however, - # the LT Client has no way of telling us whether the Server is running or not. - # i.e. the LT Client runs normally even without the server running. - # Thus, we manually make a request to the server to and check the response. - global lt_started + global client, lt_started try: - resp = requests.get(f'http://{host}:{port}/v2/check', params={'text': 'test', 'language': 'en-US'}) - lt_started = resp.status_code == 200 - except requests.ConnectionError: - pass - - if not lt_started: + client = languagetoolClient.languagetoolClient(port=port, host=host) + lt_started = True + except RuntimeError as e: raise learning_observer.prestartup.StartupCheck( - f'LanguageTool Server was not found running on port {port}.\n' - 'Please make sure to run the LanguageTool Server before starting Learning Observer.\n' - 'From within your Python environment, run\n' - '```python\nfrom awe_languagetool import languagetoolServer\nlanguagetoolServer.runServer()\n```.\n' - 'If the LanguageTool is already running on a diffrent port, make sure to adjust ' - 'the `writing_observer.languagetool_port` setting in the `creds.yaml`.' - ) + f'Unable to start LanguageTool Client.\n{e}' + ) from e else: debug_log('WARNING:: We are not configured to try and use to LanguageTool. '\ 'Set `modules.writing_observer.use_languagetool: true` in `creds.yaml` '\ 'to enable the usage of the LanguageTool client.') -def initialize_client(): - ''' - Language Tool requires a client to connect with the server. - This method checks to see if we've created a client yet and - initializes one if we haven't. - ''' - global client - if client is None: - port = learning_observer.settings.module_setting('writing_observer', 'languagetool_port') - client = languagetoolClient.languagetoolClient(port=port) - - @learning_observer.communication_protocol.integration.publish_function('writing_observer.languagetool') async def process_texts(texts): ''' @@ -95,24 +74,13 @@ async def process_texts(texts): We use a closure to allow the system to initialize the memoization KVS. ''' - - initialize_client() - - if not lt_started: - error_text = 'The LanguageTool server has not started. '\ - 'Set `modules.writing_observer.use_languagetool: true` in `creds.yaml` '\ - 'to enable the usage of the LanguageTool client.' - raise ConnectionError(error_text) - @learning_observer.cache.async_memoization() async def process_text(text): return await client.summarizeText(text) - output = [] - for t in texts: + async for t in texts: text = t.get('text', '') - text_data = await process_text(text) + text_data = await process_text(text) if lt_started else STUB_LANGUAGETOOL_OUTPUT text_data['text'] = text text_data['provenance'] = t['provenance'] - output.append(text_data) - return output + yield text_data diff --git a/modules/writing_observer/writing_observer/languagetool_features.py b/modules/writing_observer/writing_observer/languagetool_features.py new file mode 100644 index 000000000..a76350c16 --- /dev/null +++ b/modules/writing_observer/writing_observer/languagetool_features.py @@ -0,0 +1,128 @@ +'''This file lists all the options for LanguageTool (LT) +so we can query specific items. + +Note that all features are calculated at once when +querying LT. Listing all the features here allows +dashboards pull out specific items from the returned +query. + +TODO figure out the best data structure for storing +the available features +''' + +# Each tuple in AVAILABLE_ITEMS contains the full path of +# the categories. +AVAILABLE_ITEMS = [ + ('Capitalization', 'Unnecessary capitalization'), + ('Capitalization', 'Acronyms'), + ('Capitalization', 'Abbreviations'), + ('Capitalization', 'Hyphenated Letter Case'), + ('Capitalization', 'Sentence Start'), + ('Capitalization', 'Proper noun case'), + ('Capitalization', 'First person singular caps'), + ('Grammar', 'Extra function word'), + ('Grammar', 'Nonstandard copula'), + ('Grammar', 'Tag question error'), + ('Grammar', 'Missing function word'), + ('Grammar', 'Wrong verb tense'), + ('Grammar', 'Conjunction error'), + ('Grammar', 'Bare possessive'), + ('Grammar', 'Wrong word order'), + ('Grammar', 'Pronoun/antecedent agreement'), + ('Grammar', 'Plural error'), + ('Grammar', 'Missing content word'), + ('Grammar', 'Repeated words'), + ('Grammar', 'Pronoun case'), + ('Grammar', 'Article error'), + ('Grammar', 'Complement error'), + ('Grammar', 'Sentence fragment'), + ('Grammar', 'Comparative error'), + ('Grammar', 'Superlative error'), + ('Grammar', 'Tense error'), + ('Grammar', 'Wrong verb form'), + ('Grammar', 'Wrong part of speech'), + ('Grammar', 'Subject/verb agreement'), + ('Grammar', 'Wrong past participle'), + ('Grammar', 'Negation error'), + ('Possible Typo', 'Misplaced space'), + ('Possible Typo', 'Missing space'), + ('Possible Typo', 'Incorrect plural possessive'), + ('Possible Typo', 'Wrong case'), + ('Possible Typo', 'Missing hyphen'), + ('Possible Typo', 'Wrong contraction'), + ('Possible Typo', 'Possessive as contraction'), + ('Possible Typo', 'Wrong letter'), + ('Possible Typo', 'Terminology'), + ('Possible Typo', 'Reversed letters'), + ('Possible Typo', 'Possessive as plural'), + ('Possible Typo', 'Extra space'), + ('Possible Typo', 'Bare possessive'), + ('Possible Typo', 'Missing punctuation'), + ('Possible Typo', 'Extra letter'), + ('Possible Typo', 'Missing period'), + ('Possible Typo', 'Plural as possessive'), + ('Possible Typo', 'Repeated words'), + ('Possible Typo', 'Contraction without apostrophe'), + ('Possible Typo', 'Missing letter'), + ('Punctuation', 'Missing end punctuation'), + ('Punctuation', 'Oxford comma'), + ('Punctuation', 'Conjunction'), + ('Punctuation', 'Abbreviation'), + ('Punctuation', 'Comparison'), + ('Punctuation', 'Restrictive modifier'), + ('Punctuation', 'Compound sentence'), + ('Punctuation', 'Compound adjective'), + ('Punctuation', 'Sentence modifier'), + ('Punctuation', 'Vocative'), + ('Semantics', 'Date inconsistency'), + ('Semantics', 'Meaning mismatch'), + ('Spelling', 'Number in Name'), + ('Spelling', 'Misused idiom'), + ('Spelling', 'Missing letter'), + ('Spelling', 'Extra letter'), + # ('Spelling', 'Possible Typo'), + ('Spelling', 'Added or dropped t/ed'), + ('Spelling', 'Phonetic spelling'), + ('Spelling', 'Inconsistent Spelling'), + ('Spelling', 'Homonym'), + ('Spelling', 'Unknown word'), + ('Style', 'Formality'), + ('Style', 'Word choice'), + ('Style', 'Repetition'), + ('Style', 'Wikipedia'), + ('Style', 'British English'), + ('Style', 'Readability'), + ('Style', 'Profanity'), + ('Style', 'Awkward language'), + ('Style', 'Redundancy'), + ('Style', 'Informal'), + ('Style', 'Indian English Only'), + ('Typography', 'Roman Numerals'), + ('Typography', 'Math'), + ('Typography', 'Date format'), + ('Typography', 'Missing space'), + ('Typography', 'Repeated punctuation'), + ('Typography', 'Headings'), + ('Typography', 'Redundant punctuation'), + ('Typography', 'Extra whitespace'), + ('Typography', 'Paragraph Indent'), + ('Typography', 'Time format'), + ('Typography', 'Special character'), + ('Typography', 'Currency'), + ('Usage', 'Confused words'), + ('Usage', 'Missing preposition'), + ('Usage', 'Misused idiom'), + ('Usage', 'Wrong preposition'), + ('Usage', 'Wrong verb'), + ('Usage', 'Extra preposition'), + ('Word Boundaries', 'Missing hyphen'), + ('Word Boundaries', 'Extra space'), + ('Word Boundaries', 'Prefix as word'), + ('Word Boundaries', 'Missing space') +] + +CATEGORIES = [ + 'Grammar', 'Semantics', 'Style', 'Usage', + 'Capitalization', 'Possible Typo', 'Punctuation', + 'Spelling', 'Typography', 'Word Boundaries' +] diff --git a/modules/writing_observer/writing_observer/nlp_indicators.py b/modules/writing_observer/writing_observer/nlp_indicators.py index f3468e761..38c307fdc 100644 --- a/modules/writing_observer/writing_observer/nlp_indicators.py +++ b/modules/writing_observer/writing_observer/nlp_indicators.py @@ -21,92 +21,92 @@ # filter (if needed), summary function to use SPAN_INDICATORS = [ # language - ('Academic Language', 'Token', 'is_academic', None, 'percent'), - ('Informal Language', 'Token', 'vwp_interactive', None, 'percent'), - ('Latinate Words', 'Token', 'is_latinate', None, 'percent'), - ('Opinion Words', 'Token', 'vwp_evaluation', None, 'total'), - ('Emotion Words', 'Token', 'vwp_emotionword', None, 'percent'), + ('Academic Language', 'Token', 'is_academic', None, 'percent', 'language'), + ('Informal Language', 'Token', 'vwp_interactive', None, 'percent', 'language'), + ('Latinate Words', 'Token', 'is_latinate', None, 'percent', 'language'), + ('Opinion Words', 'Token', 'vwp_evaluation', None, 'total', 'language'), + ('Emotion Words', 'Token', 'vwp_emotionword', None, 'percent', 'language'), # vwp_emotion_states looks for noun/emotion word pairs (takes a lot of resources) - ignoring for now # Argumentation # ('Argumentation', 'Token', 'vwp_argumentation', None, 'percent'), # most resource heavy - ignoring for now - ('Argument Words', 'Token', 'vwp_argumentword', None, 'percent'), # more surfacey # TODO needs new label - ('Explicit argument', 'Token', 'vwp_explicit_argument', None, 'percent'), # surfacey # TODO needs new label + ('Argument Words', 'Token', 'vwp_argumentword', None, 'percent', 'argumentation'), # more surfacey # TODO needs new label + ('Explicit argument', 'Token', 'vwp_explicit_argument', None, 'percent', 'argumentation'), # surfacey # TODO needs new label # statements - ('Statements of Opinion', 'Doc', 'vwp_statements_of_opinion', None, 'percent'), - ('Statements of Fact', 'Doc', 'vwp_statements_of_fact', None, 'percent'), + ('Statements of Opinion', 'Doc', 'vwp_statements_of_opinion', None, 'percent', 'statements'), + ('Statements of Fact', 'Doc', 'vwp_statements_of_fact', None, 'percent', 'statements'), # Transitions # eventually we want to exclude \n\n as transitions using `[('!=', ['introductory'])]` # however the introductory category also includes "let us" and "let's" # no highlighting is shown on the new lines, so we won't remove it for now. - ('Transition Words', 'Doc', 'transitions', None, 'counts'), + ('Transition Words', 'Doc', 'transitions', None, 'counts', 'transitions'), # - ('Positive Transition Words', 'Doc', 'transitions', [('==', ['positive'])], 'total'), - ('Conditional Transition Words', 'Doc', 'transitions', [('==', ['conditional'])], 'total'), - ('Consequential Transition Words', 'Doc', 'transitions', [('==', ['consequential'])], 'total'), - ('Contrastive Transition Words', 'Doc', 'transitions', [('==', ['contrastive'])], 'total'), - ('Counterpoint Transition Words', 'Doc', 'transitions', [('==', ['counterpoint'])], 'total'), - ('Comparative Transition Words', 'Doc', 'transitions', [('==', ['comparative'])], 'total'), - ('Cross Referential Transition Words', 'Doc', 'transitions', [('==', ['crossreferential'])], 'total'), - ('Illustrative Transition Words', 'Doc', 'transitions', [('==', ['illustrative'])], 'total'), - ('Negative Transition Words', 'Doc', 'transitions', [('==', ['negative'])], 'total'), - ('Emphatic Transition Words', 'Doc', 'transitions', [('==', ['emphatic'])], 'total'), - ('Evenidentiary Transition Words', 'Doc', 'transitions', [('==', ['evidentiary'])], 'total'), - ('General Transition Words', 'Doc', 'transitions', [('==', ['general'])], 'total'), - ('Ordinal Transition Words', 'Doc', 'transitions', [('==', ['ordinal'])], 'total'), - ('Purposive Transition Words', 'Doc', 'transitions', [('==', ['purposive'])], 'total'), - ('Periphrastic Transition Words', 'Doc', 'transitions', [('==', ['periphrastic'])], 'total'), - ('Hypothetical Transition Words', 'Doc', 'transitions', [('==', ['hypothetical'])], 'total'), - ('Summative Transition Words', 'Doc', 'transitions', [('==', ['summative'])], 'total'), - ('Introductory Transition Words', 'Doc', 'transitions', [('==', ['introductory'])], 'total'), + ('Positive Transition Words', 'Doc', 'transitions', [('==', ['positive'])], 'total', 'transitions'), + ('Conditional Transition Words', 'Doc', 'transitions', [('==', ['conditional'])], 'total', 'transitions'), + ('Consequential Transition Words', 'Doc', 'transitions', [('==', ['consequential'])], 'total', 'transitions'), + ('Contrastive Transition Words', 'Doc', 'transitions', [('==', ['contrastive'])], 'total', 'transitions'), + ('Counterpoint Transition Words', 'Doc', 'transitions', [('==', ['counterpoint'])], 'total', 'transitions'), + ('Comparative Transition Words', 'Doc', 'transitions', [('==', ['comparative'])], 'total', 'transitions'), + ('Cross Referential Transition Words', 'Doc', 'transitions', [('==', ['crossreferential'])], 'total', 'transitions'), + ('Illustrative Transition Words', 'Doc', 'transitions', [('==', ['illustrative'])], 'total', 'transitions'), + ('Negative Transition Words', 'Doc', 'transitions', [('==', ['negative'])], 'total', 'transitions'), + ('Emphatic Transition Words', 'Doc', 'transitions', [('==', ['emphatic'])], 'total', 'transitions'), + ('Evenidentiary Transition Words', 'Doc', 'transitions', [('==', ['evidentiary'])], 'total', 'transitions'), + ('General Transition Words', 'Doc', 'transitions', [('==', ['general'])], 'total', 'transitions'), + ('Ordinal Transition Words', 'Doc', 'transitions', [('==', ['ordinal'])], 'total', 'transitions'), + ('Purposive Transition Words', 'Doc', 'transitions', [('==', ['purposive'])], 'total', 'transitions'), + ('Periphrastic Transition Words', 'Doc', 'transitions', [('==', ['periphrastic'])], 'total', 'transitions'), + ('Hypothetical Transition Words', 'Doc', 'transitions', [('==', ['hypothetical'])], 'total', 'transitions'), + ('Summative Transition Words', 'Doc', 'transitions', [('==', ['summative'])], 'total', 'transitions'), + ('Introductory Transition Words', 'Doc', 'transitions', [('==', ['introductory'])], 'total', 'transitions'), # pos_ - ('Adjectives', 'Token', 'pos_', [('==', ['ADJ'])], 'total'), - ('Adverbs', 'Token', 'pos_', [('==', ['ADV'])], 'total'), - ('Nouns', 'Token', 'pos_', [('==', ['NOUN'])], 'total'), - ('Proper Nouns', 'Token', 'pos_', [('==', ['PROPN'])], 'total'), - ('Verbs', 'Token', 'pos_', [('==', ['VERB'])], 'total'), - ('Numbers', 'Token', 'pos_', [('==', ['NUM'])], 'total'), - ('Prepositions', 'Token', 'pos_', [('==', ['ADP'])], 'total'), - ('Coordinating Conjunction', 'Token', 'pos_', [('==', ['CCONJ'])], 'total'), - ('Subordinating Conjunction', 'Token', 'pos_', [('==', ['SCONJ'])], 'total'), - ('Auxiliary Verb', 'Token', 'pos_', [('==', ['AUX'])], 'total'), - ('Pronoun', 'Token', 'pos_', [('==', ['PRON'])], 'total'), + ('Adjectives', 'Token', 'pos_', [('==', ['ADJ'])], 'total', 'pos'), + ('Adverbs', 'Token', 'pos_', [('==', ['ADV'])], 'total', 'pos'), + ('Nouns', 'Token', 'pos_', [('==', ['NOUN'])], 'total', 'pos'), + ('Proper Nouns', 'Token', 'pos_', [('==', ['PROPN'])], 'total', 'pos'), + ('Verbs', 'Token', 'pos_', [('==', ['VERB'])], 'total', 'pos'), + ('Numbers', 'Token', 'pos_', [('==', ['NUM'])], 'total', 'pos'), + ('Prepositions', 'Token', 'pos_', [('==', ['ADP'])], 'total', 'pos'), + ('Coordinating Conjunction', 'Token', 'pos_', [('==', ['CCONJ'])], 'total', 'pos'), + ('Subordinating Conjunction', 'Token', 'pos_', [('==', ['SCONJ'])], 'total', 'pos'), + ('Auxiliary Verb', 'Token', 'pos_', [('==', ['AUX'])], 'total', 'pos'), + ('Pronoun', 'Token', 'pos_', [('==', ['PRON'])], 'total', 'pos'), # sentence variety # The general 'Sentence Types' will return a complex object of all sentence types # that we do not yet handle. # ('Sentence Types', 'Doc', 'sentence_types', None, 'counts'), - ('Simple Sentences', 'Doc', 'sentence_types', [('==', ['Simple'])], 'total'), - ('Simple with Complex Predicates', 'Doc', 'sentence_types', [('==', ['SimpleComplexPred'])], 'total'), - ('Simple with Compound Predicates', 'Doc', 'sentence_types', [('==', ['SimpleCompoundPred'])], 'total'), - ('Simple with Compound Complex Predicates', 'Doc', 'sentence_types', [('==', ['SimpleCompoundComplexPred'])], 'total'), - ('Compound Sentences', 'Doc', 'sentence_types', [('==', ['Compound'])], 'total'), - ('Complex Sentences', 'Doc', 'sentence_types', [('==', ['Complex'])], 'total'), - ('Compound Complex Sentences', 'Doc', 'sentence_types', [('==', ['CompoundComplex'])], 'total'), + ('Simple Sentences', 'Doc', 'sentence_types', [('==', ['Simple'])], 'total', 'sentence_type'), + ('Simple with Complex Predicates', 'Doc', 'sentence_types', [('==', ['SimpleComplexPred'])], 'total', 'sentence_type'), + ('Simple with Compound Predicates', 'Doc', 'sentence_types', [('==', ['SimpleCompoundPred'])], 'total', 'sentence_type'), + ('Simple with Compound Complex Predicates', 'Doc', 'sentence_types', [('==', ['SimpleCompoundComplexPred'])], 'total', 'sentence_type'), + ('Compound Sentences', 'Doc', 'sentence_types', [('==', ['Compound'])], 'total', 'sentence_type'), + ('Complex Sentences', 'Doc', 'sentence_types', [('==', ['Complex'])], 'total', 'sentence_type'), + ('Compound Complex Sentences', 'Doc', 'sentence_types', [('==', ['CompoundComplex'])], 'total', 'sentence_type'), # Sources/Attributes/Citations/Quotes - ('Information Sources', 'Token', 'vwp_source', None, 'percent'), - ('Attributions', 'Token', 'vwp_attribution', None, 'percent'), - ('Citations', 'Token', 'vwp_cite', None, 'percent'), - ('Quoted Words', 'Token', 'vwp_quoted', None, 'percent'), + ('Information Sources', 'Token', 'vwp_source', None, 'percent', 'source_information'), + ('Attributions', 'Token', 'vwp_attribution', None, 'percent', 'source_information'), + ('Citations', 'Token', 'vwp_cite', None, 'percent', 'source_information'), + ('Quoted Words', 'Token', 'vwp_quoted', None, 'percent', 'source_information'), # Dialogue - ('Direct Speech Verbs', 'Doc', 'vwp_direct_speech', None, 'percent'), - ('Indirect Speech', 'Token', 'vwp_in_direct_speech', None, 'percent'), + ('Direct Speech Verbs', 'Doc', 'vwp_direct_speech', None, 'percent', 'dialogue'), + ('Indirect Speech', 'Token', 'vwp_in_direct_speech', None, 'percent', 'dialogue'), # vwp_quoted - already used above # tone - ('Positive Tone', 'Token', 'vwp_tone', [('>', [.4])], 'percent'), - ('Negative Tone', 'Token', 'vwp_tone', [('<', [-.4])], 'percent'), + ('Positive Tone', 'Token', 'vwp_tone', [('>', [.4])], 'percent', 'tone'), + ('Negative Tone', 'Token', 'vwp_tone', [('<', [-.4])], 'percent', 'tone'), # details - ('Concrete Details', 'Token', 'concrete_details', None, 'percent'), - ('Main Idea Sentences', 'Doc', 'main_ideas', None, 'total'), - ('Supporting Idea Sentences', 'Doc', 'supporting_ideas', None, 'total'), - ('Supporting Detail Sentences', 'Doc', 'supporting_details', None, 'total'), + ('Concrete Details', 'Token', 'concrete_details', None, 'percent', 'details'), + ('Main Idea Sentences', 'Doc', 'main_ideas', None, 'total', 'details'), + ('Supporting Idea Sentences', 'Doc', 'supporting_ideas', None, 'total', 'details'), + ('Supporting Detail Sentences', 'Doc', 'supporting_details', None, 'total', 'details'), # Other items - ('Polysyllabic Words', 'Token', 'nSyll', [('>', [3])], 'percent'), - ('Low Frequency Words', 'Token', 'max_freq', [('<', [4])], 'percent'), - ('Sentences', 'Doc', 'sents', None, 'total'), - ('Paragraphs', 'Doc', 'delimiter_\n', None, 'total'), - ('Character Trait Words', 'Token', 'vwp_character', None, 'percent'), - ('In Past Tense', 'Token', 'in_past_tense_scope', None, 'percent'), - ('Explicit Claims', 'Doc', 'vwp_propositional_attitudes', None, 'percent'), - ('Social Awareness', 'Doc', 'vwp_social_awareness', None, 'percent') + ('Polysyllabic Words', 'Token', 'nSyll', [('>', [3])], 'percent', 'other'), + ('Low Frequency Words', 'Token', 'max_freq', [('<', [4])], 'percent', 'other'), + ('Sentences', 'Doc', 'sents', None, 'total', 'other'), + ('Paragraphs', 'Doc', 'delimiter_\n', None, 'total', 'other'), + ('Character Trait Words', 'Token', 'vwp_character', None, 'percent', 'other'), + ('In Past Tense', 'Token', 'in_past_tense_scope', None, 'percent', 'other'), + ('Explicit Claims', 'Doc', 'vwp_propositional_attitudes', None, 'percent', 'other'), + ('Social Awareness', 'Doc', 'vwp_social_awareness', None, 'percent', 'other') ] # Create indicator dict to easily refer to each tuple above by name @@ -125,8 +125,23 @@ class NLPIndicators(dataobject): parent: str filters: list function: str + category: str # tooltip: str indicators = map(lambda ind: NLPIndicators(*ind), INDICATOR_W_IDS) INDICATOR_JSONS = [asdict(ind) for ind in indicators] + +INDICATOR_CATEGORIES = { + 'language': 'Language', + 'argumentation': 'Argumentation', + 'statements': 'Statements', + 'transitions': 'Transition Words', + 'pos': 'Parts of Speech', + 'sentence_type': 'Sentence Types', + 'source_information': 'Source Information', + 'dialogue': 'Dialogue', + 'tone': 'Tone', + 'details': 'Details', + 'other': 'Other' +} diff --git a/modules/writing_observer/writing_observer/stub_nlp.py b/modules/writing_observer/writing_observer/stub_nlp.py index bca9c352b..a9ce89811 100644 --- a/modules/writing_observer/writing_observer/stub_nlp.py +++ b/modules/writing_observer/writing_observer/stub_nlp.py @@ -137,7 +137,7 @@ async def process_texts(writing_data, options=None): if option not in writing_observer.nlp_indicators.INDICATORS: continue indicator = writing_observer.nlp_indicators.INDICATORS[option] - (id, label, infoType, select, filterInfo, summaryType) = indicator + (id, label, infoType, select, filterInfo, summaryType, category) = indicator results[id] = {} state = random.getstate() random.seed(id) From c336d5da8bdcc85e6f394a4ef7120c848db9ae3f Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 3 Apr 2025 09:17:04 -0400 Subject: [PATCH 037/327] fixed module names --- VERSION | 2 +- modules/wo_bulk_essay_analysis/VERSION | 2 +- modules/wo_bulk_essay_analysis/setup.cfg | 2 +- modules/wo_classroom_text_highlighter/VERSION | 2 +- modules/wo_classroom_text_highlighter/setup.cfg | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 276855ab5..21b05a126 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.04.02T18.12.55.218Z.4a854783.berickson.languagetool.highlight.integration +0.1.0+2025.04.03T13.17.04.073Z.7e282384.master diff --git a/modules/wo_bulk_essay_analysis/VERSION b/modules/wo_bulk_essay_analysis/VERSION index 2e2f7e4a0..21b05a126 100644 --- a/modules/wo_bulk_essay_analysis/VERSION +++ b/modules/wo_bulk_essay_analysis/VERSION @@ -1 +1 @@ -0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates +0.1.0+2025.04.03T13.17.04.073Z.7e282384.master diff --git a/modules/wo_bulk_essay_analysis/setup.cfg b/modules/wo_bulk_essay_analysis/setup.cfg index a4db1fe6d..9f5cfb10d 100644 --- a/modules/wo_bulk_essay_analysis/setup.cfg +++ b/modules/wo_bulk_essay_analysis/setup.cfg @@ -1,5 +1,5 @@ [metadata] -name = Writing Observer Automated Essay Feedback +name = WO Bulk Essay Analysis description = Dashboard for interfacing a classroom of essays with automated feedback url = https://github.com/ETS-Next-Gen/writing_observer version = file:VERSION diff --git a/modules/wo_classroom_text_highlighter/VERSION b/modules/wo_classroom_text_highlighter/VERSION index 276855ab5..21b05a126 100644 --- a/modules/wo_classroom_text_highlighter/VERSION +++ b/modules/wo_classroom_text_highlighter/VERSION @@ -1 +1 @@ -0.1.0+2025.04.02T18.12.55.218Z.4a854783.berickson.languagetool.highlight.integration +0.1.0+2025.04.03T13.17.04.073Z.7e282384.master diff --git a/modules/wo_classroom_text_highlighter/setup.cfg b/modules/wo_classroom_text_highlighter/setup.cfg index 9987017ad..5ad128574 100644 --- a/modules/wo_classroom_text_highlighter/setup.cfg +++ b/modules/wo_classroom_text_highlighter/setup.cfg @@ -1,5 +1,5 @@ [metadata] -name = Writing Observer Classroom Text Highlighter +name = WO Classroom Text Highlighter version = file:VERSION description = Use this as a base template for creating new modules on the Learning Observer. From 3bdcc7c94250daba86cbea1d5a3b156d055cda3a Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 3 Apr 2025 10:43:39 -0400 Subject: [PATCH 038/327] small js bug fixes for dashboards --- VERSION | 2 +- .../src/lib/components/WOSettings.react.js | 4 ++-- modules/wo_bulk_essay_analysis/VERSION | 2 +- .../wo_bulk_essay_analysis/assets/scripts.js | 15 +-------------- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/VERSION b/VERSION index 21b05a126..80aee927e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.04.03T13.17.04.073Z.7e282384.master +0.1.0+2025.04.03T14.43.39.953Z.c336d5da.master diff --git a/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js b/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js index 9b431e8a2..1783aacdc 100644 --- a/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js +++ b/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js @@ -79,7 +79,7 @@ export default class WOSettings extends Component { const hasChildren = allRows.some(option => option.parent === row.id); const isCollapsed = collapsed[row.id] || false; - const highlightCell = row.types && 'highlight' in row.types + const highlightCell = row.types && row.types.includes('highlight') ? (<> ) : null; - const metricCell = (row.types && 'metric' in row.types) + const metricCell = (row.types && row.types.includes('metric')) ? this.handleRowEvent(e, row.id, 'metric')} /> : null; diff --git a/modules/wo_bulk_essay_analysis/VERSION b/modules/wo_bulk_essay_analysis/VERSION index 21b05a126..80aee927e 100644 --- a/modules/wo_bulk_essay_analysis/VERSION +++ b/modules/wo_bulk_essay_analysis/VERSION @@ -1 +1 @@ -0.1.0+2025.04.03T13.17.04.073Z.7e282384.master +0.1.0+2025.04.03T14.43.39.953Z.c336d5da.master diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js index 6a00a5647..55cdbae0d 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js @@ -210,18 +210,6 @@ window.dash_clientside.bulk_essay_feedback = { return !isOpen; }, - /** - * parse message from websocket to the data and error store - */ - receive_ws_message: function (message) { - const data = JSON.parse(message.data).wo.gpt_bulk || []; - if (data.error !== undefined) { - console.error('Error received from server', data.error); - return [[], data.error]; - } - return [data, false]; - }, - /** * adds submitted query to history and clear input */ @@ -512,8 +500,7 @@ window.dash_clientside.bulk_essay_feedback = { }, expandSelectedStudent: async function (selectedStudent, wsData, showHeader, history) { - console.log('wsData', wsData); - if (!selectedStudent | !(selectedStudent in wsData.students)) { + if (!selectedStudent | !(selectedStudent in (wsData.students || {}))) { return window.dash_clientside.no_update; } const prompt = history.length > 0 ? history[history.length - 1] : ''; From bee90d117fba7cf781cc4306e80a66dde8bf423b Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 6 May 2025 09:32:37 -0400 Subject: [PATCH 039/327] add process metrics to dashboards Added process metrics (time on task and currently active) to both dashboards. They are currently just badges that appear at the top of student cards. This pull request also cleans up a handful of dashboard functionality. Added basic semaphore logic to LLMs (just Ollama for now) to prevent overloading it. Added initial workflow for comm protocol select to use multiget. --- VERSION | 2 +- learning_observer/VERSION | 2 +- learning_observer/learning_observer/cache.py | 2 +- .../communication_protocol/executor.py | 43 +++-- .../learning_observer/dashboard.py | 8 +- .../learning_observer/downloads.py | 18 +- learning_observer/learning_observer/kvs.py | 8 + .../learning_observer/redis_connection.py | 9 +- .../src/lib/components/LONameTag.scss | 1 - .../src/lib/components/WOSettings.react.js | 16 +- .../lib/components/WOStudentTextTile.react.js | 110 ++++------- .../components/WOStudentTextTile.testdata.js | 53 +----- modules/lo_gpt/lo_gpt/gpt.py | 35 ++-- modules/wo_bulk_essay_analysis/VERSION | 2 +- .../wo_bulk_essay_analysis/assets/scripts.js | 113 ++++++++---- .../wo_bulk_essay_analysis/assets/styles.css | 7 - .../dashboard/layout.py | 70 +++++-- modules/wo_classroom_text_highlighter/VERSION | 2 +- .../assets/scripts.js | 172 +++++++++--------- .../dash_dashboard.py | 26 ++- .../wo_classroom_text_highlighter/options.py | 14 +- .../preset_component.py | 6 + modules/writing_observer/VERSION | 2 +- .../writing_observer/module.py | 10 +- 24 files changed, 398 insertions(+), 333 deletions(-) diff --git a/VERSION b/VERSION index 80aee927e..82e6a0cee 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.04.03T14.43.39.953Z.c336d5da.master +0.1.0+2025.05.01T19.10.46.507Z.bc7bcb4c.berickson.202504.process.metrics diff --git a/learning_observer/VERSION b/learning_observer/VERSION index 0abb94587..82e6a0cee 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.03.27T20.51.04.053Z.57041e9f.berickson.022025.gpt.dashboard.updates +0.1.0+2025.05.01T19.10.46.507Z.bc7bcb4c.berickson.202504.process.metrics diff --git a/learning_observer/learning_observer/cache.py b/learning_observer/learning_observer/cache.py index ab11259cd..280cd39b5 100644 --- a/learning_observer/learning_observer/cache.py +++ b/learning_observer/learning_observer/cache.py @@ -9,7 +9,7 @@ def create_key_from_args(func, *args, **kwargs): - key_dict = {'func': str(func), 'args': args, 'kwargs': kwargs} + key_dict = {'func': str(func.__name__), 'args': args, 'kwargs': kwargs} key_str = json.dumps(key_dict, sort_keys=True) return key_str diff --git a/learning_observer/learning_observer/communication_protocol/executor.py b/learning_observer/learning_observer/communication_protocol/executor.py index c161ecf73..4ce83511a 100644 --- a/learning_observer/learning_observer/communication_protocol/executor.py +++ b/learning_observer/learning_observer/communication_protocol/executor.py @@ -414,31 +414,44 @@ async def handle_select(keys, fields=learning_observer.communication_protocol.qu if fields is None or fields == learning_observer.communication_protocol.query.SelectFields.Missing: fields_to_keep = {} + # Collect all keys from the async generator + keys_list = [] async for k in ensure_async_generator(keys): if isinstance(k, dict) and 'key' in k: - # output from query added to response later - query_response_element = { - 'provenance': { - 'key': k['key'], - 'provenance': k['provenance'] - } - } + keys_list.append(k) else: raise DAGExecutionException( f'Key not formatted correctly for select: {k}', inspect.currentframe().f_code.co_name, {'keys': keys, 'fields': fields} ) - resulting_value = await learning_observer.kvs.KVS()[k['key']] + + # Batch fetch all values from KVS + kvs = learning_observer.kvs.KVS() + kvs_keys = [k['key'] for k in keys_list] + resulting_values = await kvs.multiget(kvs_keys) + + # Process each key and its corresponding value + for k, resulting_value in zip(keys_list, resulting_values): + query_response_element = { + 'provenance': { + 'key': k['key'], + 'provenance': k['provenance'] + } + } + + # Use default value if KVS returned None if resulting_value is None: - # the reducer has not run yet, so we return the default value from the module - resulting_value = k['default'] + resulting_value = k.get('default', None) - # keep all current fields except for provenance (already prepared) + # Determine fields to keep based on the current resulting_value if fields is All if fields == learning_observer.communication_protocol.query.SelectFields.All: - fields_to_keep = {k: k for k in resulting_value.keys() if k != 'provenance'} + current_fields_to_keep = {key: key for key in resulting_value.keys() if key != 'provenance'} + else: + current_fields_to_keep = fields_to_keep - for f in fields_to_keep: + # Populate the query response element with the specified fields + for f in current_fields_to_keep: try: value = get_nested_dict_value(resulting_value, f) except KeyError as e: @@ -447,8 +460,8 @@ async def handle_select(keys, fields=learning_observer.communication_protocol.qu inspect.currentframe().f_code.co_name, {'target': resulting_value, 'key': f, 'exception': e} ).to_dict() - # add necessary outputs to query response - query_response_element[fields_to_keep[f]] = value + query_response_element[current_fields_to_keep[f]] = value + yield query_response_element diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8c83b7746..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -631,7 +631,7 @@ async def _execute_dag(dag_query, target, params): # Create DAG generator and drive generator = await _create_dag_generator(dag_query, target, request) - await _drive_generator(generator, dag_query['kwargs']) + await _drive_generator(generator, dag_query['kwargs'], target=target) # Handle rescheduling the execution of the DAG for fresh data # TODO add some way to specific specific endpoint delays @@ -642,15 +642,15 @@ async def _execute_dag(dag_query, target, params): await asyncio.sleep(dag_delay) await _execute_dag(dag_query, target, params) - async def _drive_generator(generator, dag_kwargs): + async def _drive_generator(generator, dag_kwargs, target=None): '''For each item in the generator, this method creates an update to send to the client. ''' async for item in generator: scope = _find_student_or_resource(item) update_path = ".".join(scope) - if 'option_hash' in dag_kwargs: - item['option_hash'] = dag_kwargs['option_hash'] + if 'option_hash' in dag_kwargs and target is not None: + item[f'option_hash_{target}'] = dag_kwargs['option_hash'] await _send_update({'op': 'update', 'path': update_path, 'value': item}) send_batches_task = asyncio.create_task(_batch_send()) diff --git a/learning_observer/learning_observer/downloads.py b/learning_observer/learning_observer/downloads.py index d57afc2d8..9e76b1ef9 100644 --- a/learning_observer/learning_observer/downloads.py +++ b/learning_observer/learning_observer/downloads.py @@ -88,9 +88,12 @@ "5.3.1": "d099dac0135309466dc6208aaa973584843a3efbb40b2c96eb7c179f5f20f" "80def35bbc1a7a0b08c9d5bdbed6b8e780ba7d013d18e4019e04fd82a19c076a1f8", "5.3.3": "54b69b378be9029cb841bce9f33e111148231ce38ae389601c10ee1fec93b" - "bfb84839e84911e9e32e9e026a182e7225fd8531dc8344ba94ef4b467852e7162d5" + "bfb84839e84911e9e32e9e026a182e7225fd8531dc8344ba94ef4b467852e7162d5", + "5.3.5": "3c9aa2c118ba4cbb2f54b2ca87528c453503ab5545983b6f5d10c6f04abd9" + "d4feb003c80c59a092857808e439642ab45e38369980288e7afb5a11e0e7946270e" }, "tested_versions": [ + 'https://cdn.jsdelivr.net/npm/bootswatch@5.3.5/dist/minty/bootstrap.min.css', 'https://cdn.jsdelivr.net/npm/bootswatch@5.3.3/dist/minty/bootstrap.min.css', "https://cdn.jsdelivr.net/npm/bootswatch@5.3.1/dist/minty/bootstrap.min.css", 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css', @@ -102,9 +105,12 @@ "6.1.1": "535a5f3e40bc8ddf475b56c1a39a5406052b524413dea331c4e683ca99e39" "6dbbc11fdce1f8355730a73c52ac6a1062de1938406c6af8e4361fd346106acb6b0", "6.3.0": "1496214e7421773324f4b332127ea77bec822fc6739292ebb19c6abcc22a5" - "6248e0634b4e0ca0c2fcac14dc10b8d01fa17febaa35f46731201d1ffd0ab482dd7" + "6248e0634b4e0ca0c2fcac14dc10b8d01fa17febaa35f46731201d1ffd0ab482dd7", + "6.7.2": "1bd8a997cca7c7abb44f3335a338feb34e69694c3cf4f2cae11ef12ed73f4" + "f120dc15e680835f88dd71df199fb6596bea05cb569b0fb0822e8fd3ec58c6e0833" }, "tested_versions": [ + "https://use.fontawesome.com/releases/v6.7.2/css/all.css", "https://use.fontawesome.com/releases/v6.3.0/css/all.css", "https://use.fontawesome.com/releases/v6.1.1/css/all.css" ] @@ -115,7 +121,9 @@ "6.1.1": "6d3fe769cc40a5790ea2e09fb775f1bd3b130d2fdae1dd552f69559e7ca4c" "a047862f795da0024737e59e3bcc7446f6eec1bab173758aef0b97ba89d722ffbde", "6.3.0": "d50c68cd4b3312f50deb66ac8ab5c37b2d4161f4e00ea077" - "326ae76769dac650dd19e65dee8d698ba2f86a69537f38cf4010ff45227211cee8b382d9b567257a" + "326ae76769dac650dd19e65dee8d698ba2f86a69537f38cf4010ff45227211cee8b382d9b567257a", + "6.7.2": "140ad609f15616dff39a7ed2efa080283bb28e13e6fe00987a39774887aa2" + "a8279f48c36816753e7522474580ee49b937e9d549674b7382f73548f159a206036" } } FONTAWESOME_TTF = { @@ -124,7 +132,9 @@ "6.1.1": "0fdd341671021d04304186c197001cf2e888d3028baaf9a5dec0f0e496959" "666e8a2e34aae8e79904f8e9b4c0ccae40249897cce5f5ae58d12cc1b3985e588d6", "6.3.0": "5a2c2b010a2496e4ed832ede8620f3bbfa9374778f3d63e4" - "5a4aab041e174dafd9fffd3229b8b36f259cf2ef46ae7bf5cb041e280f2939884652788fc1e8ce58" + "5a4aab041e174dafd9fffd3229b8b36f259cf2ef46ae7bf5cb041e280f2939884652788fc1e8ce58", + "6.7.2": "8a0a8fc8fcf0b676588bfe28f8b1d154a16af951d31f3a527a9661189c4c2" + "317b2d5b3b95a3e7c4a77377988fb6852e6d5dae6df48ad07957a62ae22fd2ac0bb" } } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 469761b7f..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -191,6 +191,14 @@ async def remove(self, key): await self.connect() return await learning_observer.redis_connection.delete(key) + async def multiget(self, keys): + ''' + Fetch multiple items from the KVS via `mget` + ''' + await self.connect() + items = await learning_observer.redis_connection.mget(keys) + return [json.loads(item) if item is not None else None for item in items] + class EphemeralRedisKVS(_RedisKVS): ''' diff --git a/learning_observer/learning_observer/redis_connection.py b/learning_observer/learning_observer/redis_connection.py index d62534f62..7b6d1494d 100644 --- a/learning_observer/learning_observer/redis_connection.py +++ b/learning_observer/learning_observer/redis_connection.py @@ -73,11 +73,18 @@ async def keys(): async def get(key): ''' - Get a key. We should eventually do multi-gets. Returns a future. + Get a key. Returns a future. ''' return await (await connection()).get(key) +async def mget(keys): + ''' + Get mutliple keys. Returns a future. + ''' + return await (await connection()).mget(keys) + + async def set(key, value, expiry=None): ''' Set a key. We should eventually do multi-sets. Returns a future. diff --git a/modules/lo_dash_react_components/src/lib/components/LONameTag.scss b/modules/lo_dash_react_components/src/lib/components/LONameTag.scss index 611345779..4670217be 100644 --- a/modules/lo_dash_react_components/src/lib/components/LONameTag.scss +++ b/modules/lo_dash_react_components/src/lib/components/LONameTag.scss @@ -6,7 +6,6 @@ span.name-tag-photo { font-family: monospace; text-align: center; - width: 42px; background-color: white; padding: 0.25rem; border-radius: 50%; diff --git a/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js b/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js index 1783aacdc..5ab1a7ee2 100644 --- a/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js +++ b/modules/lo_dash_react_components/src/lib/components/WOSettings.react.js @@ -36,7 +36,9 @@ export default class WOSettings extends Component { constructor (props) { super(props); this.state = { - collapsed: {} // Tracks which rows are collapsed + collapsed: {}, + showHighlight: props.options.some(option => option.types && option.types.includes('highlight')), + showMetric: props.options.some(option => option.types && option.types.includes('metric')) }; this.handleRowEvent = this.handleRowEvent.bind(this); this.renderRow = this.renderRow.bind(this); @@ -74,7 +76,7 @@ export default class WOSettings extends Component { } renderRow (row, allRows) { - const { collapsed } = this.state; + const { collapsed, showHighlight, showMetric } = this.state; const { value } = this.props; const hasChildren = allRows.some(option => option.parent === row.id); const isCollapsed = collapsed[row.id] || false; @@ -85,6 +87,7 @@ export default class WOSettings extends Component { type="checkbox" checked={value[row.id]?.highlight.value || false} onChange={(e) => this.handleRowEvent(e, row.id, 'highlight')} + className='me-1' /> {value[row.id]?.highlight.value ? ( )} - {highlightCell} - {metricCell} + {showHighlight && {highlightCell}} + {showMetric && {metricCell}} {/* Render children rows if not collapsed */} {!isCollapsed && @@ -135,6 +138,7 @@ export default class WOSettings extends Component { render () { const { id, className, options } = this.props; + const { showHighlight, showMetric } = this.state; const rows = sortOptionsIntoTree(options); return ( @@ -146,8 +150,8 @@ export default class WOSettings extends Component { Name - Highlight - Metric + {showHighlight && Highlight} + {showMetric && Metric} diff --git a/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.react.js b/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.react.js index 611b1600b..1bfecbf43 100644 --- a/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.react.js +++ b/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.react.js @@ -1,77 +1,41 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import Button from 'react-bootstrap/Button'; +import ButtonGroup from 'react-bootstrap/ButtonGroup'; import Card from 'react-bootstrap/Card'; -import Form from 'react-bootstrap/Form'; import LONameTag from './LONameTag.react'; -function createGoogleDocumentURL (docId) { - return `https://docs.google.com/document/d/${docId}`; -} - /** * WOStudentTextTile */ export default class WOStudentTextTile extends Component { - constructor (props) { - super(props); - this.handleDocumentSelectChange = this.handleDocumentSelectChange.bind(this); - } - - handleDocumentSelectChange (event) { - this.props.setProps({ selectedDocument: event.target.value }); - } - render () { - const { id, className, style, showHeader, studentInfo, selectedDocument, currentOptionHash, childComponent } = this.props; - // HACK we need to pass the appropriate student information into the child component - childComponent.props._dashprivate_layout.props = { ...studentInfo.documents[selectedDocument] }; - - const documentIsSelected = selectedDocument && studentInfo.documents[selectedDocument]; - const isLoading = documentIsSelected && currentOptionHash !== studentInfo.documents[selectedDocument].optionHash; + const { id, className, style, showName, profile, currentStudentHash, currentOptionHash, childComponent, additionalButtons } = this.props; + const isLoading = currentOptionHash !== currentStudentHash; let bodyClassName = isLoading ? 'loading' : ''; bodyClassName = `${bodyClassName} overflow-auto position-relative`; - const loadedItem = documentIsSelected - ? <>{childComponent} - :
Document information not found.
; - - // TODO the chunk of commented code allows for linking directly to the selected document - // and allows the user to select which document they wish to see at a given moment. - // Neither of these features are currently available due to limitations with the communication - // protocol. For now they are being commented out so users are not inclined to use them. return ( - + - {/* - - - - - {studentInfo.availableDocuments.map(doc => ( - - ))} - */} + + {isLoading && ( + + )} + {additionalButtons && additionalButtons} + - {isLoading && ( -
-
- Loading... -
- )} - {loadedItem} + {childComponent} ); @@ -80,13 +44,9 @@ export default class WOStudentTextTile extends Component { WOStudentTextTile.defaultProps = { className: '', - showHeader: true, + showName: true, style: {}, - studentInfo: { - profile: {}, - availableDocuments: [], - documents: {} - } + profile: {} }; WOStudentTextTile.propTypes = { @@ -110,18 +70,19 @@ WOStudentTextTile.propTypes = { * Determine whether the header with the student * name should be visible or not */ - showHeader: PropTypes.bool, + showName: PropTypes.bool, /** - * Which document is currently selected for this student + * Hash of the current options, used to determine if we + * should be in a loading state or not. */ - selectedDocument: PropTypes.string, + currentOptionHash: PropTypes.string, /** - * Hash of the current options, used to determine if we + * Hash of the current student, used to determine if we * should be in a loading state or not. */ - currentOptionHash: PropTypes.string, + currentStudentHash: PropTypes.string, /** * Component to use for within the card body @@ -129,23 +90,14 @@ WOStudentTextTile.propTypes = { childComponent: PropTypes.node, /** - * The breakpoints of our text + * Buttons to add to the button group + */ + additionalButtons: PropTypes.node, + + /** + * The profile of the student */ - studentInfo: PropTypes.exact({ - profile: PropTypes.object, - availableDocuments: PropTypes.arrayOf(PropTypes.exact({ - id: PropTypes.string, - title: PropTypes.string - })), - documents: PropTypes.object - // objectOf( - // PropTypes.shape({ - // text: PropTypes.string, - // breakpoints: PropTypes.arrayOf(PropTypes.any), - // optionHash: PropTypes.string - // }) - // ) - }), + profile: PropTypes.object, /** * Dash-assigned callback that should be called to report property changes diff --git a/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.testdata.js b/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.testdata.js index 0d297f065..c12774038 100644 --- a/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.testdata.js +++ b/modules/lo_dash_react_components/src/lib/components/WOStudentTextTile.testdata.js @@ -1,51 +1,16 @@ const testData = { id: 'example', - showHeader: true, + showName: true, currentOptionHash: '123', - studentInfo: { - availableDocuments: [ - { id: '1_2V-Npp1L0G3cw4lcH_ENSo_y_OV1BP3s8NdnwaFbVw', title: 'Document A' }, - { id: 'docB', title: 'Document B' }, - { id: 'docC', title: 'Document C' } - ], - profile: { - email_address: 'example@example.com', - name: { - family_name: 'Doe', - full_name: 'John Doe', - given_name: 'John' - }, - photo_url: '//lh3.googleusercontent.com/a/default-user' + currentStudentHash: '123', + profile: { + email_address: 'example@example.com', + name: { + family_name: 'Doe', + full_name: 'John Doe', + given_name: 'John' }, - documents: { - '1_2V-Npp1L0G3cw4lcH_ENSo_y_OV1BP3s8NdnwaFbVw': { - optionHash: '123', - text: "This summer was AMAZING!!! First, I went to the beach with my family for two whole weeks! We stayed in this super cool beach house that had its own private pool and hot tub. My siblings and I spent hours playing in the waves and building sandcastles on the beach. We even went on a snorkeling trip and saw some really cool fish!\n\nWhen we weren't at the beach, I hung out with my friends and we had a blast! We went to the trampoline park and played laser tag. I also started reading this really good book called \"The Giver\" and it was sooo good that I couldn't put it down.\n\nMy parents took me and my siblings on a road trip to visit our grandparents in another state. It was a pretty long drive, but we made some great memories along the way. We stopped at a few theme parks and went on some really cool rides. My favorite one was this roller coaster that had loops and corkscrews!\n\nAt home, I started working on my own little garden project. I planted some flowers and herbs, and even tried to grow my own tomatoes (which didn't quite work out as planned...). It was pretty cool seeing everything grow and flourish.\n\nOverall, this summer was definitely the best one yet!", - breakpoints: [ - { - id: 'split0', - tooltip: 'This is the first tooltip', - start: 220, - offset: 5, - style: { textDecoration: 'underline' } - }, - { - id: 'split1', - tooltip: 'This is a tooltip', - start: 240, - offset: 25, - style: { textDecoration: 'underline' } - }, - { - id: 'split2', - tooltip: 'This is another tooltip', - start: 310, - offset: 15, - style: { backgroundColor: 'green' } - } - ] - } - } + photo_url: '//lh3.googleusercontent.com/a/default-user' } }; diff --git a/modules/lo_gpt/lo_gpt/gpt.py b/modules/lo_gpt/lo_gpt/gpt.py index 69ee8acf1..b3eac5085 100644 --- a/modules/lo_gpt/lo_gpt/gpt.py +++ b/modules/lo_gpt/lo_gpt/gpt.py @@ -12,17 +12,19 @@ APIs so the code can be abstracted to the parent class. ''' import aiohttp +import asyncio import json import loremipsum import os +import random -import learning_observer.communication_protocol.integration from learning_observer.log_event import debug_log import learning_observer.prestartup import learning_observer.settings gpt_responder = None SYSTEM_PROMPT_DEFAULT = 'You are a helper agent, please help fulfill user requests.' +LLM_SEMAPHOR = {} class GPTAPI: @@ -111,6 +113,10 @@ def __init__(self, **kwargs): 'ollama run \n```') self.ollama_host = 'http://localhost:11434' + global LLM_SEMAPHOR + if 'ollama' not in LLM_SEMAPHOR: + LLM_SEMAPHOR['ollama'] = asyncio.Semaphore(os.getenv('OLLAMA_NUM_PARALLEL', 1)) + async def chat_completion(self, prompt, system_prompt): '''Ollama only returns a single item compared to GPT returning a list ''' @@ -120,15 +126,16 @@ async def chat_completion(self, prompt, system_prompt): {'role': 'user', 'content': prompt} ] content = {'model': self.model, 'messages': messages, 'stream': False} - async with aiohttp.ClientSession() as session: - async with session.post(url, json=content) as resp: - json_resp = await resp.json(content_type=None) - if resp.status == 200: - return json_resp['message']['content'] - error = 'Error occured while making Ollama request' - if 'error' in json_resp: - error += f"\n{json_resp['error']['message']}" - raise GPTRequestErorr(error) + async with LLM_SEMAPHOR['ollama']: + async with aiohttp.ClientSession() as session: + async with session.post(url, json=content) as resp: + json_resp = await resp.json(content_type=None) + if resp.status == 200: + return json_resp['message']['content'] + error = 'Error occured while making Ollama request' + if 'error' in json_resp: + error += f"\n{json_resp['error']['message']}" + raise GPTRequestErorr(error) class StubGPT(GPTAPI): @@ -137,8 +144,14 @@ class StubGPT(GPTAPI): def __init__(self, **kwargs): super().__init__() + global LLM_SEMAPHOR + if 'stub' not in LLM_SEMAPHOR: + LLM_SEMAPHOR['stub'] = asyncio.Semaphore(2) + async def chat_completion(self, prompt, system_prompt): - return "\n".join(loremipsum.get_paragraphs(1)) + async with LLM_SEMAPHOR['stub']: + await asyncio.sleep(random.randint(5, 15)) + return "\n".join(loremipsum.get_paragraphs(1)) GPT_RESPONDERS = { diff --git a/modules/wo_bulk_essay_analysis/VERSION b/modules/wo_bulk_essay_analysis/VERSION index 80aee927e..4dd337e23 100644 --- a/modules/wo_bulk_essay_analysis/VERSION +++ b/modules/wo_bulk_essay_analysis/VERSION @@ -1 +1 @@ -0.1.0+2025.04.03T14.43.39.953Z.c336d5da.master +0.1.0+2025.04.17T11.52.09.536Z.37e99b72.berickson.202504.process.metrics diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js index 55cdbae0d..a055d73cb 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/scripts.js @@ -8,7 +8,7 @@ if (!window.dash_clientside) { pdfjsLib.GlobalWorkerOptions.workerSrc = '/static/3rd_party/pdf.worker.min.js'; -const createStudentCard = async function (s, prompt, width, height, showHeader) { +const createStudentCard = async function (s, prompt, width, height, showName, selectedMetrics) { const selectedDocument = s.doc_id || Object.keys(s.documents || {})[0] || ''; const student = s.documents?.[selectedDocument] ?? {}; const promptHash = await hashObject({ prompt }); @@ -16,8 +16,17 @@ const createStudentCard = async function (s, prompt, width, height, showHeader) const studentText = { namespace: 'lo_dash_react_components', type: 'WOAnnotatedText', - props: { text: student.text, breakpoints: [], className: 'border-end' } + props: { text: student.text, breakpoints: [] } }; + const studentTileChild = createDashComponent( + DASH_HTML_COMPONENTS, 'Div', + { + children: [ + createProcessTags({ ...student }, selectedMetrics), + studentText + ] + } + ); const errorMessage = { namespace: 'dash_html_components', type: 'Div', @@ -50,19 +59,29 @@ const createStudentCard = async function (s, prompt, width, height, showHeader) className: 'text-center' } }; - const feedback = promptHash === student.option_hash ? feedbackMessage : feedbackLoading; + const feedback = promptHash === student.option_hash_gpt_bulk ? feedbackMessage : feedbackLoading; const feedbackOrError = 'error' in student ? errorMessage : feedback; - const userId = student?.user_id || '0'; + const userId = student?.user_id; + if (!userId) { return {}; } const studentTile = createDashComponent( LO_DASH_REACT_COMPONENTS, 'WOStudentTextTile', { - showHeader, - studentInfo: formatStudentData(s, []), + showName, + profile: student?.profile || {}, selectedDocument, - childComponent: studentText, + childComponent: studentTileChild, id: { type: 'WOAIAssistStudentTileText', index: userId }, currentOptionHash: promptHash, - style: { height: `${height}px` } + currentStudentHash: student.option_hash_gpt_bulk, + style: { height: `${height}px` }, + additionalButtons: createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Button', + { + id: { type: 'WOAIAssistStudentTileExpand', index: userId }, + children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-expand' }), + color: 'transparent' + } + ) } ); const tileWrapper = createDashComponent( @@ -75,15 +94,6 @@ const createStudentCard = async function (s, prompt, width, height, showHeader) DASH_BOOTSTRAP_COMPONENTS, 'Card', { children: feedbackOrError, body: true } ), - createDashComponent( - DASH_BOOTSTRAP_COMPONENTS, 'Button', - { - id: { type: 'WOAIAssistStudentTileExpand', index: userId }, - children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-expand' }), - class_name: 'position-absolute top-0 end-0 m-1', - color: 'transparent' - } - ) ], id: { type: 'WOAIAssistStudentTile', index: userId }, style: { width: `${(100 - width) / width}%` } @@ -98,11 +108,11 @@ const createStudentCard = async function (s, prompt, width, height, showHeader) * @param {*} promptHash current hash of prompts * @returns true if student's selected document's hash is the same as promptHash */ -const checkForResponse = function (s, promptHash) { +const checkForResponse = function (s, promptHash, options) { if (!('documents' in s)) { return false; } const selectedDocument = s.doc_id || Object.keys(s.documents || {})[0] || ''; const student = s.documents[selectedDocument]; - return promptHash === student.option_hash; + return options.every(option => promptHash === student[`option_hash_${option}`]); }; const charactersAfterChar = function (str, char) { @@ -160,6 +170,8 @@ const fileTextExtractors = { docx: extractDOCX }; +const AIAssistantLoadingQueries = ['gpt_bulk', 'time_on_task', 'activity']; + window.dash_clientside.bulk_essay_feedback = { /** * Sends data to server via websocket @@ -179,7 +191,7 @@ window.dash_clientside.bulk_essay_feedback = { decoded.doc_source_kwargs = docKwargs.kwargs; // TODO what is a reasonable time to wait inbetween subsequent calls for // the same arguments - decoded.rerun_dag_delay = 30; + decoded.rerun_dag_delay = 120; const trig = window.dash_clientside.callback_context.triggered[0]; if (trig.prop_id.includes('bulk-essay-analysis-submit-btn')) { @@ -194,7 +206,7 @@ window.dash_clientside.bulk_essay_feedback = { const message = { wo: { execution_dag: 'writing_observer', - target_exports: ['gpt_bulk', 'document_list', 'document_sources'], + target_exports: ['gpt_bulk', 'document_list', 'document_sources', 'time_on_task', 'activity'], kwargs: decoded } }; @@ -203,11 +215,23 @@ window.dash_clientside.bulk_essay_feedback = { return window.dash_clientside.no_update; }, - toggleAdvanced: function (clicks, isOpen) { + toggleAdvanced: function (clicks, shown) { if (!clicks) { return window.dash_clientside.no_update; } - return !isOpen; + const optionPrefix = 'bulk-essay-analysis-advanced-collapse'; + if (shown.includes(optionPrefix)) { + shown = shown.filter(item => item !== optionPrefix); + } else { + shown = shown.concat(optionPrefix); + } + return shown; + }, + + closeAdvanced: function (clicks, shown) { + if (!clicks) { return window.dash_clientside.no_update; } + shown = shown.filter(item => item !== 'bulk-essay-analysis-advanced-collapse'); + return shown; }, /** @@ -241,15 +265,16 @@ window.dash_clientside.bulk_essay_feedback = { /** * update student cards based on new data in storage */ - updateStudentGridOutput: async function (wsStorageData, history, width, height, showHeader) { + updateStudentGridOutput: async function (wsStorageData, history, width, height, showName, value, options) { if (!wsStorageData) { return 'No students'; } const currPrompt = history.length > 0 ? history[history.length - 1] : ''; + const selectedMetrics = fetchSelectedItemsFromOptions(value, options, 'metric'); let output = []; for (const student in wsStorageData.students) { - output = output.concat(await createStudentCard(wsStorageData.students[student], currPrompt, width, height, showHeader)); + output = output.concat(await createStudentCard(wsStorageData.students[student], currPrompt, width, height, showName, selectedMetrics)); } return output; }, @@ -468,7 +493,7 @@ window.dash_clientside.bulk_essay_feedback = { } const currentPrompt = history.length > 0 ? history[history.length - 1] : ''; const promptHash = await hashObject({ prompt: currentPrompt }); - const returnedResponses = Object.values(wsStorageData.students).filter(student => checkForResponse(student, promptHash)).length; + const returnedResponses = Object.values(wsStorageData.students).filter(student => checkForResponse(student, promptHash, AIAssistantLoadingQueries)).length; const totalStudents = Object.keys(wsStorageData.students).length; if (totalStudents === returnedResponses) { return noLoading; } const loadingProgress = returnedResponses / totalStudents + 0.1; @@ -490,8 +515,12 @@ window.dash_clientside.bulk_essay_feedback = { let id = null; if (triggeredItem?.type === 'WOAIAssistStudentTileExpand') { id = triggeredItem?.index; - if (clicks[ids.findIndex(item => item.index === id)]) { + const index = ids.findIndex(item => item.index === id); + if (clicks[index]) { shownPanels = shownPanels.concat('bulk-essay-analysis-expanded-student-panel'); + } else { + // No clicks occurred so we should keep the ID as it was + id = window.dash_clientside.no_update; } } else { return window.dash_clientside.no_update; @@ -499,7 +528,7 @@ window.dash_clientside.bulk_essay_feedback = { return [id, shownPanels]; }, - expandSelectedStudent: async function (selectedStudent, wsData, showHeader, history) { + expandSelectedStudent: async function (selectedStudent, wsData, showName, history, value, options) { if (!selectedStudent | !(selectedStudent in (wsData.students || {}))) { return window.dash_clientside.no_update; } @@ -509,12 +538,23 @@ window.dash_clientside.bulk_essay_feedback = { const document = Object.keys(s.documents)[0]; const student = s.documents[document]; const promptHash = await hashObject({ prompt }); + const selectedMetrics = fetchSelectedItemsFromOptions(value, options, 'metric'); + // TODO some of this can easily be abstracted const studentText = { namespace: 'lo_dash_react_components', type: 'WOAnnotatedText', - props: { text: student.text, breakpoints: [], className: 'border-end' } + props: { text: student.text, breakpoints: [] } }; + const studentTileChild = createDashComponent( + DASH_HTML_COMPONENTS, 'Div', + { + children: [ + createProcessTags({ ...student }, selectedMetrics), + studentText + ] + } + ); const errorMessage = { namespace: 'dash_html_components', type: 'Div', @@ -527,7 +567,7 @@ window.dash_clientside.bulk_essay_feedback = { type: 'Markdown', props: { children: student?.feedback ? student.feedback : '', - className: student?.feedback ? 'p-1 overflow-auto' : '', + className: student?.feedback ? 'p-1' : '', style: { whiteSpace: 'pre-line' } } }; @@ -547,17 +587,18 @@ window.dash_clientside.bulk_essay_feedback = { className: 'text-center' } }; - const feedback = promptHash === student.option_hash ? feedbackMessage : feedbackLoading; + const feedback = promptHash === student.option_hash_gpt_bulk ? feedbackMessage : feedbackLoading; const feedbackOrError = 'error' in student ? errorMessage : feedback; const studentTile = createDashComponent( LO_DASH_REACT_COMPONENTS, 'WOStudentTextTile', { - showHeader, - studentInfo: formatStudentData(s, []), + showName, + profile: student?.profile || {}, selectedDocument, - childComponent: studentText, + childComponent: studentTileChild, id: { type: 'WOAIAssistStudentTileText', index: student.user_id }, - currentOptionHash: promptHash + currentOptionHash: promptHash, + currentStudentHash: student.option_hash_gpt_bulk } ); const individualWrapper = createDashComponent( @@ -568,7 +609,7 @@ window.dash_clientside.bulk_essay_feedback = { studentTile, createDashComponent( DASH_BOOTSTRAP_COMPONENTS, 'Card', - { children: feedbackOrError, body: true, className: 'individual-student-feedback' } + { children: feedbackOrError, body: true } ) ] } diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css index 9e9d73472..b134da7e3 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/assets/styles.css @@ -1,10 +1,3 @@ -.individual-student-feedback { - position: -webkit-sticky; - position: sticky; - bottom: 0; - min-height: 250px; -} - .prompt-variable-tag button:last-child { border-top-left-radius: 0; border-bottom-left-radius: 0; diff --git a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py index 5df3c0f7e..59ae6ae3c 100644 --- a/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py +++ b/modules/wo_bulk_essay_analysis/wo_bulk_essay_analysis/dashboard/layout.py @@ -4,12 +4,13 @@ ''' import dash_bootstrap_components as dbc from dash_renderjson import DashRenderjson -import datetime import lo_dash_react_components as lodrc import random from dash import html, dcc, clientside_callback, ClientsideFunction, Output, Input, State, ALL +import wo_classroom_text_highlighter.options + # TODO pull this flag from settings DEBUG_FLAG = True @@ -29,9 +30,11 @@ _advanced_doc_src = f'{_advanced}-document-source' _advanced_toggle = f'{_advanced}-toggle' _advanced_collapse = f'{_advanced}-collapse' +_advanced_close = f'{_advanced}-close' _advanced_width = f'{_advanced}-width' _advanced_height = f'{_advanced}-height' _advanced_hide_header = f'{_advanced}-hide-header' +_advanced_text_information = f'{_advanced}-text-information' _system_input = f'{prefix}-system-prompt-input' _system_input_tooltip = f'{_system_input}-tooltip' @@ -138,22 +141,36 @@ def layout(): Generic layout function to create dashboard ''' # advanced menu for system prompt - advanced = [ + advanced = html.Div([ html.Div([ - lodrc.LODocumentSourceSelectorAIO(aio_id=_advanced_doc_src), - dbc.Card([ - dbc.CardHeader('View Options'), - dbc.CardBody([ - dbc.Label('Students per row'), - dbc.Input(type='number', min=1, max=10, value=3, step=1, id=_advanced_width), - dbc.Label('Height of student tile'), - dcc.Slider(min=100, max=800, marks=None, value=350, id=_advanced_height), - dbc.Label('Student name headers'), - dbc.Switch(value=True, id=_advanced_hide_header, label='Show/Hide'), - ]) - ]), + html.H3('Settings', className='d-inline-block'), + dbc.Button( + html.I(className='fas fa-close'), + className='float-end', id=_advanced_close, + color='transparent'), + ]), + lodrc.LODocumentSourceSelectorAIO(aio_id=_advanced_doc_src), + dbc.Card([ + dbc.CardHeader('View Options'), + dbc.CardBody([ + dbc.Label('Students per row'), + dbc.Input(type='number', min=1, max=10, value=2, step=1, id=_advanced_width), + dbc.Label('Height of student tile'), + dcc.Slider(min=100, max=800, marks=None, value=350, id=_advanced_height), + dbc.Label('Student profile'), + dbc.Switch(value=True, id=_advanced_hide_header, label='Show/Hide'), + ]) + ]), + dbc.Card([ + dbc.CardHeader('Information Options'), + dbc.CardBody(lodrc.WOSettings( + id=_advanced_text_information, + options=wo_classroom_text_highlighter.options.PROCESS_OPTIONS, + value=wo_classroom_text_highlighter.options.DEFAULT_VALUE, + className='table table-striped align-middle' + )) ]) - ] + ]) # history panel history_favorite_panel = dbc.Card([ @@ -216,7 +233,6 @@ def layout(): dbc.Button([html.I(className='fas fa-cog me-1'), 'Advanced'], id=_advanced_toggle), lodrc.ProfileSidebarAIO(class_name='rounded-0 rounded-end', color='secondary'), ], class_name='mb-1'), - dbc.Collapse(advanced, id=_advanced_collapse, class_name='mb-1'), lodrc.LOPanelLayout( input_panel, panels=[ @@ -231,9 +247,10 @@ def layout(): lodrc.LOPanelLayout( html.Div(id=grid, className='d-flex justify-content-between flex-wrap'), panels=[ + {'children': advanced, 'width': '30%', 'id': _advanced_collapse, 'side': 'left' }, {'children': expanded_student_component, 'width': '30%', 'id': _expanded_student_panel, - 'side': 'right', 'className': 'vh-100 overflow-auto'} + 'side': 'right'} ], id=_student_data_wrapper, shown=[] ), @@ -244,9 +261,18 @@ def layout(): # Toggle if the advanced menu collapse is open or not clientside_callback( ClientsideFunction(namespace=_namespace, function_name='toggleAdvanced'), - Output(_advanced_collapse, 'is_open'), + Output(_student_data_wrapper, 'shown', allow_duplicate=True), Input(_advanced_toggle, 'n_clicks'), - State(_advanced_collapse, 'is_open') + State(_student_data_wrapper, 'shown'), + prevent_initial_call=True +) + +clientside_callback( + ClientsideFunction(namespace=_namespace, function_name='closeAdvanced'), + Output(_student_data_wrapper, 'shown', allow_duplicate=True), + Input(_advanced_close, 'n_clicks'), + State(_student_data_wrapper, 'shown'), + prevent_initial_call=True ) # send request on websocket @@ -329,7 +355,9 @@ def layout(): Input(history_store, 'data'), Input(_advanced_width, 'value'), Input(_advanced_height, 'value'), - Input(_advanced_hide_header, 'value') + Input(_advanced_hide_header, 'value'), + Input(_advanced_text_information, 'value'), + State(_advanced_text_information, 'options') ) # append tag in curly braces to input @@ -423,6 +451,8 @@ def layout(): Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), Input(_advanced_hide_header, 'value'), Input(history_store, 'data'), + Input(_advanced_text_information, 'value'), + State(_advanced_text_information, 'options') ) # Close expanded student diff --git a/modules/wo_classroom_text_highlighter/VERSION b/modules/wo_classroom_text_highlighter/VERSION index 21b05a126..daf8882e5 100644 --- a/modules/wo_classroom_text_highlighter/VERSION +++ b/modules/wo_classroom_text_highlighter/VERSION @@ -1 +1 @@ -0.1.0+2025.04.03T13.17.04.073Z.7e282384.master +0.1.0+2025.04.16T16.38.16.396Z.ab096d59.berickson.202504.process.metrics diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js index 6ae74e4da..7510b2d37 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/assets/scripts.js @@ -57,52 +57,63 @@ function simpleHash (str) { return hash.toString(16); } -// TODO some of this will move to the communication protocol, but for now -// it lives here -function formatStudentData (student, selectedHighlights) { - let profile = {}; - const documents = {}; - for (const document in student.documents || []) { - const breakpoints = selectedHighlights.reduce((acc, option) => { - const offsets = student.documents[document][option.id]?.offsets || []; - if (offsets) { - const modifiedOffsets = offsets.map(offset => { - return { - id: '', - tooltip: option.label, - start: offset[0], - offset: offset[1], - style: { backgroundColor: option.highlight.color } - }; - }); - acc = acc.concat(modifiedOffsets); - } - return acc; - }, []); - const text = student.documents[document].text; - const optionHash = student.documents[document].option_hash; - profile = student.documents[document].profile; - documents[document] = { text, optionHash, breakpoints }; - } - let availableDocuments = []; - if ('availableDocuments' in student) { - availableDocuments = Object.keys(student.availableDocuments).map(id => ({ - id, - title: student.availableDocuments[id].title || id, - last_access: student.availableDocuments[id].last_access || null - })); - } - return { - profile, - availableDocuments, - documents - }; +function formatStudentData (document, selectedHighlights) { + const breakpoints = selectedHighlights.reduce((acc, option) => { + const offsets = document[option.id]?.offsets || []; + if (offsets) { + const modifiedOffsets = offsets.map(offset => { + return { + id: '', + tooltip: option.label, + start: offset[0], + offset: offset[1], + style: { backgroundColor: option.highlight.color } + }; + }); + acc = acc.concat(modifiedOffsets); + } + return acc; + }, []); + const text = document.text; + return { text, breakpoints }; } function styleStudentTile (width, height) { return { width: `${(100 - width) / width}%`, height: `${height}px` }; } +function fetchSelectedItemsFromOptions (value, options, type) { + return options.reduce(function(filtered, option) { + if (value?.[option.id]?.[type]?.value) { + const selected = {...option, ...value[option.id]}; + filtered.push(selected); + } + return filtered; + }, []); +} + +function createProcessTags (document, metrics) { + const children = metrics.map(metric => { + switch (metric.id) { + case 'time_on_task': + return createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Badge', + { children: `${rendertime2(document[metric.id])} on task`, className: 'me-1' } + ); + case 'status': + const color = document[metric.id] === 'active' ? 'success' : 'warning'; + return createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Badge', + { children: document[metric.id], color } + ); + default: + break + } + }); + return createDashComponent(DASH_HTML_COMPONENTS, 'Div', { children, className: 'sticky-top' }) +} +const ClassroomTextHighlightLoadingQueries = ['docs_with_nlp_annotations', 'time_on_task', 'activity']; + window.dash_clientside.wo_classroom_text_highlighter = { /** * Send updated queries to the communication protocol. @@ -128,7 +139,7 @@ window.dash_clientside.wo_classroom_text_highlighter = { const outgoingMessage = { wo_classroom_text_highlighter_query: { execution_dag: 'writing_observer', - target_exports: ['docs_with_nlp_annotations', 'document_sources', 'document_list'], + target_exports: ['docs_with_nlp_annotations', 'document_sources', 'document_list', 'time_on_task', 'activity'], kwargs: decodedParams } }; @@ -184,63 +195,59 @@ window.dash_clientside.wo_classroom_text_highlighter = { * @param {*} wsStorageData information stored in the websocket store * @returns Dash object to be displayed on page */ - populateOutput: async function (wsStorageData, value, width, height, showHeader, options) { + populateOutput: async function (wsStorageData, value, width, height, showName, options) { // console.log('wsStorageData', wsStorageData); if (!wsStorageData?.students) { return 'No students'; } let output = []; - const selectedHighlights = options.reduce(function(filtered, option) { - if (value?.[option.id]?.highlight?.value) { - const selected = {...option, ...value[option.id]}; - filtered.push(selected); - } - return filtered; - }, []); - // TODO do something with the selected metrics/progress bars/etc. - // currently due to a HACK with how we pass data to the `childComponent` - // we are only able to have a single child and we expect it to be the - // `WOAnnotatedText` component. - const selectedMetrics = options.reduce(function(filtered, option) { - if (value?.[option.id]?.metric?.value) { - const selected = {...option, ...value[option.id]}; - filtered.push(selected); - } - return filtered; - }, []); + const selectedHighlights = fetchSelectedItemsFromOptions(value, options, 'highlight'); + const selectedMetrics = fetchSelectedItemsFromOptions(value, options, 'metric'); const optionHash = await hashObject(value); const students = wsStorageData.students; for (const student in students) { const selectedDocument = students[student].doc_id || Object.keys(students[student].documents || {})[0] || ''; + const studentTileChild = createDashComponent( + DASH_HTML_COMPONENTS, 'Div', + { + children: [ + createProcessTags({ ...students[student].documents[selectedDocument] }, selectedMetrics), + createDashComponent( + LO_DASH_REACT_COMPONENTS, 'WOAnnotatedText', + formatStudentData({ ...students[student].documents[selectedDocument] }, selectedHighlights) + ) + ] + } + ); const studentTile = createDashComponent( LO_DASH_REACT_COMPONENTS, 'WOStudentTextTile', { - showHeader, - studentInfo: formatStudentData(students[student], selectedHighlights), + showName, + profile: students[student].documents[selectedDocument]?.profile || {}, selectedDocument, - childComponent: createDashComponent(LO_DASH_REACT_COMPONENTS, 'WOAnnotatedText', {}), + childComponent: studentTileChild, id: { type: 'WOStudentTextTile', index: student }, + currentStudentHash: students[student].documents[selectedDocument]?.option_hash_docs_with_nlp_annotations, currentOptionHash: optionHash, - className: 'h-100' + className: 'h-100', + additionalButtons: createDashComponent( + DASH_BOOTSTRAP_COMPONENTS, 'Button', + { + id: { type: 'WOStudentTileExpand', index: student }, + children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-expand' }), + color: 'transparent' + } + ) } ); const tileWrapper = createDashComponent( DASH_HTML_COMPONENTS, 'Div', { - className: 'position-relative mb-2', + className: 'mb-2', children: [ studentTile, - createDashComponent( - DASH_BOOTSTRAP_COMPONENTS, 'Button', - { - id: { type: 'WOStudentTileExpand', index: student }, - children: createDashComponent(DASH_HTML_COMPONENTS, 'I', { className: 'fas fa-expand' }), - class_name: 'position-absolute top-0 end-0 m-1', - color: 'transparent' - } - ) ], id: { type: 'WOStudentTile', index: student }, style: styleStudentTile(width, height) @@ -284,7 +291,7 @@ window.dash_clientside.wo_classroom_text_highlighter = { } const students = wsStorageData.students; const promptHash = await hashObject(nlpValue); - const returnedResponses = Object.values(students).filter(student => checkForResponse(student, promptHash)).length; + const returnedResponses = Object.values(students).filter(student => checkForResponse(student, promptHash, ClassroomTextHighlightLoadingQueries)).length; const totalStudents = Object.keys(students).length; if (totalStudents === returnedResponses) { return noLoading; } const loadingProgress = returnedResponses / totalStudents + 0.1; @@ -318,15 +325,12 @@ window.dash_clientside.wo_classroom_text_highlighter = { }, updateLegend: function (value, options) { - const selectedHighlights = options.reduce(function(filtered, option) { - if (value?.[option.id]?.highlight?.value) { - const selected = {...option, ...value[option.id]}; - filtered.push(selected); - } - return filtered; - }, []); + const selectedHighlights = fetchSelectedItemsFromOptions(value, options, 'highlight'); + const selectedMetrics = fetchSelectedItemsFromOptions(value, options, 'metric'); + const total = selectedHighlights.length + selectedMetrics.length; + if (selectedHighlights.length === 0) { - return ['No options selected. Click on the `Highlight Options` to select them.', 0]; + return ['No options selected. Click on the `Options` to select them.', total]; } let output = selectedHighlights.map(highlight => { const color = highlight.highlight.color; @@ -345,6 +349,6 @@ window.dash_clientside.wo_classroom_text_highlighter = { return legendItem; }); output = output.concat('Note: words in the student text may have multiple highlights. Hover over a word for the full list of which options apply'); - return [output, selectedHighlights.length]; + return [output, total]; } }; diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py index 18712240e..6a86b6d6b 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/dash_dashboard.py @@ -55,16 +55,25 @@ dbc.CardHeader('View Options'), dbc.CardBody([ dbc.Label('Students per row'), - dbc.Input(type='number', min=1, max=10, value=3, step=1, id=_options_width), + dbc.Input(type='number', min=1, max=10, value=2, step=1, id=_options_width), dbc.Label('Height of student tile'), dcc.Slider(min=100, max=800, marks=None, value=500, id=_options_height), - dbc.Label('Student name headers'), + dbc.Label('Student profile'), dbc.Switch(value=True, id=_options_hide_header, label='Show/Hide'), ]) ]), - html.H4('Highlight Options'), - wo_classroom_text_highlighter.preset_component.create_layout(), - lodrc.WOSettings(id=_options_text_information, options=wo_classroom_text_highlighter.options.OPTIONS, className='table table-striped align-middle') + dbc.Card([ + dbc.CardHeader('Information Options'), + dbc.CardBody([ + wo_classroom_text_highlighter.preset_component.create_layout(), + lodrc.WOSettings( + id=_options_text_information, + options=wo_classroom_text_highlighter.options.OPTIONS, + value=wo_classroom_text_highlighter.options.DEFAULT_VALUE, + className='table table-striped align-middle' + ) + ]) + ]) ], className='p-2') # Legend @@ -103,7 +112,7 @@ dbc.InputGroupText(lodrc.LOConnectionAIO(aio_id=_websocket)), dbc.Button([ html.I(className='fas fa-cog me-1'), - 'Highlight Options (', + 'Options (', html.Span('0', id=_options_toggle_count), ')' ], id=_options_toggle), @@ -111,7 +120,6 @@ 'Legend', id=_legend_button, color='primary'), dbc.Popover( - 'No options selected. Click on the `Highlight Options` to select them.', id=_legend_children, target=_legend_button, trigger='click', body=True, placement='bottom'), lodrc.ProfileSidebarAIO(class_name='rounded-0 rounded-end', color='secondary'), @@ -135,7 +143,7 @@ def layout(): {'children': options_component, 'width': '30%', 'id': _options_prefix, 'side': 'left' }, {'children': expanded_student_component, 'width': '30%', 'id': _expanded_student_panel, - 'side': 'right', 'className': 'vh-100 overflow-auto'} + 'side': 'right'} ], id=_options_collapse, shown=[] ), @@ -196,7 +204,7 @@ def layout(): # Handle showing or hiding the student tile header clientside_callback( ClientsideFunction(namespace=_namespace, function_name='showHideHeader'), - Output({'type': 'WOStudentTextTile', 'index': ALL}, 'showHeader'), + Output({'type': 'WOStudentTextTile', 'index': ALL}, 'showName'), Input(_options_hide_header, 'value'), State({'type': 'WOStudentTextTile', 'index': ALL}, 'id'), ) diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py index 1ca677c3c..07a9ab5aa 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/options.py @@ -1,9 +1,12 @@ import writing_observer.nlp_indicators import writing_observer.languagetool_features -parents = [] - -OPTIONS = [ +PROCESS_OPTIONS = [ + {'id': 'process_information', 'label': 'Process Information', 'parent': ''}, + {'id': 'time_on_task', 'label': 'Time on Task', 'types': ['metric'], 'parent': 'process_information'}, + {'id': 'status', 'label': 'Status', 'types': ['metric'], 'parent': 'process_information'} +] +OPTIONS = PROCESS_OPTIONS + [ {'id': indicator['id'], 'types': ['highlight'], 'label': indicator['name'], 'parent': indicator['category']} for indicator in writing_observer.nlp_indicators.INDICATOR_JSONS ] @@ -11,6 +14,11 @@ OPTIONS.append({'id': category, 'label': label, 'parent': 'text_information'}) OPTIONS.append({'id': 'text_information', 'label': 'Text Information', 'parent': ''}) +DEFAULT_VALUE = { + 'time_on_task': {'metric': {'value': True}}, + 'status': {'metric': {'value': True}} +} + # Set of colors to use for highlighting with presets HIGHLIGHTING_COLORS = [ "#FFD700", # Golden Yellow diff --git a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py index 5a142d56f..3dfeac035 100644 --- a/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py +++ b/modules/wo_classroom_text_highlighter/wo_classroom_text_highlighter/preset_component.py @@ -10,6 +10,7 @@ _prefix = 'option-preset' _store = f'{_prefix}-store' _add_input = f'{_prefix}-add-input' +_add_help = f'{_prefix}-add-help' _add_button = f'{_prefix}-add-button' _tray = f'{_prefix}-tray' _set_item = f'{_prefix}-set-item' @@ -19,6 +20,11 @@ def create_layout(): add_preset = dbc.InputGroup([ dbc.Input(id=_add_input, placeholder='Preset name', type='text', value=''), + dbc.InputGroupText(html.I(className='fas fa-circle-question'), id=_add_help), + dbc.Tooltip( + 'Save the current selected information as a preset for quick use in the future.', + target=_add_help + ), dbc.Button([ html.I(className='fas fa-plus me-1'), 'Preset' diff --git a/modules/writing_observer/VERSION b/modules/writing_observer/VERSION index 2e2f7e4a0..c309e668b 100644 --- a/modules/writing_observer/VERSION +++ b/modules/writing_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.04.01T15.05.13.407Z.44725993.berickson.022025.gpt.dashboard.updates +0.1.0+2025.04.07T20.48.55.419Z.3bdcc7c9.berickson.202504.process.metrics diff --git a/modules/writing_observer/writing_observer/module.py b/modules/writing_observer/writing_observer/module.py index 2c82bf5d4..dad2f01a3 100644 --- a/modules/writing_observer/writing_observer/module.py +++ b/modules/writing_observer/writing_observer/module.py @@ -101,9 +101,8 @@ 'nlp_sep_proc': q.select(q.keys('writing_observer.nlp_components', STUDENTS=q.variable('roster'), STUDENTS_path='user_id', RESOURCES=q.variable("doc_ids"), RESOURCES_path='doc_id'), fields='All'), 'nlp_combined': q.join(LEFT=q.variable(nlp_source), LEFT_ON='provenance.provenance.STUDENT.value.user_id', RIGHT=q.variable('roster'), RIGHT_ON='user_id'), # error dashboard activity map nodes - 'time_on_task': q.select(q.keys('writing_observer.time_on_task', STUDENTS=q.variable("roster"), STUDENTS_path='user_id', RESOURCES=q.variable("doc_sources"), RESOURCES_path='doc_id'), fields={'saved_ts': 'last_ts'}), + 'time_on_task': q.select(q.keys('writing_observer.time_on_task', STUDENTS=q.variable("roster"), STUDENTS_path='user_id', RESOURCES=q.variable("doc_sources"), RESOURCES_path='doc_id'), fields={'saved_ts': 'last_ts', 'total_time_on_task': 'time_on_task'}), 'activity_map': q.map(determine_activity, q.variable('time_on_task'), value_path='last_ts'), - 'activity_combined': q.join(LEFT=q.variable('activity_map'), LEFT_ON='provenance.value.provenance.provenance.STUDENT.value.user_id', RIGHT=q.variable('roster'), RIGHT_ON='user_id'), # single student language tool nodes 'single_student_latest_doc': q.select(q.keys('writing_observer.last_document', STUDENTS=q.parameter("student_id", required=True), STUDENTS_path='user_id'), fields={'document_id': 'doc_id'}), 'single_timestamped_docs': q.select(q.keys('writing_observer.document_access_timestamps', STUDENTS=q.parameter("student_id", required=True), STUDENTS_path='user_id'), fields={'timestamps': 'timestamps'}), @@ -189,7 +188,12 @@ "output": "" }, "activity": { - "returns": "activity_combined", + "returns": "activity_map", + "parameters": ["course_id"], + "output": "" + }, + "time_on_task": { + "returns": "time_on_task", "parameters": ["course_id"], "output": "" }, From e4e4adf41c74c6d475418a521713e27987528e98 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Wed, 11 Jun 2025 07:48:01 -0500 Subject: [PATCH 040/327] LTI auth + Canvas/Schoology integration Added LTI auth workflow as well as canvas and schoology integrations. This included abstracting some of the google endpoint cleaner code out so we could reuse it. --- VERSION | 2 +- learning_observer/VERSION | 2 +- .../learning_observer/auth/__init__.py | 1 + .../learning_observer/auth/lti_sso.py | 343 ++++++++++++ .../learning_observer/auth/social_sso.py | 4 +- .../learning_observer/client_config.py | 1 + learning_observer/learning_observer/google.py | 489 ------------------ .../integrations/__init__.py | 30 ++ .../learning_observer/integrations/canvas.py | 146 ++++++ .../learning_observer/integrations/google.py | 251 +++++++++ .../integrations/schoology.py | 115 ++++ .../learning_observer/integrations/util.py | 301 +++++++++++ .../learning_observer/rosters.py | 87 +++- learning_observer/learning_observer/routes.py | 26 +- .../learning_observer/settings.py | 3 +- .../static/modules/login.html | 2 + learning_observer/learning_observer/util.py | 8 + .../learning_observer/webapp_helpers.py | 12 +- modules/writing_observer/VERSION | 2 +- .../writing_observer/awe_nlp.py | 1 + requirements.txt | 1 + 21 files changed, 1304 insertions(+), 523 deletions(-) create mode 100644 learning_observer/learning_observer/auth/lti_sso.py delete mode 100644 learning_observer/learning_observer/google.py create mode 100644 learning_observer/learning_observer/integrations/__init__.py create mode 100644 learning_observer/learning_observer/integrations/canvas.py create mode 100644 learning_observer/learning_observer/integrations/google.py create mode 100644 learning_observer/learning_observer/integrations/schoology.py create mode 100644 learning_observer/learning_observer/integrations/util.py diff --git a/VERSION b/VERSION index 82e6a0cee..f9873b800 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.05.01T19.10.46.507Z.bc7bcb4c.berickson.202504.process.metrics +0.1.0+2025.06.11T12.17.15.667Z.233ef706.202505.berickson.lti.integration diff --git a/learning_observer/VERSION b/learning_observer/VERSION index 82e6a0cee..f9873b800 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.05.01T19.10.46.507Z.bc7bcb4c.berickson.202504.process.metrics +0.1.0+2025.06.11T12.17.15.667Z.233ef706.202505.berickson.lti.integration diff --git a/learning_observer/learning_observer/auth/__init__.py b/learning_observer/learning_observer/auth/__init__.py index 5edc27b78..3e6be7858 100644 --- a/learning_observer/learning_observer/auth/__init__.py +++ b/learning_observer/learning_observer/auth/__init__.py @@ -70,6 +70,7 @@ # Specific authentication schemes from learning_observer.auth.social_sso import social_handler from learning_observer.auth.password import password_auth +from learning_observer.auth.lti_sso import handle_oidc_authorize, handle_oidc_launch, check_oidc_login # Code below does sanity checks on configuration # diff --git a/learning_observer/learning_observer/auth/lti_sso.py b/learning_observer/learning_observer/auth/lti_sso.py new file mode 100644 index 000000000..e6bcd3ba3 --- /dev/null +++ b/learning_observer/learning_observer/auth/lti_sso.py @@ -0,0 +1,343 @@ +''' +Generic LTI 1.3 Single Sign-On handler for multiple providers. + +Implements LTI 1.3's OpenID Connect (OIDC) authentication handshake. +OIDC establishes a secure SSO channel between Learning Management +Systems (LMS) and our tool. This allows the LMS to install our +application under specific contexts (courses). + +The workflow is split across 2 functions + +`handle_oidc_authorize` +1. The LMS sends request for OIDC parameters to this endpoint +2. We create parameters with metadata and send back + +`handle_oidc_launch` +3. If authorized, the LMS sends back encrypted data to this endpoint +4. We decrypt, to get information about the user +5. We verify ourselves against the LMS to generate an auth token +6. User and auth information is stored in the session +''' + +import aiohttp +import aiohttp_session +import jwt +import pmss +import re +import time +import uuid +from aiohttp import web +from urllib.parse import urlencode + +import learning_observer.auth.utils +import learning_observer.constants as constants +import learning_observer.settings + +from learning_observer.log_event import debug_log + +''' +Items in settings should look like +{ + 'auth_uri': 'https://canvas.instructure.com/api/lti/authorize_redirect', + 'jwks_uri': 'https://canvas.instructure.com/api/lti/security/jwks', + 'token_uri': 'https://canvas.instructure.com/login/oauth2/token', + 'client_id': 'YOUR_CLIENT_ID', + 'redirect_uri': 'https://yourdomain.com/lti/canvas/launch', + 'private_key_path': './keys/canvas/private.pem' +} +''' +pmss.register_field( + name='auth_uri', + type=pmss.pmsstypes.TYPES.string, + description="Where to redirect the user's OIDC parameters", + required=True +) +pmss.register_field( + name='jwks_uri', + type=pmss.pmsstypes.TYPES.string, + description="The server's jwks endpoint", + required=True +) +pmss.register_field( + name='token_uri', + type=pmss.pmsstypes.TYPES.string, + description="Where to trade verified users for oauth tokens", + required=True +) +pmss.register_field( + name='redirect_uri', + type=pmss.pmsstypes.TYPES.string, + description='Where to redirect a user after successful OAuth login', + required=True +) +pmss.register_field( + name='private_key_path', + type=pmss.pmsstypes.TYPES.string, + description='Path to where private key is stored', + required=True +) + + +# TODO this code is copied from lo/lo/integrations/canvas.py +# it should abstracted properly +def _extract_course_id_from_url(url): + if match := re.search(r'/courses/(\d+)/names_and_role', url): + return match.group(1) + return None + + +# TODO: Implement persistent configuration storage +# TODO: Add rate limiting for JWKS requests +# TODO: Implement CSRF protection for state parameter + +# =============================== +# JWKS/JWT Validation Utilities +# =============================== + +JWKS_CACHE = {} + + +async def _decode_and_validate_lti_token(provider: str, token: str) -> dict: + ''' + This uses the provider's public key to decode the token + provided by the LMS to our launch endpoint. + + The JSON Web Key Sets (JWKS) are used for verifying + JSON Web Tokens (JWT) that were issued and signed. + ''' + async def get_public_key(kid: str): + '''Get RSA public key from our JWKS to verify token signature + ''' + async def fetch_jwks() -> dict: + '''This fetches and caches JWKS from an external service. + ''' + jwks_uri = learning_observer.settings.pmss_settings.jwks_uri(types=['auth', 'lti', provider]) + + if provider not in JWKS_CACHE: + async with aiohttp.ClientSession() as session: + async with session.get(jwks_uri) as response: + JWKS_CACHE[provider] = await response.json() + return JWKS_CACHE[provider] + + def find_jwk(jwks: dict) -> dict: + return next((k for k in jwks.get('keys', []) if k.get('kid') == kid), None) + + if jwk := find_jwk(await fetch_jwks()): + return jwt.algorithms.RSAAlgorithm.from_jwk(jwk) + return None + + # Extract unverified headers and claims from JWT + # We need to extract some information from the token so + # we can know the `kid`, `aud`, and `iss`. + headers = jwt.get_unverified_header(token) + claims = jwt.decode(token, options={'verify_signature': False}) + + if not (public_key := await get_public_key(headers.get('kid'))): + raise jwt.exceptions.InvalidTokenError('Invalid key ID') + + return jwt.decode( + token, + public_key, + algorithms=['RS256'], + audience=claims.get('aud'), + issuer=claims.get('iss') + ) + + +# ====================== +# OIDC Authorization Flow +# ====================== +# Implements LTI 1.3's OpenID Connect (OIDC) authentication handshake. +# OIDC establishes a secure SSO channel between Learning Management +# Systems (LMS) and our tool. + +# ====================== +# OIDC Login Handler +# ====================== + + +async def handle_oidc_authorize(request: web.Request) -> web.Response: + '''Initiate OIDC authorization flow. + Create OIDC request parameters and send them to the + LMS to verify. + + This function is registered to route `/lti/{provider}/login` + ''' + def create_oidc_params(provider, data: dict) -> dict: + return { + 'scope': 'openid', + 'response_type': 'id_token', + 'response_mode': 'form_post', + 'prompt': 'none', + 'client_id': learning_observer.settings.pmss_settings.client_id(types=['auth', 'lti', provider]), + # TODO this could easily be built from server/lti/{provider}/launch + 'redirect_uri': learning_observer.settings.pmss_settings.redirect_uri(types=['auth', 'lti', provider]), + # help confirm state with future responses + 'nonce': str(uuid.uuid4()), + 'state': str(uuid.uuid4()), + # hints provided by LMS + 'login_hint': data.get('login_hint', ''), + 'lti_message_hint': data.get('lti_message_hint', '') + } + + provider = request.match_info['provider'] + data = await request.post() if request.method == 'POST' else request.query + + params = create_oidc_params(provider, data) + session = await aiohttp_session.get_session(request) + session['lti_state'] = params['state'] + session['lti_nonce'] = params['nonce'] + redirect_base_url = learning_observer.settings.pmss_settings.auth_uri(types=['auth', 'lti', provider]) + return web.HTTPFound( + location=f"{redirect_base_url}?{urlencode(params)}" + ) + + +# ====================== +# OIDC Launch Handler +# ====================== + + +async def handle_oidc_launch(request: web.Request) -> web.Response: + '''Process OIDC launch response + After the LMS server confirms our identity, it sends information + about the user to this endpoint. We exchange that information for + an API token and store it in the user's session. This token is + used later for getting the roster/assignments/etc. + + This function is registered to route `/lti/{provider}/launch` + ''' + def validate_oidc_state(session: dict, state: str) -> None: + '''Validate OIDC state parameter matches session''' + if session.get('lti_state') != state: + debug_log('LTI Launch invalid state') + raise web.HTTPBadRequest(text='Something went wrong.') + + def create_user_from_claims(claims: dict, provider: str) -> dict: + '''The created user is consistent with the rest of LO. + ''' + roles = claims.get('https://purl.imsglobal.org/spec/lti/claim/roles', []) + instructor_roles = [ + 'http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator', + 'http://purl.imsglobal.org/vocab/lis/v2/institution/person#Instructor', + 'http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor', + 'http://purl.imsglobal.org/vocab/lis/v2/system/person#SysAdmin' + ] + is_instructor = any(r in roles for r in instructor_roles) + + # Include the LTI Launch Context + # HACK in Canvas, each course has 2 IDs: + # 1. LTI compliant ID - `lti_context_id` + # 2. ID used to make API calls - `api_id` + context = claims.get('https://purl.imsglobal.org/spec/lti/claim/context', {}) + api_with_id = claims.get('https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice', {}).get('context_memberships_url') + extracted_course_id = _extract_course_id_from_url(api_with_id) + id = context['id'] + lti_context = { + 'lti_context_id': id, + 'api_id': extracted_course_id if extracted_course_id else id, + 'provider': provider + } + + return { + constants.USER_ID: claims['sub'], + 'email': claims.get('email'), + 'name': claims.get('given_name'), + 'family_name': claims.get('family_name', ''), + 'picture': claims.get('picture', ''), + 'role': learning_observer.auth.ROLES.TEACHER if is_instructor else learning_observer.auth.ROLES.STUDENT, + 'authorized': is_instructor, + 'lti_context': lti_context + # TODO figure out backto. With google sso, we had a state we could store things in + # 'back_to': request.query.get('state') + } + + def generate_signed_client_authentication_jwt(provider) -> str: + ''' + Generates cryptographically signed JWTs for verifying identity. + Uses RSA-SHA256 to sign claims containing client identity (iss/sub), + token endpoint (aud), timestamp controls (iat/exp), and unique JTI. + + The token generated is used to obtain an OAuth token + ''' + def read_private_pem_key_from_file(path: str) -> str: + return open(path, 'r').read() + + private_key_path = learning_observer.settings.pmss_settings.private_key_path(types=['auth', 'lti', provider]) + private_key = read_private_pem_key_from_file(private_key_path) + + now = time.time() + client_id = learning_observer.settings.pmss_settings.client_id(types=['auth', 'lti', provider]) + token_uri = learning_observer.settings.pmss_settings.token_uri(types=['auth', 'lti', provider]) + + # Note the client is both the issuer and subject since + # it is proving its own identity + payload = { + 'iss': client_id, # issuer + 'sub': client_id, # subject + 'aud': token_uri, # audience + 'iat': now, # JWT issued at + 'exp': now + 300, # JWT expiration (5 minutes) + 'jti': str(uuid.uuid4()) # JWT ID + } + return jwt.encode(payload, private_key, algorithm='RS256') + + async def exchange_assertion_for_token(provider, assertion: str) -> str: + '''Exchange client assertion for access token''' + token_uri = learning_observer.settings.pmss_settings.token_uri(types=['auth', 'lti', provider]) + token_data = { + 'grant_type': 'client_credentials', + 'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', + 'client_assertion': assertion, + 'scope': ' '.join([ + # Can retrieve user data associated with the context the tool is installed in + 'https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly', + # Can view assignment data in the gradebook associated with the tool + 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly', + # Can create and update submission results for assignments associated with the tool + 'https://purl.imsglobal.org/spec/lti-ags/scope/score', + ]) + } + async with aiohttp.ClientSession() as session: + async with session.post(url=token_uri, data=token_data) as response: + if response.status != 200: + debug_log(f'LTI Launch Error during token exchange:\n{await response.text()}') + raise web.HTTPBadRequest(text='Something went wrong.') + return (await response.json())['access_token'] + + provider = request.match_info['provider'] + data = await request.post() + + try: + # Validate OIDC response + session = await aiohttp_session.get_session(request) + validate_oidc_state(session, data.get('state')) + + # Verify and decode JWT + claims = await _decode_and_validate_lti_token(provider, data.get('id_token')) + if claims['nonce'] != session.get('lti_nonce'): + debug_log('LTI Launch invalid nonce') + raise web.HTTPBadRequest(text='Something went wrong.') + + # Create user session + user_info = create_user_from_claims(claims, provider) + await learning_observer.auth.utils.update_session_user_info(request, user_info) + + # Exchange for access token + assertion = generate_signed_client_authentication_jwt(provider) + access_token = await exchange_assertion_for_token(provider, assertion) + + # Store auth headers + headers = {'Authorization': f'Bearer {access_token}'} + session[constants.AUTH_HEADERS] = headers + request[constants.AUTH_HEADERS] = headers + + return web.HTTPFound(location='/') + + except (jwt.PyJWTError, KeyError) as e: + debug_log(f'LTI Launch Authentication failed: {e}') + raise web.HTTPUnauthorized(text='Something went wrong.') + + +async def check_oidc_login(request): + return web.HTTPFound('/') diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 0bad8f1b7..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -41,7 +41,6 @@ import learning_observer.constants as constants import learning_observer.exceptions -import learning_observer.google import learning_observer.kvs import learning_observer.rosters import learning_observer.runtime @@ -163,6 +162,7 @@ async def _store_teacher_info_for_background_process(id, request): TODO remove this function and references when new, better workflows are established. ''' + import learning_observer.google debug_log("SocialSSO Storing teacher info: {} {}".format(id, request)) kvs = learning_observer.kvs.KVS() runtime = learning_observer.runtime.Runtime(request) @@ -189,7 +189,7 @@ async def _fetch_and_store_document(student, doc_id): doc = await learning_observer.google.doctext(runtime, documentId=doc_id) if 'text' not in doc: skipped_docs.add(doc_id) - debu_log("** SocialSSO Text not found: {} {}".format(student, doc_id)) + debug_log("** SocialSSO Text not found: {} {}".format(student, doc_id)) return await kvs.set(doc_key, doc) debug_log("** SocialSSO Text stored: {} {}".format(student, doc_id)) diff --git a/learning_observer/learning_observer/client_config.py b/learning_observer/learning_observer/client_config.py index 4b1c0d20e..4a2c86755 100644 --- a/learning_observer/learning_observer/client_config.py +++ b/learning_observer/learning_observer/client_config.py @@ -37,6 +37,7 @@ async def client_config_handler(request): "google_oauth": "google_oauth" in learning_observer.settings.settings['auth'], "password_auth": "password_file" in learning_observer.settings.settings['auth'], "http_basic_auth": learning_observer.auth.http_basic.http_auth_page_enabled(), + "lti_auth": "lti" in learning_observer.settings.settings['auth'], "theme": learning_observer.settings.settings['theme'] } diff --git a/learning_observer/learning_observer/google.py b/learning_observer/learning_observer/google.py deleted file mode 100644 index f1e45f899..000000000 --- a/learning_observer/learning_observer/google.py +++ /dev/null @@ -1,489 +0,0 @@ -''' -We will gradually move all of the Google-specific code into here. - -Our design goals: -- Easily call into Google APIs (Classroom, Drive, Docs, etc.) -- Be able to preprocess the data into standard formats - -On a high level, for each Google request, we plan to have a 4x4 grid: -- Web request and function call -- Cleaned versus raw data - -The Google APIs are well-designed (if poorly-documented, and with occasional -bugs), but usually return more data than we need, so we have cleaner functions. - -For a given call, we might have several cleaners. For example, for a Google Doc, -Google returns a massive JSON object containing everything. For most purposes, -we don't need all of that, and it's more convenient to work with a plain -text representation, and for downstream code to not need to understand this -JSON. However, for some algorithms, we might need additonal data of different -sorts. It's still more convenient to hand this back in something simplified for -analysis. -''' - -import collections -import itertools -import json -import recordclass -import string -import re - -import aiohttp -import aiohttp.web -import aiohttp_session - -import learning_observer.constants as constants -import learning_observer.settings as settings -import learning_observer.log_event -import learning_observer.util -import learning_observer.auth -import learning_observer.runtime -import learning_observer.prestartup - - -cache = None - - -GOOGLE_FIELDS = [ - 'alternateLink', 'calculationType', 'calendarId', 'courseGroupEmail', - 'courseId', 'courseState', 'creationTime', 'descriptionHeading', - 'displaySetting', 'emailAddress', 'enrollmentCode', 'familyName', - 'fullName', 'givenName', 'gradebookSettings', 'guardiansEnabled', - 'ownerId', 'photoUrl', 'teacherFolder', 'teacherGroupEmail', 'updateTime', - 'userId' -] - -# On in-take, we want to convert Google's CamelCase to LO's snake_case. This -# dictionary contains the conversions. -camel_to_snake = re.compile(r'(?>> ("hello {hi} my {bye}")] - ['hi', 'bye'] - ''' - # The parse returns a lot of context, which we discard. In particular, the - # last item is often about the suffix after the last parameter and may be - # `None` - return [f[1] for f in string.Formatter().parse(format_string) if f[1] is not None] - - -async def raw_google_ajax(runtime, target_url, **kwargs): - ''' - Make an AJAX call to Google, managing auth + auth. - - * runtime is a Runtime class containing request information. - * default_url is typically grabbed from ENDPOINTS - * ... and we pass the named parameters - ''' - request = runtime.get_request() - url = target_url.format(**kwargs) - user = await learning_observer.auth.get_active_user(request) - if constants.AUTH_HEADERS not in request or user is None: - raise aiohttp.web.HTTPUnauthorized(text="Please log in") # TODO: Consistent way to flag this - - cache_key = "raw_google/" + learning_observer.auth.encode_id('session', user[constants.USER_ID]) + '/' + learning_observer.util.url_pathname(url) - if settings.feature_flag('use_google_ajax') is not None: - value = await cache[cache_key] - if value is not None: - return learning_observer.util.translate_json_keys( - json.loads(value), - GOOGLE_TO_SNAKE - ) - async with aiohttp.ClientSession(loop=request.app.loop) as client: - async with client.get(url, headers=request[constants.AUTH_HEADERS]) as resp: - response = await resp.json() - learning_observer.log_event.log_ajax(target_url, response, request) - if settings.feature_flag('use_google_ajax') is not None: - await cache.set(cache_key, json.dumps(response, indent=2)) - return learning_observer.util.translate_json_keys( - response, - GOOGLE_TO_SNAKE - ) - - -def raw_access_partial(remote_url, name=None): - ''' - This is a helper which allows us to create a function which calls specific - Google APIs. - - To test this, try: - - print(await raw_document(request, documentId="some_google_doc_id")) - ''' - async def caller(request, **kwargs): - ''' - Make an AJAX request to Google - ''' - return await raw_google_ajax(request, remote_url, **kwargs) - setattr(caller, "__qualname__", name) - - return caller - - -@learning_observer.prestartup.register_startup_check -def connect_to_google_cache(): - '''Setup cache for requests to the Google API. - The cache is currently only used with the `use_google_ajax` - feature flag. - ''' - if not settings.feature_flag('google_routes'): - return - - for key in ['save_google_ajax', 'use_google_ajax', 'save_clean_ajax', 'use_clean_ajax']: - if settings.feature_flag(key): - global cache - try: - cache = learning_observer.kvs.KVS.google_cache() - except AttributeError: - error_text = 'The google_cache KVS is not configured.\n'\ - 'Please add a `google_cache` kvs item to the `kvs` '\ - 'key in `creds.yaml`.\n'\ - '```\ngoogle_cache:\n type: filesystem\n path: ./learning_observer/static_data/google\n'\ - ' subdirs: true\n```\nOR\n'\ - '```\ngoogle_cache:\n type: redis_ephemeral\n expiry: 600\n```' - raise learning_observer.prestartup.StartupCheck("Google KVS: " + error_text) - - -def initialize_and_register_routes(app): - ''' - This is a big 'ol function which might be broken into smaller ones at some - point. We: - - - Created debug routes to pass through AJAX requests to Google - - Created production APIs to have access to cleaned versions of said data - - Create local function calls to call from other pieces of code - within process - - We probably don't need all of this in production, but a lot of this is - very important for debugging. Having APIs is more useful than it looks, since - making use of Google APIs requires a lot of infrastructure (registering - apps, auth/auth, etc.) which we already have in place on dev / debug servers. - ''' - # For now, all of this is behind one big feature flag. In the future, - # we'll want seperate ones for the debugging tools and the production - # staff - if not settings.feature_flag('google_routes'): - return - - # Provide documentation on what we're doing - app.add_routes([ - aiohttp.web.get("/google", api_docs_handler) - ]) - - def make_ajax_raw_handler(remote_url): - ''' - This creates a handler to forward Google requests to the client. It's used - for debugging right now. We should think through APIs before relying on this. - ''' - async def ajax_passthrough(request): - ''' - And the actual handler.... - ''' - runtime = learning_observer.runtime.Runtime(request) - response = await raw_google_ajax( - runtime, - remote_url, - **request.match_info - ) - - return aiohttp.web.json_response(response) - return ajax_passthrough - - def make_cleaner_handler(raw_function, cleaner_function, name=None): - async def cleaner_handler(request): - ''' - ''' - response = cleaner_function( - await raw_function(request, **request.match_info) - ) - if isinstance(response, dict) or isinstance(response, list): - return aiohttp.web.json_response( - response - ) - elif isinstance(response, str): - return aiohttp.web.Response( - text=response - ) - else: - raise AttributeError(f"Invalid response type: {type(response)}") - if name is not None: - setattr(cleaner_handler, "__qualname__", name + "_handler") - - return cleaner_handler - - def make_cleaner_function(raw_function, cleaner_function, name=None): - async def cleaner_local(request, **kwargs): - google_response = await raw_function(request, **kwargs) - clean = cleaner_function(google_response) - return clean - if name is not None: - setattr(cleaner_local, "__qualname__", name) - return cleaner_local - - for e in ENDPOINTS: - function_name = f"raw_{e.name}" - raw_function = raw_access_partial(remote_url=e.remote_url, name=e.name) - globals()[function_name] = raw_function - cleaners = e._cleaners() - for c in cleaners: - app.add_routes([ - aiohttp.web.get( - cleaners[c]['local_url'], - make_cleaner_handler( - raw_function, - cleaners[c]['function'], - name=cleaners[c]['name'] - ) - ) - ]) - globals()[cleaners[c]['name']] = make_cleaner_function( - raw_function, - cleaners[c]['function'], - name=cleaners[c]['name'] - ) - app.add_routes([ - aiohttp.web.get( - e._local_url(), - make_ajax_raw_handler(e.remote_url) - ) - ]) - - -def api_docs_handler(request): - ''' - Return a list of available endpoints. - - Eventually, we should also document available function calls - ''' - response = "URL Endpoints:\n\n" - for endpoint in ENDPOINTS: - response += f"{endpoint._local_url()}\n" - cleaners = endpoint._cleaners() - for c in cleaners: - response += f" {cleaners[c]['local_url']}\n" - response += "\n\n Globals:" - if False: - response += str(globals()) - return aiohttp.web.Response(text=response) - - -def register_cleaner(data_source, cleaner_name): - ''' - This will register a cleaner function, for export both as a web service - and as a local function call. - ''' - def decorator(f): - found = False - for endpoint in ENDPOINTS: - if endpoint.name == data_source: - found = True - endpoint._add_cleaner( - cleaner_name, - { - 'function': f, - 'local_url': f'{endpoint._local_url()}/{cleaner_name}', - 'name': cleaner_name - } - ) - - if not found: - raise AttributeError(f"Data source {data_source} invalid; not found in endpoints.") - return f - - return decorator - - -# Rosters -@register_cleaner("course_roster", "roster") -def clean_course_roster(google_json): - ''' - Retrieve the roster for a course, alphabetically - ''' - students = google_json.get('students', []) - students.sort( - key=lambda x: x.get('name', {}).get('fullName', 'ZZ'), - ) - # Convert Google IDs to internal ideas (which are the same, but with a gc- prefix) - for student_json in students: - google_id = student_json['profile']['id'] - local_id = learning_observer.auth.google_id_to_user_id(google_id) - student_json[constants.USER_ID] = local_id - del student_json['profile']['id'] - - # For the present there is only one external id so we will add that directly. - if 'external_ids' not in student_json['profile']: - student_json['profile']['external_ids'] = [] - student_json['profile']['external_ids'].append({"source": "google", "id": google_id}) - return students - - -@register_cleaner("course_list", "courses") -def clean_course_list(google_json): - ''' - Google's course list is one object deeper than we'd like, and alphabetic - sort order is nicer. This will clean it up a bit - ''' - courses = google_json.get('courses', []) - courses.sort( - key=lambda x: x.get('name', 'ZZ'), - ) - return courses - - -@register_cleaner('course_work', 'assignments') -def clean_course_work(google_json): - ''' - Google's course work is one object deeper than we'd like, and update_time - sort order is nicer. This will clean it up a bit - ''' - assignments = google_json.get('courseWork', []) - assignments.sort( - key=lambda x: x.get('update_time', 0) - ) - return assignments - - -# Google Docs -def _force_text_length(text, length): - ''' - Force text to a given length, either concatenating or padding - - >>> force_text_length("Hello", 3) - >>> 'Hel' - - >>> force_text_length("Hello", 13) - >>> 'Hello ' - ''' - return text[:length] + " " * (length - len(text)) - - -def get_error_details(error): - messages = { - 403: 'Student working on private document.', - 404: 'Unable to fetch document.' - } - code = error['code'] - message = messages.get(code, 'Unknown error.') - return {'error': {'code': code, 'message': message}} - - -@register_cleaner("document", "doctext") -def extract_text_from_google_doc_json( - j, align=True, - EXTRACT_DEBUG_CHECKS=False): - ''' - Extract text from a Google Docs JSON object, ignoring formatting. - - There is an alignment issue between Google's and Python's handling - of Unicode. We can either: - * extract text faithfully (align=False) - * extract text with aligned indexes by cutting text / adding - spaces (align=True) - - This issue came up in text with a Russian flag unicode symbol - (referencing the current conflict). I tried various encodings, - and none quite matched Google 100%. - - Note that align=True doesn't necessarily give perfect local alignment - within text chunks, since we do have different lengths for something like - this flag. It does work okay globally. - ''' - # return error message for text - if 'error' in j: - return get_error_details(j['error']) - length = j['body']['content'][-1]['endIndex'] - elements = [a.get('paragraph', {}).get('elements', []) for a in j['body']['content']] - flat = sum(elements, []) - text_chunks = [f['textRun']['content'] for f in flat] - if align: - lengths = [f['endIndex'] - f['startIndex'] for f in flat] - text_chunks = [_force_text_length(chunk, length) for chunk, length in zip(text_chunks, lengths)] - text = ''.join(text_chunks) - - if EXTRACT_DEBUG_CHECKS: - print("Text length versus Google length:") - print(len(text), length) - print("We expect these to be off by one, since Google seems to starts at 1 (and Python at 0)") - if align: - print - print("Offsets (these should match):") - print(list(zip(itertools.accumulate(map(len, text_chunks)), itertools.accumulate(lengths)))) - - return {'text': text} - - -@register_cleaner("coursework_submissions", "assigned_docs") -def clean_assignment_docs(google_json): - ''' - Retrieve set of documents per student associated with an assignment - ''' - student_submissions = google_json.get('studentSubmissions', []) - for student_json in student_submissions: - google_id = student_json[constants.USER_ID] - local_id = learning_observer.auth.google_id_to_user_id(google_id) - student_json[constants.USER_ID] = local_id - docs = [d['driveFile'] for d in learning_observer.util.get_nested_dict_value(student_json, 'assignmentSubmission.attachments', []) if 'driveFile' in d] - student_json['documents'] = docs - # TODO we should probably remove some of the keys provided - return student_submissions - - -if __name__ == '__main__': - import json - import sys - j = json.load(open(sys.argv[1])) - # extract_text_from_google_doc_json(j, align=False, EXTRACT_DEBUG_CHECKS=True) - # extract_text_from_google_doc_json(j, align=True, EXTRACT_DEBUG_CHECKS=True) - output = clean_assignment_docs(j) - print(json.dumps(output, indent=2)) diff --git a/learning_observer/learning_observer/integrations/__init__.py b/learning_observer/learning_observer/integrations/__init__.py new file mode 100644 index 000000000..213faa972 --- /dev/null +++ b/learning_observer/learning_observer/integrations/__init__.py @@ -0,0 +1,30 @@ +import learning_observer.integrations.canvas +import learning_observer.integrations.google +import learning_observer.integrations.schoology +import learning_observer.settings + +INTEGRATIONS = {} + + +def register_integrations(app): + '''`routes.py:add_routes` calls this function to add the + integrated services as routes on the system + + This initializes INTEGRATIONS for other functions to reference + when making a call to course/rosters/assignments/etc. + ''' + # TODO the setting checks should be calling into `pmss_settings` instead of `settings` + if 'google_oauth' in learning_observer.settings.settings['auth']: + INTEGRATIONS['google'] = learning_observer.integrations.google.register_endpoints(app) + + if 'lti' not in learning_observer.settings.settings['auth']: + return + + if 'schoology' in learning_observer.settings.settings['auth']['lti']: + INTEGRATIONS['schoology'] = learning_observer.integrations.schoology.register_endpoints(app) + + canvas_providers = [k for k in learning_observer.settings.settings['auth']['lti'].keys() if 'canvas' in k] + for provider in canvas_providers: + provider_endpoint_registrar = learning_observer.integrations.canvas.setup_canvas_provider(provider) + # TODO check that provider doesn't already exist and is trying to be overwritten + INTEGRATIONS[provider] = provider_endpoint_registrar(app) diff --git a/learning_observer/learning_observer/integrations/canvas.py b/learning_observer/learning_observer/integrations/canvas.py new file mode 100644 index 000000000..cb6c9164a --- /dev/null +++ b/learning_observer/learning_observer/integrations/canvas.py @@ -0,0 +1,146 @@ +import pmss +import re + +import learning_observer.kvs +import learning_observer.constants as constants +import learning_observer.settings as settings + +from . import util + +pmss.register_field( + name='api_domain', + type=pmss.pmsstypes.TYPES.string, + description='Domain of the api calls', + required=True +) + + +def setup_canvas_provider(provider): + # TODO pull the base url from settings based on provider + base_url = settings.pmss_settings.api_domain(types=['auth', 'lti', provider]) + + ENDPOINTS = list(map(lambda x: util.Endpoint(*x, api_name=provider), [ + ('course_list', base_url + '/api/lti/courses/{courseId}/names_and_roles'), + ('course_roster', base_url + '/api/lti/courses/{courseId}/names_and_roles'), + ('course_lineitems', base_url + '/api/lti/courses/{courseId}/line_items'), + ])) + + register_cleaner = util.make_cleaner_registrar(ENDPOINTS) + + def register_canvas_endpoints(app): + if not settings.feature_flag('canvas_routes'): + return + + # Create the API routes and get back the functions + return util.register_endpoints( + app=app, + endpoints=ENDPOINTS, + api_name=provider, + feature_flag_name='canvas_routes' + ) + + def _extract_course_id_from_url(url): + if match := re.search(r'/courses/(\d+)/names_and_role', url): + return match.group(1) + return None + + @register_cleaner('course_list', 'courses') + def clean_course_list(canvas_json): + ''' + The LTI integration Canvas uses for auth occurs on a + course by course level. This cleaner wraps the current + course in a list. + ''' + context = canvas_json.get('context', {}) + if not (id := _extract_course_id_from_url(canvas_json.get('id', ''))): + raise ValueError('Canvas json did not provide a parsable id') + course = { + 'id': id, + 'name': context.get('label'), + 'title': context.get('title'), + 'lti_id': context.get('id') + } + cleaned = [course] + return cleaned + + async def _lookup_gid_by_email(email): + kvs = learning_observer.kvs.KVS() + key = f'email-studentID-mapping:{email}' + id = await kvs[key] + if id: + return f'gid-{id}' + return None + + async def _process_canvas_user_for_system(member): + # Skip if no canvas id + canvas_id = member.get('user_id') + if not canvas_id: return None + + # Skip non students + is_student = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner' in member.get('roles', []) + if not is_student: return None + + # Create user for our system + email = member.get('email') + local_id = await _lookup_gid_by_email(email) + if not local_id: + local_id = f'canvas-{canvas_id}' + + member[constants.USER_ID] = local_id + user = { + 'profile': { + 'name': { + 'given_name': member.get('given_name'), + 'family_name': member.get('family_name'), + 'full_name': member.get('name') + }, + 'email_address': email, + 'photo_url': member.get('picture') + }, + constants.USER_ID: local_id, + # TODO is this needed? Other roster functions in LO include it + # 'course_id': course_id + } + return user + + @register_cleaner('course_roster', 'roster') + async def clean_course_roster(canvas_json): + ''' + Retrieve and clean the roster for a Canvas course, alphabetically sorted + + Conforms to LTI NRPS v2 response format + https://www.imsglobal.org/spec/lti-nrps/v2p0 + ''' + members = canvas_json.get('members', []) + members.sort( + key=lambda x: x.get('name', 'ZZ'), + ) + # Process each student record + users = [] + for m in members: + user = await _process_canvas_user_for_system(m) + if user is not None: + users.append(user) + + return users + + @register_cleaner('course_lineitems', 'assignments') + def clean_course_assignments(canvas_json): + ''' + Clean course line items (assignments) from Canvas + + Conforms to LTI AGS response format + https://www.imsglobal.org/spec/lti-ags/v2p0 + ''' + line_items = canvas_json + if not isinstance(line_items, list): + # If it's not already a list, check for lineItems property that might contain the list + line_items = canvas_json.get('lineItems', []) + + # Sort by due date if available, otherwise by title + line_items.sort( + key=lambda x: x.get('endDateTime', x.get('label', 'ZZ')), + ) + return line_items + + return register_canvas_endpoints diff --git a/learning_observer/learning_observer/integrations/google.py b/learning_observer/learning_observer/integrations/google.py new file mode 100644 index 000000000..de7f85c9a --- /dev/null +++ b/learning_observer/learning_observer/integrations/google.py @@ -0,0 +1,251 @@ +''' +Google-specific API module for Learning Observer. + +This module provides access to various Google APIs (Classroom, Drive, Docs, etc.) +using the generic API infrastructure. + +The module provides: +- Raw data access to Google APIs +- Cleaned data from Google APIs in standardized formats +- Both web API routes and in-process function calls +''' + +import itertools +import json +import re + +import learning_observer.constants as constants +import learning_observer.auth +import learning_observer.kvs +import learning_observer.prestartup +import learning_observer.settings as settings +import learning_observer.util + +from . import util + + +# Cache for Google API responses +cache = None + +# Google field name mapping +GOOGLE_FIELDS = [ + 'alternateLink', 'calculationType', 'calendarId', 'courseGroupEmail', + 'courseId', 'courseState', 'creationTime', 'descriptionHeading', + 'displaySetting', 'emailAddress', 'enrollmentCode', 'familyName', + 'fullName', 'givenName', 'gradebookSettings', 'guardiansEnabled', + 'ownerId', 'photoUrl', 'teacherFolder', 'teacherGroupEmail', 'updateTime', + 'userId' +] + +# Convert Google's CamelCase to LO's snake_case +camel_to_snake = re.compile(r'(?>> force_text_length("Hello", 3) + >>> 'Hel' + + >>> force_text_length("Hello", 13) + >>> 'Hello ' + ''' + return text[:length] + " " * (length - len(text)) + + +def get_error_details(error): + messages = { + 403: 'Student working on private document.', + 404: 'Unable to fetch document.' + } + code = error['code'] + message = messages.get(code, 'Unknown error.') + return {'error': {'code': code, 'message': message}} + + +@register_cleaner("document", "doctext") +def extract_text_from_google_doc_json( + j, align=True, + EXTRACT_DEBUG_CHECKS=False): + ''' + Extract text from a Google Docs JSON object, ignoring formatting. + + There is an alignment issue between Google's and Python's handling + of Unicode. We can either: + * extract text faithfully (align=False) + * extract text with aligned indexes by cutting text / adding + spaces (align=True) + + This issue came up in text with a Russian flag unicode symbol + (referencing the current conflict). I tried various encodings, + and none quite matched Google 100%. + + Note that align=True doesn't necessarily give perfect local alignment + within text chunks, since we do have different lengths for something like + this flag. It does work okay globally. + ''' + # return error message for text + if 'error' in j: + return get_error_details(j['error']) + length = j['body']['content'][-1]['endIndex'] + elements = [a.get('paragraph', {}).get('elements', []) for a in j['body']['content']] + flat = sum(elements, []) + text_chunks = [f['textRun']['content'] for f in flat] + if align: + lengths = [f['endIndex'] - f['startIndex'] for f in flat] + text_chunks = [_force_text_length(chunk, length) for chunk, length in zip(text_chunks, lengths)] + text = ''.join(text_chunks) + + if EXTRACT_DEBUG_CHECKS: + print("Text length versus Google length:") + print(len(text), length) + print("We expect these to be off by one, since Google seems to starts at 1 (and Python at 0)") + if align: + print + print("Offsets (these should match):") + print(list(zip(itertools.accumulate(map(len, text_chunks)), itertools.accumulate(lengths)))) + + return {'text': text} + + +@register_cleaner("coursework_submissions", "assigned_docs") +def clean_assignment_docs(google_json): + ''' + Retrieve set of documents per student associated with an assignment + ''' + student_submissions = google_json.get('studentSubmissions', []) + for student_json in student_submissions: + google_id = student_json[constants.USER_ID] + local_id = learning_observer.auth.google_id_to_user_id(google_id) + student_json[constants.USER_ID] = local_id + docs = [d['driveFile'] for d in learning_observer.util.get_nested_dict_value(student_json, 'assignmentSubmission.attachments', []) if 'driveFile' in d] + student_json['documents'] = docs + # TODO we should probably remove some of the keys provided + return student_submissions + + +if __name__ == '__main__': + import json + import sys + j = json.load(open(sys.argv[1])) + # extract_text_from_google_doc_json(j, align=False, EXTRACT_DEBUG_CHECKS=True) + # extract_text_from_google_doc_json(j, align=True, EXTRACT_DEBUG_CHECKS=True) + output = clean_assignment_docs(j) + print(json.dumps(output, indent=2)) diff --git a/learning_observer/learning_observer/integrations/schoology.py b/learning_observer/learning_observer/integrations/schoology.py new file mode 100644 index 000000000..990b72360 --- /dev/null +++ b/learning_observer/learning_observer/integrations/schoology.py @@ -0,0 +1,115 @@ +import learning_observer.constants as constants +import learning_observer.kvs +import learning_observer.settings as settings + +from . import util + +API = 'schoology' + +ENDPOINTS = list(map(lambda x: util.Endpoint(**x, api_name=API), [ + {'name': 'course_list', 'remote_url': 'https://api.schoology.com/v1/sections/{courseId}/enrollments', 'headers': {'Accept': 'application/vnd.ims.lti-nrps.v2.membershipcontainer+json'}}, + {'name': 'course_roster', 'remote_url': 'https://api.schoology.com/v1/sections/{courseId}/enrollments', 'headers': {'Accept': 'application/vnd.ims.lti-nrps.v2.membershipcontainer+json'}}, + {'name': 'course_assignments', 'remote_url': 'https://api.schoology.com/v1/sections/{courseId}/assignments', 'headers': {'Accept': 'application/vnd.ims.lis.v2.lineitemcontainer+json'}}, +])) + +register_cleaner = util.make_cleaner_registrar(ENDPOINTS) + + +def register_endpoints(app): + ''' + ''' + if not settings.feature_flag('schoology_routes'): + return + + return util.register_endpoints( + app=app, + endpoints=ENDPOINTS, + api_name=API, + feature_flag_name='schoology_routes' + ) + + +@register_cleaner('course_list', 'courses') +def clean_course_list(schoology_json): + ''' + The LTI integration Schoology uses for auth occurs on a + course by course level. This cleaner wraps the current + course in a list. + ''' + context = schoology_json.get('context', {}) + course = { + 'id': context.get('id'), + 'name': context.get('label'), + 'title': context.get('title'), + } + return [course] + + +# TODO this already exists in a different place - it should live in only one place +async def _lookup_gid_by_email(email): + kvs = learning_observer.kvs.KVS() + key = f'email-studentID-mapping:{email}' + id = await kvs[key] + if id: + return f'gid-{id}' + return None + + +async def _process_schoology_user_for_system(member): + # Skip if no canvas id + canvas_id = member.get('user_id') + if not canvas_id: return None + + # Skip non students + is_student = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner' in member.get('roles', []) + if not is_student: return None + + # Create user for our system + email = member.get('email') + local_id = await _lookup_gid_by_email(email) + if not local_id: + local_id = f'canvas-{canvas_id}' + + member[constants.USER_ID] = local_id + user = { + 'profile': { + 'name': { + 'given_name': member.get('given_name'), + 'family_name': member.get('family_name'), + 'full_name': member.get('name') + }, + 'email_address': email, + 'photo_url': member.get('picture') + }, + constants.USER_ID: local_id, + # TODO is this needed? Other roster functions in LO include it + # 'course_id': course_id + } + return user + + +@register_cleaner('course_roster', 'roster') +async def clean_course_roster(schoology_json): + ''' + Retrieve and clean the roster for a Canvas course, alphabetically sorted + + Conforms to LTI NRPS v2 response format + https://www.imsglobal.org/spec/lti-nrps/v2p0 + ''' + print('clean_course_roster', schoology_json) + return + # Process each student record + # for m in members: + # user = await _process_schoology_user_for_system(m) + + +@register_cleaner('course_assignments', 'assignments') +def clean_course_assignments(schoology_json): + ''' + Clean course line items (assignments) from Schoology + + Conforms to LTI AGS response format + https://www.imsglobal.org/spec/lti-ags/v2p0 + ''' + print('clean_course_assignments', schoology_json) + return diff --git a/learning_observer/learning_observer/integrations/util.py b/learning_observer/learning_observer/integrations/util.py new file mode 100644 index 000000000..b56595cce --- /dev/null +++ b/learning_observer/learning_observer/integrations/util.py @@ -0,0 +1,301 @@ +''' +Generic API calling infrastructure that can be reused for different APIs. + +Design goals: +- Easily call into external APIs +- Be able to preprocess the data into standard formats + +On a high level, for each API request, we plan to have a 4x4 grid: +- Web request and function call +- Cleaned versus raw data + +For each specific API implementation, we'll have both raw data access and cleaner functions +to transform that data into more convenient formats. +''' +import inspect +import json +import recordclass +import string + +import aiohttp +import aiohttp.web + +import learning_observer.constants as constants +import learning_observer.settings as settings +import learning_observer.log_event +import learning_observer.auth +import learning_observer.runtime +import learning_observer.util + + +class Endpoint(recordclass.make_dataclass("Endpoint", ["name", "remote_url", "doc", "cleaners", "api_name", "headers"], defaults=["", None, None, None])): + def arguments(self): + return extract_parameters_from_format_string(self.remote_url) + + def _local_url(self): + parameters = "}/{".join(self.arguments()) + base_url = f"/{self.api_name}/{self.name}" + if len(parameters) == 0: + return base_url + else: + return base_url + "/{" + parameters + "}" + + def _add_cleaner(self, name, cleaner): + if self.cleaners is None: + self.cleaners = dict() + self.cleaners[name] = cleaner + if 'local_url' not in cleaner: + cleaner['local_url'] = self._local_url() + "/" + name + + def _cleaners(self): + if self.cleaners is None: + return [] + else: + return self.cleaners + + +def extract_parameters_from_format_string(format_string): + ''' + Extracts parameters from a format string. E.g. + + >>> ("hello {hi} my {bye}")] + ['hi', 'bye'] + ''' + # The parse returns a lot of context, which we discard. In particular, the + # last item is often about the suffix after the last parameter and may be + # `None` + return [f[1] for f in string.Formatter().parse(format_string) if f[1] is not None] + + +async def raw_api_ajax(runtime, target_url, key_translator=None, cache=None, cache_key_prefix=None, headers=None, **kwargs): + ''' + Make an AJAX call to an API, managing auth + auth. + + * runtime is a Runtime class containing request information. + * target_url is typically grabbed from ENDPOINTS + * key_translator is a dictionary to translate API keys to internal keys + * cache is an optional cache object + * cache_key_prefix is the prefix to use for cache keys + * ... and we pass the named parameters + ''' + request = runtime.get_request() + url = target_url.format(**kwargs) + user = await learning_observer.auth.get_active_user(request) + + if constants.AUTH_HEADERS not in request or user is None: + raise aiohttp.web.HTTPUnauthorized(text="Please log in") + + if headers is None: + headers = {} + headers.update(request.get(constants.AUTH_HEADERS, {})) + + cache_available = cache is not None and cache_key_prefix is not None + + if cache_available: + cache_key = f"{cache_key_prefix}/{learning_observer.auth.encode_id('session', user[constants.USER_ID])}/{learning_observer.util.url_pathname(url)}" + if settings.feature_flag('save_clean_ajax') is not None: + value = await cache[cache_key] + if value is not None: + response_data = json.loads(value) + if key_translator: + return learning_observer.util.translate_json_keys(response_data, key_translator) + return response_data + + async with aiohttp.ClientSession(loop=request.app.loop) as client: + async with client.get(url, headers=headers) as resp: + response = await resp.json() + learning_observer.log_event.log_ajax(target_url, response, request) + + if cache_available: + if settings.feature_flag('use_clean_ajax') is not None: + await cache.set(cache_key, json.dumps(response, indent=2)) + + if key_translator: + return learning_observer.util.translate_json_keys(response, key_translator) + return response + + +def raw_access_partial(remote_url, key_translator=None, cache=None, cache_key_prefix=None, name=None, headers=None): + ''' + This is a helper which allows us to create a function which calls specific + API endpoints. + ''' + async def caller(runtime, **kwargs): + ''' + Make an AJAX request to the API + ''' + return await raw_api_ajax( + runtime, + remote_url, + key_translator, + cache, + cache_key_prefix, + headers, + **kwargs + ) + + if name: + setattr(caller, "__qualname__", name) + + return caller + + +def register_endpoints(app, endpoints, api_name, key_translator=None, cache=None, cache_key_prefix=None, feature_flag_name=None): + ''' + Initialize API routes and handlers: + + - Creates debug routes to pass through AJAX requests to API + - Creates production APIs to have access to cleaned versions of data + - Creates local function calls to call from other pieces of code within process + + Parameters: + - app: The aiohttp application to which routes will be added + - endpoints: List of Endpoint objects describing API endpoints + - api_name: Name of the API (e.g., "google", "canvas") + - key_translator: Dictionary to translate API keys to internal keys + - cache: Cache object for API responses + - cache_key_prefix: Prefix for cache keys + - feature_flag_name: Feature flag to check before enabling routes + ''' + # Check feature flag if provided + if feature_flag_name and not settings.feature_flag(feature_flag_name): + return + + # Provide documentation on what we're doing + async def api_docs_handler(request): + '''Return a list of available endpoints.''' + response = f"{api_name.capitalize()} API Endpoints:\n" + for endpoint in endpoints: + response += f"{endpoint._local_url()}\n" + cleaners = endpoint._cleaners() + for c in cleaners: + response += f" {cleaners[c]['local_url']}\n" + return aiohttp.web.Response(text=response) + + app.add_routes([ + aiohttp.web.get(f"/{api_name}", api_docs_handler) + ]) + + def make_ajax_raw_handler(remote_url): + ''' + Creates a handler to forward API requests to the client. + ''' + async def ajax_passthrough(request): + '''The actual handler.''' + runtime = learning_observer.runtime.Runtime(request) + response = await raw_api_ajax( + runtime, + remote_url, + key_translator, + cache, + cache_key_prefix, + **request.match_info + ) + return aiohttp.web.json_response(response) + return ajax_passthrough + + def make_cleaner_handler(raw_function, cleaner_function, name=None): + async def cleaner_handler(request): + # TODO check if we need the runtime here + runtime = learning_observer.runtime.Runtime(request) + response = cleaner_function( + await raw_function(runtime, **request.match_info) + ) + if inspect.isawaitable(response): + response = await response + if isinstance(response, dict) or isinstance(response, list): + return aiohttp.web.json_response(response) + elif isinstance(response, str): + return aiohttp.web.Response(text=response) + else: + raise AttributeError(f"Invalid response type: {type(response)}") + + if name is not None: + setattr(cleaner_handler, "__qualname__", name + "_handler") + return cleaner_handler + + def make_cleaner_function(raw_function, cleaner_function, name=None): + async def cleaner_local(runtime, **kwargs): + api_response = await raw_function(runtime, **kwargs) + clean = cleaner_function(api_response) + if inspect.isawaitable(clean): + clean = await clean + return clean + if name is not None: + setattr(cleaner_local, "__qualname__", name) + return cleaner_local + + # Setup the global namespace using the provided namespace dict + result_functions = {} + + for e in endpoints: + function_name = f"raw_{e.name}" + raw_function = raw_access_partial( + remote_url=e.remote_url, + key_translator=key_translator, + cache=cache, + cache_key_prefix=cache_key_prefix, + name=e.name + ) + result_functions[function_name] = raw_function + cleaners = e._cleaners() + for c in cleaners: + app.add_routes([ + aiohttp.web.get( + cleaners[c]['local_url'], + make_cleaner_handler( + raw_function, + cleaners[c]['function'], + name=cleaners[c]['name'] + ) + ) + ]) + result_functions[cleaners[c]['name']] = make_cleaner_function( + raw_function, + cleaners[c]['function'], + name=cleaners[c]['name'] + ) + + app.add_routes([ + aiohttp.web.get( + e._local_url(), + make_ajax_raw_handler(e.remote_url) + ) + ]) + + return result_functions + + +def make_cleaner_registrar(endpoints): + ''' + Creates a register_cleaner function specific to a list of endpoints. + + Returns: + A function that can be used as a decorator to register cleaners. + ''' + def register_cleaner(data_source, cleaner_name): + ''' + Registers a cleaner function for export both as a web service + and as a local function call. + ''' + def decorator(f): + found = False + for endpoint in endpoints: + if endpoint.name == data_source: + found = True + endpoint._add_cleaner( + cleaner_name, + { + 'function': f, + 'local_url': f'{endpoint._local_url()}/{cleaner_name}', + 'name': cleaner_name + } + ) + + if not found: + raise AttributeError(f"Data source {data_source} invalid; not found in endpoints.") + return f + + return decorator + + return register_cleaner diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 6e66baf3b..a0627657c 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -60,6 +60,7 @@ time. ''' +import inspect import json import os.path @@ -71,8 +72,9 @@ import learning_observer.auth as auth import learning_observer.cache +import learning_observer.communication_protocol.integration import learning_observer.constants as constants -import learning_observer.google +import learning_observer.integrations import learning_observer.kvs import learning_observer.log_event as log_event from learning_observer.log_event import debug_log @@ -80,13 +82,13 @@ import learning_observer.prestartup import learning_observer.runtime import learning_observer.settings as settings -import learning_observer.communication_protocol.integration +import learning_observer.util COURSE_URL = 'https://classroom.googleapis.com/v1/courses' ROSTER_URL = 'https://classroom.googleapis.com/v1/courses/{courseid}/students' -pmss.parser('roster_source', parent='string', choices=['google_api', 'all', 'test', 'filesystem'], transform=None) +pmss.parser('roster_source', parent='string', choices=['google', 'canvas', 'schoology', 'all', 'test', 'filesystem'], transform=None) pmss.register_field( name='source', type='roster_source', @@ -94,7 +96,7 @@ '`all`: aggregate all available students into a single class\n'\ '`test`: use sample course and student files\n'\ '`filesystem`: read rosters defined on filesystem\n'\ - '`google_api`: fetch from Google API', + '`google|schoology|canvas`: fetch from specific API', required=True ) @@ -349,19 +351,13 @@ def init(): ''' global ajax roster_source = settings.pmss_settings.source(types=['roster_data']) - if 'roster_data' not in settings.settings: - print(settings.settings) - raise learning_observer.prestartup.StartupCheck( - "Settings file needs a `roster_data` element with a `source` element. No `roster_data` element found." - ) - elif 'source' not in settings.settings['roster_data']: - raise learning_observer.prestartup.StartupCheck( - "Settings file needs a `roster_data` element with a `source` element. No `source` element found." - ) - elif roster_source in ['test', 'filesystem']: + if roster_source in ['test', 'filesystem']: ajax = synthetic_ajax + # Google, Canvas, and Schoology all use integrations instead of ajax when called elif roster_source in ["google_api"]: ajax = google_ajax + elif roster_source in ["canvas_api", 'schoology_api']: + pass elif roster_source in ["all"]: ajax = all_ajax else: @@ -369,7 +365,7 @@ def init(): "Settings file `roster_data` element should have `source` field\n" "set to either:\n" " test (retrieve from files courses.json and students.json)\n" - " google_api (retrieve roster data from Google)\n" + " google_api | canvas_api | schoology_api (retrieve roster data from an api)\n" " filesystem (retrieve roster data from file system hierarchy\n" " all (retrieve roster data as all students)" ) @@ -406,14 +402,55 @@ def init(): return ajax +async def run_additional_module_func(request, function_name, kwargs=None): + '''This function calls the `function_name` for one of our integrated LMSs. + This is used to call the LMSs `.courses` and `.roster` functions. + Returns result of the function, `None` otherwise. + ''' + if not kwargs: + kwargs = {} + + user = await auth.get_active_user(request) + + user_domain = learning_observer.util.get_domain_from_email(user.get('email')) + # TODO we ough to include provider in the attributes (need to test provider) + provider = user.get('lti_context', {}).get('provider') + roster_source = settings.pmss_settings.source(types=['roster_data'], attributes={'domain': user_domain}) + + # HACK/TODO since Canvas and Schoology are launched via an LTI, + # we need to pass a course to the courses - LTI applications are + # provided on a course-by-course basis, so fetching the courses + # just needs to provide the current course context. + if roster_source in ['canvas', 'schoology'] and function_name == 'corosterurses': + kwargs['courseId'] = user.get('lti_context', {}).get('api_id') + + if roster_source not in learning_observer.integrations.INTEGRATIONS: + debug_log(f'Provider `{roster_source}` not found in INTEGRATIONS. Available integrations: {learning_observer.integrations.INTEGRATIONS.keys()}') + return None + + runtime = learning_observer.runtime.Runtime(request) + func = learning_observer.integrations.INTEGRATIONS[roster_source].get(function_name, None) + if not func: + debug_log(f'Provider `{roster_source}` does not have function `{function_name}`.') + return None + + if callable(func): + result = func(runtime, **kwargs) + if inspect.isawaitable(result): + result = await result + return result + debug_log(f'No result from `{roster_source}.{function_name}`') + return None + + async def courselist(request): ''' List all of the courses a teacher manages: Helper ''' - # New code - if settings.pmss_settings.source(types=['roster_data']) in ["google_api"]: - runtime = learning_observer.runtime.Runtime(request) - return await learning_observer.google.courses(runtime) + course_list = await run_additional_module_func(request, 'courses') + if course_list: + return course_list + # TODO if course_list is falsey, the following code may fail if there if ajax is not defined. # Legacy code course_list = await ajax( @@ -445,7 +482,9 @@ async def memoize_courseroster_runtime(runtime, course_id): In the future, we ought to be able to specify how the values from individual nodes are handled: static, dynamic (current), or memoized. ''' - @learning_observer.cache.async_memoization() + # TODO the async memoization cache here is causing a ton of slowdown + # when trying to connect to a remote Redis instance. + # @learning_observer.cache.async_memoization() async def course_roster_memoization_layer(c): return await courseroster_runtime(runtime, c) return await course_roster_memoization_layer(course_id) @@ -455,10 +494,12 @@ async def courseroster(request, course_id): ''' List all of the students in a course: Helper ''' - if settings.pmss_settings.source(types=['roster_data']) in ["google_api"]: - runtime = learning_observer.runtime.Runtime(request) - return await learning_observer.google.roster(runtime, courseId=course_id) + roster = await run_additional_module_func(request, 'roster', kwargs={'courseId': course_id}) + if roster: + return roster + if not ajax: + return [] roster = await ajax( request, url=ROSTER_URL, diff --git a/learning_observer/learning_observer/routes.py b/learning_observer/learning_observer/routes.py index b1fa0adc4..8811f668c 100644 --- a/learning_observer/learning_observer/routes.py +++ b/learning_observer/learning_observer/routes.py @@ -22,7 +22,7 @@ import learning_observer.impersonate import learning_observer.incoming_student_event as incoming_student_event import learning_observer.dashboard -import learning_observer.google +import learning_observer.integrations import learning_observer.rosters as rosters import learning_observer.module_loader @@ -66,7 +66,7 @@ def tracemalloc_handler(request): register_static_routes(app) register_incoming_event_views(app) register_debug_routes(app) - learning_observer.google.initialize_and_register_routes(app) + learning_observer.integrations.register_integrations(app) app.add_routes([ aiohttp.web.get( @@ -240,12 +240,30 @@ def register_auth_webapp_views(app): debug_log("Running with Google authentication") app.add_routes([ aiohttp.web.get( - # TODO only allow the available sign-in options found in pmss - # '/auth/login/{provider:google|canvas|schoology}', '/auth/login/{provider:google}', handler=learning_observer.auth.social_handler), ]) + # TODO We ought to use pmss here, though at this time it is easier + # to check if a key exists this way + if 'lti' in settings.settings['auth']: + debug_log("Running with LTI authentication") + # TODO build provider syntax based on available providers + app.add_routes([ + aiohttp.web.post( + '/lti/{provider}/login', + handler=learning_observer.auth.handle_oidc_authorize), + aiohttp.web.get( + '/lti/{provider}/login', + handler=learning_observer.auth.handle_oidc_authorize), + aiohttp.web.post( + '/lti/{provider}/launch', + handler=learning_observer.auth.handle_oidc_launch), + aiohttp.web.get( + '/auth/login/lti', + learning_observer.auth.check_oidc_login) + ]) + if 'password_file' in settings.settings['auth']: debug_log("Running with password authentication") if not os.path.exists(settings.settings['auth']['password_file']): diff --git a/learning_observer/learning_observer/settings.py b/learning_observer/learning_observer/settings.py index 385d8a96a..017da21c5 100644 --- a/learning_observer/learning_observer/settings.py +++ b/learning_observer/learning_observer/settings.py @@ -225,7 +225,8 @@ def initialized(): # Not all of these are guaranteed to work on every branch of the codebase. AVAILABLE_FEATURE_FLAGS = [ 'uvloop', 'watchdog', 'auth_headers_page', 'merkle', 'save_google_ajax', 'use_google_ajax', - 'google_routes', 'save_clean_ajax', 'use_clean_ajax' + 'google_routes', 'save_clean_ajax', 'use_clean_ajax', + 'canvas_routes', 'schoology_routes' ] diff --git a/learning_observer/learning_observer/static/modules/login.html b/learning_observer/learning_observer/static/modules/login.html index fe4ab8e03..271e391de 100644 --- a/learning_observer/learning_observer/static/modules/login.html +++ b/learning_observer/learning_observer/static/modules/login.html @@ -50,6 +50,8 @@

{{ server_name }}

+
+

diff --git a/learning_observer/learning_observer/util.py b/learning_observer/learning_observer/util.py index 96140943d..4b0db2c8e 100644 --- a/learning_observer/learning_observer/util.py +++ b/learning_observer/learning_observer/util.py @@ -299,6 +299,14 @@ async def async_generator_to_list(gen): return result +def get_domain_from_email(email): + '''Helper function to extract the domain from an email address + ''' + if '@' in email: + return email.split('@')[1] + return None + + # And a test case if __name__ == '__main__': assert to_safe_filename('{') == '-123-' diff --git a/learning_observer/learning_observer/webapp_helpers.py b/learning_observer/learning_observer/webapp_helpers.py index a201c399d..4210a0548 100644 --- a/learning_observer/learning_observer/webapp_helpers.py +++ b/learning_observer/learning_observer/webapp_helpers.py @@ -66,9 +66,19 @@ def setup_session_storage(app): ''' This is a helper function to setup session storage. ''' + protocol = settings.pmss_settings.protocol() + cookie_params = {} + if protocol == 'https': + debug_log('Setting cookie parameters for HTTPS') + cookie_params = { + 'domain': settings.pmss_settings.hostname(), + 'secure': True, + 'samesite': 'None' + } aiohttp_session.setup(app, aiohttp_session.cookie_storage.EncryptedCookieStorage( learning_observer.auth.fernet_key(settings.pmss_settings.session_secret(types=['aio'])), - max_age=settings.pmss_settings.session_max_age(types=['aio']))) + max_age=settings.pmss_settings.session_max_age(types=['aio']), + **cookie_params)) def find_open_port(): diff --git a/modules/writing_observer/VERSION b/modules/writing_observer/VERSION index c309e668b..3fb21c1f9 100644 --- a/modules/writing_observer/VERSION +++ b/modules/writing_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.04.07T20.48.55.419Z.3bdcc7c9.berickson.202504.process.metrics +0.1.0+2025.05.16T17.31.36.630Z.e1505886.202505.berickson.lti.integration diff --git a/modules/writing_observer/writing_observer/awe_nlp.py b/modules/writing_observer/writing_observer/awe_nlp.py index b6d286fd9..4028d1265 100644 --- a/modules/writing_observer/writing_observer/awe_nlp.py +++ b/modules/writing_observer/writing_observer/awe_nlp.py @@ -372,6 +372,7 @@ async def process_writings_with_caching(writing_data, options=None, mode=RUN_MOD async for writing in writing_data: text = writing.get('text', '') if len(text) == 0: + yield writing continue # Creating text hash and setting defaults diff --git a/requirements.txt b/requirements.txt index c9333e839..d052bba15 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ loremipsum @ git+https://github.com/testlabauto/loremipsum.git@b7bd71a6651207ef8 ipython ipykernel jsonschema +pyjwt lxml # pubsub names notebook From 28cb3ec99d7f7b545fe0a3edb7ba9c408b08bf35 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 10 Jul 2025 08:52:19 -0400 Subject: [PATCH 041/327] Update rosters.py --- learning_observer/learning_observer/rosters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index a0627657c..a1c09ab07 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -421,7 +421,7 @@ async def run_additional_module_func(request, function_name, kwargs=None): # we need to pass a course to the courses - LTI applications are # provided on a course-by-course basis, so fetching the courses # just needs to provide the current course context. - if roster_source in ['canvas', 'schoology'] and function_name == 'corosterurses': + if roster_source in ['canvas', 'schoology'] and function_name == 'courses': kwargs['courseId'] = user.get('lti_context', {}).get('api_id') if roster_source not in learning_observer.integrations.INTEGRATIONS: From a6724ed606e2253cfc5c4fe288e672ca0819dbd0 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Wed, 16 Jul 2025 13:40:26 -0400 Subject: [PATCH 042/327] Workshop updates (#230) * Update the workshop files/instructions * updated template module --------- Co-authored-by: JohnDamilola --- VERSION | 2 +- docs/workshop.md | 9 ++++ .../learning_observer/creds.yaml.workshop | 1 + .../{{ cookiecutter.project_slug }}/VERSION | 2 +- .../assets/scripts.js | 45 +++++-------------- .../dash_dashboard.py | 21 +++------ .../my_layout.py | 17 +++---- 7 files changed, 34 insertions(+), 63 deletions(-) diff --git a/VERSION b/VERSION index f9873b800..cbbd3281b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.06.11T12.17.15.667Z.233ef706.202505.berickson.lti.integration +0.1.0+2025.07.16T17.39.45.896Z.a3b5acf4.workshop.updates diff --git a/docs/workshop.md b/docs/workshop.md index a79b6c664..b10d595f7 100644 --- a/docs/workshop.md +++ b/docs/workshop.md @@ -67,11 +67,20 @@ NOTE: All future commands should be ran starting from the repository's root dire Make sure you are on a fresh virtual environment. In `virtualenvwrapper`: +You can either run this + ```bash mkvirtualenv lo_workshop workon lo_workshop ``` +or run this to set up the virtual environment + +```bash +python -m venv lo_workshop +source lo_workshop/bin/activate +``` + Then run the install command: ```bash diff --git a/learning_observer/learning_observer/creds.yaml.workshop b/learning_observer/learning_observer/creds.yaml.workshop index c580cf039..afd7c0c10 100644 --- a/learning_observer/learning_observer/creds.yaml.workshop +++ b/learning_observer/learning_observer/creds.yaml.workshop @@ -1,3 +1,4 @@ +protocol: http config: run_mode: dev auth: diff --git a/modules/lo_template_module/{{ cookiecutter.project_slug }}/VERSION b/modules/lo_template_module/{{ cookiecutter.project_slug }}/VERSION index 367ae11d9..cbbd3281b 100644 --- a/modules/lo_template_module/{{ cookiecutter.project_slug }}/VERSION +++ b/modules/lo_template_module/{{ cookiecutter.project_slug }}/VERSION @@ -1 +1 @@ -0.1.0+2024.12.16T16.42.38.637Z.fa6150e4.berickson.versioning.workflow +0.1.0+2025.07.16T17.39.45.896Z.a3b5acf4.workshop.updates diff --git a/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/assets/scripts.js b/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/assets/scripts.js index f0f919126..5733e08c1 100644 --- a/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/assets/scripts.js +++ b/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/assets/scripts.js @@ -34,37 +34,18 @@ window.dash_clientside.{{ cookiecutter.project_slug }} = { return window.dash_clientside.no_update; }, - /** - * Process a message from LOConnection - * @param {object} incomingMessage object received from LOConnection - * @returns parsed data to local storage - */ - receiveWSMessage: async function (incomingMessage) { - // TODO the naming here is broken serverside. Notice above we - // called the target export `{{ cookiecutter.reducer }}_export`, i.e. the named - // export. Below, we need to call `{{ cookiecutter.project_slug }}_join_roster`, i.e. the name - // of the node. This ought to be cleaned up in the communication protocl. - const messageData = JSON.parse(incomingMessage.data).{{ cookiecutter.project_slug }}_query.{{ cookiecutter.reducer }}_join_roster || []; - if (messageData.error !== undefined) { - console.error('Error received from server', messageData.error); - return []; - } - return messageData; - }, - /** * Build the student UI components based on the stored websocket data * @param {*} wsStorageData information stored in the websocket store * @returns Dash object to be displayed on page */ - populateOutput: function(wsStorageData) { - if (!wsStorageData) { + populateOutput: function (wsStorageData) { + if (!wsStorageData?.students) { return 'No students'; } let output = [] // Iterate over students and create UI items for each - for (const student of wsStorageData) { - + for (const [student, value] of Object.entries(wsStorageData.students)) { // We define Dash components in JS via a dictionary // of where the component lives, what it is, and any // parameters we want to pass along to it. @@ -72,31 +53,27 @@ window.dash_clientside.{{ cookiecutter.project_slug }} = { // - `type`: the component to use // - `props`: any parameters the component expects // The following produces a LONameTag and Span wrapped in a Div - studentBadge = { + const studentBadge = { namespace: 'dash_html_components', type: 'Div', props: { children: [{ - namespace: 'lo_dash_react_components', + namespace: 'dash_html_components', props: { - profile: student.profile, - className: 'student-name-tag d-inline-block', - includeName: true, - id: `${student.user_id}-activity-img` + children: student }, - type: 'LONameTag' - },{ + type: 'Span' + }, { namespace: 'dash_html_components', props: { - children: ` - ${student.count} events`, + children: ` - ${value.count} events` }, type: 'Span' - }] } } - output = output.concat(studentBadge) + output = output.concat(studentBadge); } return output; } -} +}; diff --git a/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/dash_dashboard.py b/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/dash_dashboard.py index 05dbe2831..e82bf3cf2 100644 --- a/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/dash_dashboard.py +++ b/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/dash_dashboard.py @@ -23,35 +23,24 @@ _prefix = '{{ cookiecutter.project_hyphenated }}' _namespace = '{{ cookiecutter.project_slug }}' _websocket = f'{_prefix}-websocket' -_websocket_storage = f'{_prefix}-websocket-store' _output = f'{_prefix}-output' def layout(): ''' Function to define the page's layout. ''' - return my_layout(_websocket, _websocket_storage, _output) + return my_layout(_websocket, _output) # Send the initial state based on the url hash to LO. # If this is not included, nothing will be returned from # the communication protocol. clientside_callback( ClientsideFunction(namespace=_namespace, function_name='sendToLOConnection'), - Output(lodrc.LOConnectionStatusAIO.ids.websocket(_websocket), 'send'), - Input(lodrc.LOConnectionStatusAIO.ids.websocket(_websocket), 'state'), # used for initial setup + Output(lodrc.LOConnectionAIO.ids.websocket(_websocket), 'send'), + Input(lodrc.LOConnectionAIO.ids.websocket(_websocket), 'state'), # used for initial setup Input('_pages_location', 'hash') ) -# Handle receiving a message from the websocket. -# This step will parse the message and update the -# local storage accordingly. -clientside_callback( - ClientsideFunction(namespace=_namespace, function_name='receiveWSMessage'), - Output(_websocket_storage, 'data'), - Input(lodrc.LOConnectionStatusAIO.ids.websocket(_websocket), 'message'), - prevent_initial_call=True -) - # Build the UI based on what we've received from the # communicaton protocol # This clientside callback and the serverside callback below are @@ -59,13 +48,13 @@ def layout(): # clientside_callback( # ClientsideFunction(namespace=_namespace, function_name='populateOutput'), # Output(_output, 'children'), -# Input(_websocket_storage, 'data'), +# Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), # ) @callback( Output(_output, 'children'), - Input(_websocket_storage, 'data'), + Input(lodrc.LOConnectionAIO.ids.ws_store(_websocket), 'data'), ) def populate_output(data): '''This method creates UI components for each student found diff --git a/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/my_layout.py b/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/my_layout.py index 70eea5739..f33b39111 100644 --- a/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/my_layout.py +++ b/modules/lo_template_module/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/my_layout.py @@ -2,22 +2,20 @@ import dash_bootstrap_components as dbc import lo_dash_react_components as lodrc -def my_layout(_websocket, _websocket_storage, _output): +def my_layout(_websocket, _output): ''' This is the layout for the static part of your dashboard which is loaded when the page first loads. * The data would be populated in a div with id _output. * We pass the _websocket so we can render a component letting us know when things updated - * We pass the _websocket_storage, although we really should bubble that up. ''' page_layout = html.Div(children=[ html.H1(children='{{ cookiecutter.project_name }}'), dbc.InputGroup([ - dbc.InputGroupText(lodrc.LOConnectionStatusAIO(aio_id=_websocket)), + dbc.InputGroupText(lodrc.LOConnectionAIO(aio_id=_websocket)), lodrc.ProfileSidebarAIO(class_name='rounded-0 rounded-end', color='secondary'), ]), - dcc.Store(id=_websocket_storage), html.H2('Output from reducers'), html.Div(id=_output) ]) @@ -29,13 +27,10 @@ def my_data_layout(data): This is the layout for the changing part of your dashboard populated from the data. ''' - if not data: + if not data or len(data.get('students', {})) == 0: return 'No students' output = [html.Div([ - lodrc.LONameTag( - profile=s['profile'], className='d-inline-block student-name-tag', - includeName=True, id=f'{s["user_id"]}-name-tag' - ), - html.Span(f' - {s["count"]} events') - ]) for s in data] + k, + html.Span(f' - {v["count"]} events') + ]) for k, v in data.get('students', {}).items()] return output From f61cb8b128e383003792d6959ac90ca9481d0901 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Sun, 10 Aug 2025 16:58:27 -0400 Subject: [PATCH 043/327] Various improvements to serving as an LTI Supports Canvas and Schoology with some hacked solutions. Additionally added scripts for starting and stopping multiple instances. --- VERSION | 2 +- devops/single_server_instances/README.md | 36 ++++++++++++++++ .../start_lo_instances.sh | 39 ++++++++++++++++++ .../stop_lo_instances.sh | 29 +++++++++++++ learning_observer/VERSION | 2 +- .../learning_observer/downloads.py | 4 +- .../integrations/__init__.py | 5 ++- .../learning_observer/integrations/canvas.py | 19 +++------ .../integrations/schoology.py | 41 +++++++++---------- .../learning_observer/integrations/util.py | 13 +++++- .../learning_observer/log_event.py | 2 +- learning_observer/learning_observer/main.py | 2 +- .../learning_observer/rosters.py | 19 ++++++--- .../learning_observer/settings.py | 5 +++ modules/writing_observer/VERSION | 2 +- .../writing_observer/module.py | 5 +++ .../writing_observer/writing_analysis.py | 12 ++++++ scripts/map_emails_to_ids_in_kvs.py | 28 +++++++++++++ 18 files changed, 216 insertions(+), 49 deletions(-) create mode 100644 devops/single_server_instances/README.md create mode 100755 devops/single_server_instances/start_lo_instances.sh create mode 100755 devops/single_server_instances/stop_lo_instances.sh create mode 100644 scripts/map_emails_to_ids_in_kvs.py diff --git a/VERSION b/VERSION index cbbd3281b..23e7294b1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.07.16T17.39.45.896Z.a3b5acf4.workshop.updates +0.1.0+2025.08.10T20.53.47.175Z.cc7dc75e.berickson.202507.new.lti.updates diff --git a/devops/single_server_instances/README.md b/devops/single_server_instances/README.md new file mode 100644 index 000000000..48ae6103d --- /dev/null +++ b/devops/single_server_instances/README.md @@ -0,0 +1,36 @@ +# Learning Observer — Instance Control Scripts + +This directory contains two bash scripts to start and stop multiple instances of the `learning_observer` application. + +## Files + +* **`start_lo_instances.sh`** — Launches one or more instances of the app on sequential ports, creates log files, and stores process IDs in a PID directory. +* **`stop_lo_instances.sh`** — Stops all running instances recorded in the PID directory. + +## Configuration + +Before use, edit the scripts to match your system: + +* `LEARNING_OBSERVER_LOC` — Path to your project code. +* `VIRTUALENV_PATH` — Path to your Python virtual environment. +* `LOGFILE_DEST` — Directory for logs (default `/var/log/learning_observer`). +* `START_PORT` — First port to use. +* `SCRIPT_NAME` — Command or Python file to run. + +## Usage + +Start instances (default: 1): + +```bash +./start_lo_instances.sh +./start_lo_instances.sh 3 # start 3 instances +``` + +Stop all instances: + +```bash +./stop_lo_instances.sh +``` + +Logs are saved in `LOGFILE_DEST`, and PIDs are stored in `LOGFILE_DEST/pids`. +You may need to change paths or permissions depending on your environment. diff --git a/devops/single_server_instances/start_lo_instances.sh b/devops/single_server_instances/start_lo_instances.sh new file mode 100755 index 000000000..c872430dc --- /dev/null +++ b/devops/single_server_instances/start_lo_instances.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# === Config === +NUM_SERVERS=${1:-1} # default 1 server instance +START_PORT=9001 +LOGFILE_DEST="/var/log/learning_observer" +PIDFILE_DIR="$LOGFILE_DEST/pids" +LEARNING_OBSERVER_LOC="/path/to/your/code" +VIRTUALENV_PATH="/path/to/your/venv" +SCRIPT_NAME="learning_observer" + +# Create log + pid dirs if they don't exist +mkdir -p "$LOGFILE_DEST" +mkdir -p "$PIDFILE_DIR" + +# Timestamp for log grouping +LOG_DATE=$(date "+%m-%d-%Y--%H-%M-%S") + +# === Start Servers === +echo "Starting $NUM_SERVERS instances of $SCRIPT_NAME..." + +cd "$LEARNING_OBSERVER_LOC" +source "$VIRTUALENV_PATH/bin/activate" + +for ((i=0; i Log: $LOGFILE_NAME" + nohup python $SCRIPT_NAME --port $PORT > "$LOGFILE_NAME" 2>&1 & + PROCESS_ID=$! + echo $PROCESS_ID > "$PIDFILE_NAME" + echo " -> PID $PROCESS_ID logged to $PIDFILE_NAME" +done + +echo "✅ All servers started." +echo "Run ./scripts/stop_lo_instances.sh to stop server processes." diff --git a/devops/single_server_instances/stop_lo_instances.sh b/devops/single_server_instances/stop_lo_instances.sh new file mode 100755 index 000000000..2a3243445 --- /dev/null +++ b/devops/single_server_instances/stop_lo_instances.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# === Config === +LOGFILE_DEST="/var/log/learning_observer" +PIDFILE_DIR="$LOGFILE_DEST/pids" +SCRIPT_NAME="learning_observer" + +# === Stop All Servers === +echo "Stopping all $SCRIPT_NAME servers..." + +if [ ! -d "$PIDFILE_DIR" ]; then + echo "PID directory not found. Nothing to stop." + exit 1 +fi + +for PIDFILE in "$PIDFILE_DIR"/*.pid; do + if [ -f "$PIDFILE" ]; then + PID=$(cat "$PIDFILE") + if kill -0 "$PID" 2>/dev/null; then + echo "Stopping PID $PID from $PIDFILE" + kill "$PID" + else + echo "PID $PID not running, skipping." + fi + rm -f "$PIDFILE" + fi +done + +echo "✅ All servers stopped." diff --git a/learning_observer/VERSION b/learning_observer/VERSION index f9873b800..5f2ef51aa 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.06.11T12.17.15.667Z.233ef706.202505.berickson.lti.integration +0.1.0+2025.08.07T20.03.33.270Z.c17a54d7.berickson.202507.new.lti.updates diff --git a/learning_observer/learning_observer/downloads.py b/learning_observer/learning_observer/downloads.py index 9e76b1ef9..abea04761 100644 --- a/learning_observer/learning_observer/downloads.py +++ b/learning_observer/learning_observer/downloads.py @@ -90,7 +90,9 @@ "5.3.3": "54b69b378be9029cb841bce9f33e111148231ce38ae389601c10ee1fec93b" "bfb84839e84911e9e32e9e026a182e7225fd8531dc8344ba94ef4b467852e7162d5", "5.3.5": "3c9aa2c118ba4cbb2f54b2ca87528c453503ab5545983b6f5d10c6f04abd9" - "d4feb003c80c59a092857808e439642ab45e38369980288e7afb5a11e0e7946270e" + "d4feb003c80c59a092857808e439642ab45e38369980288e7afb5a11e0e7946270e", + "5.3.6": "0d33ccd34e5244052264f2e30088c92bfd28efc2db229926932be93ba3cc4" + "8b5f8378e12cf030c50965d1aa62a4a1a8f74493293b320aa9ef0a6b98962ab83b8" }, "tested_versions": [ 'https://cdn.jsdelivr.net/npm/bootswatch@5.3.5/dist/minty/bootstrap.min.css', diff --git a/learning_observer/learning_observer/integrations/__init__.py b/learning_observer/learning_observer/integrations/__init__.py index 213faa972..d3f2086c8 100644 --- a/learning_observer/learning_observer/integrations/__init__.py +++ b/learning_observer/learning_observer/integrations/__init__.py @@ -20,9 +20,12 @@ def register_integrations(app): if 'lti' not in learning_observer.settings.settings['auth']: return - if 'schoology' in learning_observer.settings.settings['auth']['lti']: + # TODO we ought to check for what type of provider each lti setting needs + # then only register the needed set of providers + if any('schoology' in k for k in learning_observer.settings.settings['auth']['lti']): INTEGRATIONS['schoology'] = learning_observer.integrations.schoology.register_endpoints(app) + # TODO we ought to fetch the following information with PMSS canvas_providers = [k for k in learning_observer.settings.settings['auth']['lti'].keys() if 'canvas' in k] for provider in canvas_providers: provider_endpoint_registrar = learning_observer.integrations.canvas.setup_canvas_provider(provider) diff --git a/learning_observer/learning_observer/integrations/canvas.py b/learning_observer/learning_observer/integrations/canvas.py index cb6c9164a..fe6dbaa0f 100644 --- a/learning_observer/learning_observer/integrations/canvas.py +++ b/learning_observer/learning_observer/integrations/canvas.py @@ -16,7 +16,6 @@ def setup_canvas_provider(provider): - # TODO pull the base url from settings based on provider base_url = settings.pmss_settings.api_domain(types=['auth', 'lti', provider]) ENDPOINTS = list(map(lambda x: util.Endpoint(*x, api_name=provider), [ @@ -63,15 +62,7 @@ def clean_course_list(canvas_json): cleaned = [course] return cleaned - async def _lookup_gid_by_email(email): - kvs = learning_observer.kvs.KVS() - key = f'email-studentID-mapping:{email}' - id = await kvs[key] - if id: - return f'gid-{id}' - return None - - async def _process_canvas_user_for_system(member): + def _process_canvas_user_for_system(member, google_id): # Skip if no canvas id canvas_id = member.get('user_id') if not canvas_id: return None @@ -82,7 +73,7 @@ async def _process_canvas_user_for_system(member): # Create user for our system email = member.get('email') - local_id = await _lookup_gid_by_email(email) + local_id = google_id if not local_id: local_id = f'canvas-{canvas_id}' @@ -116,9 +107,11 @@ async def clean_course_roster(canvas_json): key=lambda x: x.get('name', 'ZZ'), ) # Process each student record + emails = [m.get('email') for m in members] + google_ids = await util.lookup_gids_by_emails(emails) users = [] - for m in members: - user = await _process_canvas_user_for_system(m) + for member, google_id in zip(members, google_ids): + user = _process_canvas_user_for_system(member, google_id) if user is not None: users.append(user) diff --git a/learning_observer/learning_observer/integrations/schoology.py b/learning_observer/learning_observer/integrations/schoology.py index 990b72360..5ab47943e 100644 --- a/learning_observer/learning_observer/integrations/schoology.py +++ b/learning_observer/learning_observer/integrations/schoology.py @@ -7,8 +7,8 @@ API = 'schoology' ENDPOINTS = list(map(lambda x: util.Endpoint(**x, api_name=API), [ - {'name': 'course_list', 'remote_url': 'https://api.schoology.com/v1/sections/{courseId}/enrollments', 'headers': {'Accept': 'application/vnd.ims.lti-nrps.v2.membershipcontainer+json'}}, - {'name': 'course_roster', 'remote_url': 'https://api.schoology.com/v1/sections/{courseId}/enrollments', 'headers': {'Accept': 'application/vnd.ims.lti-nrps.v2.membershipcontainer+json'}}, + {'name': 'course_list', 'remote_url': 'https://lti-service.svc.schoology.com/lti-service/tool/{clientId}/services/names-roles/v2p0/membership/{courseId}', 'headers': {'Accept': 'application/vnd.ims.lti-nrps.v2.membershipcontainer+json'}}, + {'name': 'course_roster', 'remote_url': 'https://lti-service.svc.schoology.com/lti-service/tool/{clientId}/services/names-roles/v2p0/membership/{courseId}', 'headers': {'Accept': 'application/vnd.ims.lti-nrps.v2.membershipcontainer+json'}}, {'name': 'course_assignments', 'remote_url': 'https://api.schoology.com/v1/sections/{courseId}/assignments', 'headers': {'Accept': 'application/vnd.ims.lis.v2.lineitemcontainer+json'}}, ])) @@ -45,28 +45,19 @@ def clean_course_list(schoology_json): return [course] -# TODO this already exists in a different place - it should live in only one place -async def _lookup_gid_by_email(email): - kvs = learning_observer.kvs.KVS() - key = f'email-studentID-mapping:{email}' - id = await kvs[key] - if id: - return f'gid-{id}' - return None - - -async def _process_schoology_user_for_system(member): +def _process_schoology_user_for_system(member, google_id): # Skip if no canvas id canvas_id = member.get('user_id') if not canvas_id: return None # Skip non students is_student = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner' in member.get('roles', []) - if not is_student: return None + if not is_student: + return None # Create user for our system email = member.get('email') - local_id = await _lookup_gid_by_email(email) + local_id = google_id if not local_id: local_id = f'canvas-{canvas_id}' @@ -96,11 +87,17 @@ async def clean_course_roster(schoology_json): Conforms to LTI NRPS v2 response format https://www.imsglobal.org/spec/lti-nrps/v2p0 ''' - print('clean_course_roster', schoology_json) - return - # Process each student record - # for m in members: - # user = await _process_schoology_user_for_system(m) + members = schoology_json.get('members', []) + users = [] + + emails = [m.get('email') for m in members] + google_ids = await util.lookup_gids_by_emails(emails) + + for member, google_id in zip(members, google_ids): + user = _process_schoology_user_for_system(member, google_id) + if user is not None: + users.append(user) + return users @register_cleaner('course_assignments', 'assignments') @@ -111,5 +108,5 @@ def clean_course_assignments(schoology_json): Conforms to LTI AGS response format https://www.imsglobal.org/spec/lti-ags/v2p0 ''' - print('clean_course_assignments', schoology_json) - return + # print('Schoology assignments TODO', schoology_json) + return [] diff --git a/learning_observer/learning_observer/integrations/util.py b/learning_observer/learning_observer/integrations/util.py index b56595cce..4058b228c 100644 --- a/learning_observer/learning_observer/integrations/util.py +++ b/learning_observer/learning_observer/integrations/util.py @@ -22,6 +22,7 @@ import learning_observer.constants as constants import learning_observer.settings as settings +import learning_observer.kvs import learning_observer.log_event import learning_observer.auth import learning_observer.runtime @@ -235,7 +236,8 @@ async def cleaner_local(runtime, **kwargs): key_translator=key_translator, cache=cache, cache_key_prefix=cache_key_prefix, - name=e.name + name=e.name, + headers=e.headers ) result_functions[function_name] = raw_function cleaners = e._cleaners() @@ -299,3 +301,12 @@ def decorator(f): return decorator return register_cleaner + + +async def lookup_gids_by_emails(emails): + '''Fetch a set of google ids based on a list of emails + ''' + kvs = learning_observer.kvs.KVS() + keys = [f'email-studentID-mapping:{email}' for email in emails] + ids = await kvs.multiget(keys) + return ids diff --git a/learning_observer/learning_observer/log_event.py b/learning_observer/learning_observer/log_event.py index 4f16b686c..fb1b76a22 100644 --- a/learning_observer/learning_observer/log_event.py +++ b/learning_observer/learning_observer/log_event.py @@ -280,7 +280,7 @@ def debug_log(*args): # Print to file. Only helpful for development. if LogDestination.FILE in DEBUG_LOG_DESTINATIONS: - with open(paths.logs("debug.log"), "a") as fp: + with open(paths.logs("debug.log"), "a", encoding='utf-8') as fp: fp.write(message.strip() + "\n") # Ideally, we'd like to be able to log these somewhere which won't cause cascading failures. diff --git a/learning_observer/learning_observer/main.py b/learning_observer/learning_observer/main.py index 9d27fde3c..17486aa21 100644 --- a/learning_observer/learning_observer/main.py +++ b/learning_observer/learning_observer/main.py @@ -63,7 +63,7 @@ def configure_event_loop(): debug_log("Running without uvloop") -port = None +port = getattr(args, 'port', None) runmode = None diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index a1c09ab07..959693c87 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -88,7 +88,11 @@ COURSE_URL = 'https://classroom.googleapis.com/v1/courses' ROSTER_URL = 'https://classroom.googleapis.com/v1/courses/{courseid}/students' -pmss.parser('roster_source', parent='string', choices=['google', 'canvas', 'schoology', 'all', 'test', 'filesystem'], transform=None) +# TODO we need to treat canvas sources as individuals since they could +# come from different servers. Whereas schoology always calls into the +# same api endpoints. +# i.e. the roster_source name for canvas is config dependent +pmss.parser('roster_source', parent='string', choices=['google', 'x-canvas', 'schoology', 'all', 'test', 'filesystem'], transform=None) pmss.register_field( name='source', type='roster_source', @@ -412,17 +416,20 @@ async def run_additional_module_func(request, function_name, kwargs=None): user = await auth.get_active_user(request) + # Grab roster source based on user user_domain = learning_observer.util.get_domain_from_email(user.get('email')) - # TODO we ough to include provider in the attributes (need to test provider) provider = user.get('lti_context', {}).get('provider') - roster_source = settings.pmss_settings.source(types=['roster_data'], attributes={'domain': user_domain}) + roster_source = settings.pmss_settings.source(types=['roster_data'], attributes={'domain': user_domain, 'provider': provider}) # HACK/TODO since Canvas and Schoology are launched via an LTI, # we need to pass a course to the courses - LTI applications are # provided on a course-by-course basis, so fetching the courses # just needs to provide the current course context. - if roster_source in ['canvas', 'schoology'] and function_name == 'courses': + # HACK/TODO there ought to be a better way to determine if schoology or canvas is present + if ('canvas' in roster_source or 'schoology' in roster_source) and function_name == 'courses': kwargs['courseId'] = user.get('lti_context', {}).get('api_id') + if roster_source == 'schoology': + kwargs['clientId'] = settings.pmss_settings.client_id(types=['auth', 'lti', provider]) if roster_source not in learning_observer.integrations.INTEGRATIONS: debug_log(f'Provider `{roster_source}` not found in INTEGRATIONS. Available integrations: {learning_observer.integrations.INTEGRATIONS.keys()}') @@ -448,7 +455,7 @@ async def courselist(request): List all of the courses a teacher manages: Helper ''' course_list = await run_additional_module_func(request, 'courses') - if course_list: + if course_list is not None: return course_list # TODO if course_list is falsey, the following code may fail if there if ajax is not defined. @@ -495,7 +502,7 @@ async def courseroster(request, course_id): List all of the students in a course: Helper ''' roster = await run_additional_module_func(request, 'roster', kwargs={'courseId': course_id}) - if roster: + if roster is not None: return roster if not ajax: diff --git a/learning_observer/learning_observer/settings.py b/learning_observer/learning_observer/settings.py index 017da21c5..7df530caa 100644 --- a/learning_observer/learning_observer/settings.py +++ b/learning_observer/learning_observer/settings.py @@ -91,6 +91,11 @@ def parse_and_validate_arguments(): help='Launce the Learning Observer application. This can be used with `--ipython-console` and `--ipython-kernel`.', default=True, nargs='?', const=True, type=str_to_bool) + parser.add_argument( + '--port', + help='Which port to start the system on. Overrides any port listed in a configuration file.', + type=int) + args = parser.parse_args() if not os.path.exists(args.config_file): diff --git a/modules/writing_observer/VERSION b/modules/writing_observer/VERSION index 3fb21c1f9..c98f3678a 100644 --- a/modules/writing_observer/VERSION +++ b/modules/writing_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.05.16T17.31.36.630Z.e1505886.202505.berickson.lti.integration +0.1.0+2025.08.07T19.58.28.937Z.ed90597d.berickson.202507.new.lti.updates diff --git a/modules/writing_observer/writing_observer/module.py b/modules/writing_observer/writing_observer/module.py index dad2f01a3..009262cef 100644 --- a/modules/writing_observer/writing_observer/module.py +++ b/modules/writing_observer/writing_observer/module.py @@ -316,6 +316,11 @@ 'function': writing_observer.writing_analysis.languagetool_process, 'default': {'text': '', 'category_counts': {}, 'matches': [], 'subcategory_counts': {}, 'wordcounts': {}} }, + { + 'context': "org.mitros.writing_analytics", + 'scope': writing_observer.writing_analysis.student_scope, + 'function': writing_observer.writing_analysis.student_profile, + } ] diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index c2cb9b33b..7ebe5dd15 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -229,6 +229,18 @@ async def event_count(event, internal_state): return state, state +@kvs_pipeline(scope=student_scope, null_state={}) +async def student_profile(event, internal_state): + '''Store profile information for a given id + ''' + email = event['client'].get('chrome_identity', {}).get('email') + id = event['client'].get('auth', {}).get('safe_user_id') + if email != internal_state.get('email') or id != internal_state.get('user_id'): + state = {'email': email, 'google_id': id} + return state, state + return False, False + + @kvs_pipeline(scope=gdoc_scope, null_state={}) async def nlp_components(event, internal_state): '''HACK the reducers need this method to query data diff --git a/scripts/map_emails_to_ids_in_kvs.py b/scripts/map_emails_to_ids_in_kvs.py new file mode 100644 index 000000000..953269bbe --- /dev/null +++ b/scripts/map_emails_to_ids_in_kvs.py @@ -0,0 +1,28 @@ +import asyncio + +import learning_observer.kvs +import learning_observer.offline +import learning_observer.stream_analytics.helpers as sa_helpers + +import writing_observer.writing_analysis + + +def create_key(email): + return f'email-studentID-mapping:{email}' + + +async def run(): + learning_observer.offline.init('creds.yaml') + kvs = learning_observer.kvs.KVS() + reducer_function_name = sa_helpers.fully_qualified_function_name(writing_observer.writing_analysis.student_profile) + all_keys = await kvs.keys() + keys = [k for k in all_keys if 'Internal' in k and reducer_function_name in k] + values = await kvs.multiget(keys) + for profile in values: + if 'email' not in profile or 'google_id' not in profile: + continue + await kvs.set(create_key(profile['email']), profile['google_id']) + + +if __name__ == '__main__': + asyncio.run(run()) From 4d8e2b48fdde05c008af8acf9ca8755538c149d2 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Fri, 15 Aug 2025 09:29:30 -0400 Subject: [PATCH 044/327] added nginx conf --- VERSION | 2 +- devops/single_server_instances/README.md | 38 +++++++++++++ .../nginx.conf.example | 55 +++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 devops/single_server_instances/nginx.conf.example diff --git a/VERSION b/VERSION index 23e7294b1..5efb812a6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.08.10T20.53.47.175Z.cc7dc75e.berickson.202507.new.lti.updates +0.1.0+2025.08.15T13.29.30.819Z.f61cb8b1.master diff --git a/devops/single_server_instances/README.md b/devops/single_server_instances/README.md index 48ae6103d..f2123849b 100644 --- a/devops/single_server_instances/README.md +++ b/devops/single_server_instances/README.md @@ -34,3 +34,41 @@ Stop all instances: Logs are saved in `LOGFILE_DEST`, and PIDs are stored in `LOGFILE_DEST/pids`. You may need to change paths or permissions depending on your environment. + +## Nginx Settings + +The file `nginx.conf.example` provides a sample configration for Nginx when you start 4 instances of LO. +First, these settings split the incoming events and all other traffic between 2 upstream servers. +Each upstream server balances connections between 2 instances of Learning Observer. + +```text +Incoming Request + │ + ▼ ++---------------+ +| NGINX | ++---------------+ + │ + ▼ + Path starts + with "/wsapi/in/"? + ┌───────────────┐ + Yes│ │No + ▼ ▼ ++------------------+ +-----------------+ +| wsapi_in_backend | | general_backend | +| | | | ++-------+----------+ +--------+--------+ + │ │ + +----+----+ +----+----+ Balanced by least + | App 1 | | App 3 | connections `least_conn` + | :9001 | | :9003 | + +---------+ +---------+ + +----+----+ +----+----+ + | App 2 | | App 4 | + | :9002 | | :9004 | + +---------+ +---------+ +``` + +Note: these are settings to add to your nginx configuration. +You will likely have other settings, such as ssl certificates. diff --git a/devops/single_server_instances/nginx.conf.example b/devops/single_server_instances/nginx.conf.example new file mode 100644 index 000000000..571ba0f2d --- /dev/null +++ b/devops/single_server_instances/nginx.conf.example @@ -0,0 +1,55 @@ +# Upstreams +upstream wsapi_in_backend { + least_conn; + server 127.0.0.1:9001; + server 127.0.0.1:9002; +} + +upstream general_backend { + least_conn; + server 127.0.0.1:9003; + server 127.0.0.1:9004; +} + +# Simple CORS preflight detection +map $request_method $cors_preflight { + default 0; + OPTIONS 1; +} + +server { + # Common proxy headers for everything + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # --- Split route for /wsapi/in/ --- + location /wsapi/in/ { + proxy_pass http://wsapi_in_backend; + proxy_read_timeout 86400; + + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, HEAD'; + add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept'; + + if ($cors_preflight) { + return 200; + } + } + + # --- Everything else goes to general backend --- + location / { + proxy_pass http://general_backend; + proxy_read_timeout 86400; + + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, HEAD'; + add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, X-Requested-With, Content-Type, Accept'; + + if ($cors_preflight) { + return 200; + } + } +} From 381ec667a0e5267e63245032b07533a779c0b549 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Fri, 19 Sep 2025 10:50:00 -0400 Subject: [PATCH 045/327] restructured documentation (#236) --- VERSION | 2 +- autodocs/.gitignore | 1 + autodocs/api.rst | 1 + autodocs/concepts.rst | 18 +++++++++ autodocs/conf.py | 38 ++++++++++++++++++- autodocs/development.rst | 21 ---------- autodocs/docs | 1 + autodocs/how-to.rst | 14 +++++++ autodocs/images.rst | 10 ----- autodocs/index.rst | 19 +++++++--- autodocs/modules.rst | 14 +++---- autodocs/reference.rst | 16 ++++++++ autodocs/system_design.rst | 16 -------- autodocs/tutorials.rst | 11 ++++++ docs/{ => concepts}/architecture.md | 0 docs/{ => concepts}/auth.md | 0 docs/{ => concepts}/events.md | 0 docs/{ => concepts}/history.md | 0 docs/{ => concepts}/privacy.md | 0 docs/{ => concepts}/reducers.md | 0 docs/{ => concepts}/scaling.md | 0 docs/{ => concepts}/system_design.md | 6 +-- docs/{ => concepts}/technologies.md | 0 docs/{ => how-to}/config.md | 0 docs/{ => how-to}/dashboards.md | 0 docs/{ => how-to}/docker.md | 0 docs/{ => how-to}/extension.md | 0 docs/{ => how-to}/interactive_environments.md | 0 docs/{ => reference}/code_quality.md | 0 docs/{ => reference}/documentation.md | 0 docs/{ => reference}/linting.md | 0 docs/{ => reference}/testing.md | 0 docs/{ => reference}/versioning.md | 0 docs/{ => tutorials}/install.md | 0 docs/{ => tutorials}/workshop.md | 0 docs/{ => tutorials}/workshop_creds.md | 0 36 files changed, 121 insertions(+), 67 deletions(-) create mode 100644 autodocs/concepts.rst delete mode 100644 autodocs/development.rst create mode 120000 autodocs/docs create mode 100644 autodocs/how-to.rst delete mode 100644 autodocs/images.rst create mode 100644 autodocs/reference.rst delete mode 100644 autodocs/system_design.rst create mode 100644 autodocs/tutorials.rst rename docs/{ => concepts}/architecture.md (100%) rename docs/{ => concepts}/auth.md (100%) rename docs/{ => concepts}/events.md (100%) rename docs/{ => concepts}/history.md (100%) rename docs/{ => concepts}/privacy.md (100%) rename docs/{ => concepts}/reducers.md (100%) rename docs/{ => concepts}/scaling.md (100%) rename docs/{ => concepts}/system_design.md (96%) rename docs/{ => concepts}/technologies.md (100%) rename docs/{ => how-to}/config.md (100%) rename docs/{ => how-to}/dashboards.md (100%) rename docs/{ => how-to}/docker.md (100%) rename docs/{ => how-to}/extension.md (100%) rename docs/{ => how-to}/interactive_environments.md (100%) rename docs/{ => reference}/code_quality.md (100%) rename docs/{ => reference}/documentation.md (100%) rename docs/{ => reference}/linting.md (100%) rename docs/{ => reference}/testing.md (100%) rename docs/{ => reference}/versioning.md (100%) rename docs/{ => tutorials}/install.md (100%) rename docs/{ => tutorials}/workshop.md (100%) rename docs/{ => tutorials}/workshop_creds.md (100%) diff --git a/VERSION b/VERSION index 5efb812a6..a5a5ba116 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.08.15T13.29.30.819Z.f61cb8b1.master +0.1.0+2025.09.18T20.00.55.977Z.4d8e2b48.berickson.2025.document.restructure diff --git a/autodocs/.gitignore b/autodocs/.gitignore index 9c36f954f..90045b728 100644 --- a/autodocs/.gitignore +++ b/autodocs/.gitignore @@ -1,3 +1,4 @@ _build/ generated/ apidocs/ +module_readmes/ diff --git a/autodocs/api.rst b/autodocs/api.rst index ab7dcdf04..2d744d115 100644 --- a/autodocs/api.rst +++ b/autodocs/api.rst @@ -2,5 +2,6 @@ API === .. toctree:: + :maxdepth: 4 apidocs/index diff --git a/autodocs/concepts.rst b/autodocs/concepts.rst new file mode 100644 index 000000000..f6c06c98e --- /dev/null +++ b/autodocs/concepts.rst @@ -0,0 +1,18 @@ +Concepts +============= + +Explanations of key ideas, principles, and background knowledge. + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + docs/concepts/architecture.md + docs/concepts/auth.md + docs/concepts/events.md + docs/concepts/history.md + docs/concepts/privacy.md + docs/concepts/reducers.md + docs/concepts/scaling.md + docs/concepts/system_design.md + docs/concepts/technologies.md diff --git a/autodocs/conf.py b/autodocs/conf.py index 84d390af0..55ec33798 100644 --- a/autodocs/conf.py +++ b/autodocs/conf.py @@ -1,5 +1,8 @@ -import sys import os +import pathlib +import shutil +import sphinx.util +import sys # Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: @@ -9,7 +12,7 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = 'Learning Observer' -copyright = '2023, Bradley Erickson' +copyright = '2020-2025, Bradley Erickson' author = 'Bradley Erickson' # -- General configuration --------------------------------------------------- @@ -26,6 +29,9 @@ '../modules/writing_observer/writing_observer' ] +autodoc2_output_dir = 'apidocs' +autodoc2_member_order = 'bysource' + source_suffix = { '.rst': 'restructuredtext', '.md': 'markdown', @@ -40,3 +46,31 @@ html_theme = 'alabaster' html_static_path = ['_static'] + +LOGGER = sphinx.util.logging.getLogger(__name__) + + +def _copy_module_readmes(app): + """Populate ``module_readmes`` with module README files.""" + + docs_root = pathlib.Path(__file__).parent.resolve() + modules_root = docs_root.parent / 'modules' + destination_root = docs_root / 'module_readmes' + + if not modules_root.exists(): + LOGGER.warning("modules directory %s was not found", modules_root) + return + + if destination_root.exists(): + shutil.rmtree(destination_root) + destination_root.mkdir(parents=True, exist_ok=True) + + readme_paths = sorted(modules_root.glob('*/README.md')) + for readme_path in readme_paths: + module_name = readme_path.parent.name + destination_path = destination_root / f"{module_name}.md" + shutil.copy2(readme_path, destination_path) + + +def setup(app): + app.connect('builder-inited', _copy_module_readmes) diff --git a/autodocs/development.rst b/autodocs/development.rst deleted file mode 100644 index f32772264..000000000 --- a/autodocs/development.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _development: - -Development ------------ - -.. include:: ../docs/documentation.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/interactive_environments.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/privacy.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/config.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/linting.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/testing.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/versioning.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/technologies.md - :parser: myst_parser.sphinx_ diff --git a/autodocs/docs b/autodocs/docs new file mode 120000 index 000000000..6246dffc3 --- /dev/null +++ b/autodocs/docs @@ -0,0 +1 @@ +../docs/ \ No newline at end of file diff --git a/autodocs/how-to.rst b/autodocs/how-to.rst new file mode 100644 index 000000000..534354882 --- /dev/null +++ b/autodocs/how-to.rst @@ -0,0 +1,14 @@ +How-to +============= + +Practical instructions to solve specific problems or achieve goals. + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + docs/how-to/config.md + docs/how-to/dashboards.md + docs/how-to/docker.md + docs/how-to/extension.md + docs/how-to/interactive_environments.md diff --git a/autodocs/images.rst b/autodocs/images.rst deleted file mode 100644 index eae7f3bfa..000000000 --- a/autodocs/images.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. _images: - -Images -================= - -.. image:: ../docs/_images/block.png - -.. image:: ../docs/_images/lo_block.png - -.. image:: ../docs/_images/mmnd.png diff --git a/autodocs/index.rst b/autodocs/index.rst index df1bee6e3..d4509ecf0 100644 --- a/autodocs/index.rst +++ b/autodocs/index.rst @@ -12,14 +12,21 @@ per-student writing data, and aggegators to make dashboards. We've tested this in math and writing, but our focus is on writing process data. +Our documentation is organized into four main categories, each serving a different purpose. You can explore them below: + +- :doc:`Tutorials ` - Step-by-step guides to help you learn by doing. +- :doc:`Concepts ` - Explanations of key ideas and background knowledge. +- :doc:`How-To ` - Practical instructions to solve specific goals. +- :doc:`Reference ` - Detailed API/configuration information. + .. toctree:: - :maxdepth: 2 + :hidden: + :maxdepth: 3 - development - system_design - modules - extension - api + tutorials + concepts + how-to + reference Additional Information ---------------------- diff --git a/autodocs/modules.rst b/autodocs/modules.rst index dd2b9f08a..b267a6da9 100644 --- a/autodocs/modules.rst +++ b/autodocs/modules.rst @@ -1,11 +1,9 @@ -.. _modules: - Modules ----------- +The module READMEs are collected automatically during the Sphinx build. + +.. toctree:: + :maxdepth: 1 + :glob: -.. include:: ../modules/lo_dash_react_components/README.md - :parser: myst_parser.sphinx_ -.. include:: ../modules/lo_event/README.md - :parser: myst_parser.sphinx_ -.. include:: ../modules/writing_observer/README.md - :parser: myst_parser.sphinx_ + module_readmes/* diff --git a/autodocs/reference.rst b/autodocs/reference.rst new file mode 100644 index 000000000..5df3f458d --- /dev/null +++ b/autodocs/reference.rst @@ -0,0 +1,16 @@ +Reference +============= + +Detailed, structured information about APIs, configurations, and technical details. + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + docs/reference/code_quality.md + docs/reference/documentation.md + docs/reference/linting.md + docs/reference/testing.md + docs/reference/versioning.md + modules + api diff --git a/autodocs/system_design.rst b/autodocs/system_design.rst deleted file mode 100644 index 43c818d49..000000000 --- a/autodocs/system_design.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _system_design: - -System Design -------------- -.. include:: ../docs/architecture.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/auth.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/system_design.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/events.md - :parser: myst_parser.sphinx_ -.. include:: ../docs/reducers.md - :parser: myst_parser.sphinx_ -.. include:: ../learning_observer/learning_observer/communication_protocol/README.md - :parser: myst_parser.sphinx_ diff --git a/autodocs/tutorials.rst b/autodocs/tutorials.rst new file mode 100644 index 000000000..fb73b2ba8 --- /dev/null +++ b/autodocs/tutorials.rst @@ -0,0 +1,11 @@ +Tutorials +============= + +Step-by-step guides to help you learn by doing. + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + docs/tutorials/workshop.md + docs/tutorials/install.md diff --git a/docs/architecture.md b/docs/concepts/architecture.md similarity index 100% rename from docs/architecture.md rename to docs/concepts/architecture.md diff --git a/docs/auth.md b/docs/concepts/auth.md similarity index 100% rename from docs/auth.md rename to docs/concepts/auth.md diff --git a/docs/events.md b/docs/concepts/events.md similarity index 100% rename from docs/events.md rename to docs/concepts/events.md diff --git a/docs/history.md b/docs/concepts/history.md similarity index 100% rename from docs/history.md rename to docs/concepts/history.md diff --git a/docs/privacy.md b/docs/concepts/privacy.md similarity index 100% rename from docs/privacy.md rename to docs/concepts/privacy.md diff --git a/docs/reducers.md b/docs/concepts/reducers.md similarity index 100% rename from docs/reducers.md rename to docs/concepts/reducers.md diff --git a/docs/scaling.md b/docs/concepts/scaling.md similarity index 100% rename from docs/scaling.md rename to docs/concepts/scaling.md diff --git a/docs/system_design.md b/docs/concepts/system_design.md similarity index 96% rename from docs/system_design.md rename to docs/concepts/system_design.md index 6dc2a9ab5..e4a15ae4e 100644 --- a/docs/system_design.md +++ b/docs/concepts/system_design.md @@ -20,7 +20,7 @@ Our goal is to build a system which will: In other words: -![](_images/block.png) +![](../_images/block.png) Internally, the system takes a stream of events from each learner, and routes it to one or more analytics modules. Each of these modules @@ -37,7 +37,7 @@ through instructors for such an aggregation, and only aggregate where data has changed, so that with large numbers of instructors, the system merely updates dashboards less quickly: -![](_images/lo_block.png) +![](../_images/lo_block.png) Although at present, reduce operations are per-student, and aggregations per-class, in the future, we envision: @@ -51,6 +51,6 @@ aggregations per-class, in the future, we envision: Data will be stored in a git-like Merkle tree format: -![](_images/mmnd.png) +![](../_images/mmnd.png) We'll document this in more detail later. \ No newline at end of file diff --git a/docs/technologies.md b/docs/concepts/technologies.md similarity index 100% rename from docs/technologies.md rename to docs/concepts/technologies.md diff --git a/docs/config.md b/docs/how-to/config.md similarity index 100% rename from docs/config.md rename to docs/how-to/config.md diff --git a/docs/dashboards.md b/docs/how-to/dashboards.md similarity index 100% rename from docs/dashboards.md rename to docs/how-to/dashboards.md diff --git a/docs/docker.md b/docs/how-to/docker.md similarity index 100% rename from docs/docker.md rename to docs/how-to/docker.md diff --git a/docs/extension.md b/docs/how-to/extension.md similarity index 100% rename from docs/extension.md rename to docs/how-to/extension.md diff --git a/docs/interactive_environments.md b/docs/how-to/interactive_environments.md similarity index 100% rename from docs/interactive_environments.md rename to docs/how-to/interactive_environments.md diff --git a/docs/code_quality.md b/docs/reference/code_quality.md similarity index 100% rename from docs/code_quality.md rename to docs/reference/code_quality.md diff --git a/docs/documentation.md b/docs/reference/documentation.md similarity index 100% rename from docs/documentation.md rename to docs/reference/documentation.md diff --git a/docs/linting.md b/docs/reference/linting.md similarity index 100% rename from docs/linting.md rename to docs/reference/linting.md diff --git a/docs/testing.md b/docs/reference/testing.md similarity index 100% rename from docs/testing.md rename to docs/reference/testing.md diff --git a/docs/versioning.md b/docs/reference/versioning.md similarity index 100% rename from docs/versioning.md rename to docs/reference/versioning.md diff --git a/docs/install.md b/docs/tutorials/install.md similarity index 100% rename from docs/install.md rename to docs/tutorials/install.md diff --git a/docs/workshop.md b/docs/tutorials/workshop.md similarity index 100% rename from docs/workshop.md rename to docs/tutorials/workshop.md diff --git a/docs/workshop_creds.md b/docs/tutorials/workshop_creds.md similarity index 100% rename from docs/workshop_creds.md rename to docs/tutorials/workshop_creds.md From fb5631b36627b02b73c52d9d759d93cde07b84c8 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Mon, 22 Sep 2025 15:03:01 -0400 Subject: [PATCH 046/327] Updated extension to only connect when relevant tabs are present (#235) * updated extension to only connect when relevant tabs are present * updated urls * added terminate event to the server to close files --- VERSION | 2 +- extension/writing-process/src/background.js | 130 +++++++++++------- extension/writing-process/src/manifest.json | 3 +- extension/writing-process/src/writing.js | 13 ++ learning_observer/VERSION | 2 +- .../incoming_student_event.py | 61 ++++++-- 6 files changed, 151 insertions(+), 60 deletions(-) diff --git a/VERSION b/VERSION index a5a5ba116..7e456cd3f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.18T20.00.55.977Z.4d8e2b48.berickson.2025.document.restructure +0.1.0+2025.09.15T18.58.19.025Z.cb6381ff.berickson.202509.extension.fixes diff --git a/extension/writing-process/src/background.js b/extension/writing-process/src/background.js index 5396ce383..236a91d3e 100644 --- a/extension/writing-process/src/background.js +++ b/extension/writing-process/src/background.js @@ -28,34 +28,54 @@ import { localStorageInfo, sessionStorageInfo } from 'lo_event/lo_event/metadata // } /* and other async logic */); // websocketLogger( callback ); +// Track which tabs currently have an active content script and the state of +// our logger so that we only initialize logging when needed. +const activeContentTabs = new Set(); +let loEventActive = false; +let loggers = []; +const manifestVersion = chrome.runtime.getManifest().version; + + // We are not sure if this should be done within `websocketLogger()`'s `init` // or one level up. -const loggers = [ - consoleLogger(), - websocketLogger(WEBSOCKET_SERVER_URL) -] - -loEvent.init( - 'org.mitros.writing_analytics', - '0.01', - loggers, - { - debugLevel: loEventDebug.LEVEL.SIMPLE, - metadata: [ - browserInfo(), - chromeAuth(), - localStorageInfo(), - sessionStorageInfo(), - ] - } -); -loEvent.go(); +function startLogger () { + if (loEventActive) return; + loggers = [ + consoleLogger(), + websocketLogger(WEBSOCKET_SERVER_URL) + ]; + loEvent.init( + 'org.mitros.writing_analytics', + manifestVersion, + loggers, + { + debugLevel: loEventDebug.LEVEL.SIMPLE, + // TODO document what we have currently and what we want + metadata: [ + browserInfo(), + chromeAuth(), + localStorageInfo(), + sessionStorageInfo(), + ] + } + ); + loEvent.go(); + loEventActive = true; + loEvent.logEvent('extension_loaded', {}); + logFromServiceWorker('Extension loaded'); +} + +function stopLogger () { + if (!loEventActive) return; + loEvent.logEvent('terminate', {}); + loEventActive = false; +} // Function to serve as replacement for // chrome.extension.getBackgroundPage().console.log(event); because it is not allowed in V3 // It logs the event to the console for debugging. function logFromServiceWorker(event) { - console.log(event); + console.log(event); } function this_a_google_docs_save(request) { @@ -69,7 +89,7 @@ function this_a_google_docs_save(request) { went from a conservative regexp to a liberal one. We should confirm this never catches extra requests, though. */ - if(request.url.match(/.*:\/\/docs\.google\.com\/document\/(.*)\/save/i)) { + if (request.url.match(/.*:\/\/docs\.google\.com\/document\/(.*)\/save/i)) { return true; } return false; @@ -85,7 +105,7 @@ function this_a_google_docs_bind(request) { https://stackoverflow.com/questions/6831916/is-it-possible-to-monitor-http-traffic-in-chrome-using-an-extension#6832018 */ - if(request.url.match(/.*:\/\/docs\.google\.com\/document\/(.*)\/bind/i)) { + if (request.url.match(/.*:\/\/docs\.google\.com\/document\/(.*)\/bind/i)) { return true; } return false; @@ -106,10 +126,29 @@ chrome.storage.sync.get(['process_server'], function(result) { // Listen for the keystroke messages from the page script and forward to the server. chrome.runtime.onMessage.addListener( - function(request, sender, sendResponse) { - //chrome.extension.getBackgroundPage().console.log("Got message"); - //chrome.extension.getBackgroundPage().console.log(request); - //console.log(sender); + function (request, sender, sendResponse) { + // Lifecycle messages from content scripts manage the logger state + if (request?.type === 'content_script_ready') { + if (sender.tab?.id !== undefined) { + activeContentTabs.add(sender.tab.id); + if (!loEventActive) { + startLogger(); + } + } + return; + } else if (request?.type === 'content_script_unloading') { + if (sender.tab?.id !== undefined) { + activeContentTabs.delete(sender.tab.id); + if (activeContentTabs.size === 0) { + stopLogger(); + } + } + return; + } + // Forward analytics events only when the logger is active + if (!loEventActive) { + return; + } request['wa_source'] = 'client_page'; loEvent.logEvent(request['event'], request); } @@ -142,31 +181,35 @@ chrome.webRequest.onBeforeRequest.addListener( especially new pages. They do inject a lot of noise, though, and from there, being able to easily ignore these is nice. */ - function(request) { + function (request) { + // No logger availaber + if (!loEventActive) { + return; + } //chrome.extension.getBackgroundPage().console.log("Web request url:"+request.url); var formdata = {}; let event; - if(request.requestBody) { + if (request.requestBody) { formdata = request.requestBody.formData; } - if(!formdata) { + if (!formdata) { formdata = {}; } - if(RAW_DEBUG) { + if (RAW_DEBUG) { loEvent.logEvent('raw_http_request', { - 'url': request.url, + 'url': request.url, 'form_data': formdata }); } - if(this_a_google_docs_save(request)){ + if (this_a_google_docs_save(request)) { //chrome.extension.getBackgroundPage().console.log("Google Docs bundles "+request.url); try { /* We should think through which time stamps we should log. These are all subtly different: browser event versus request timestamp, as well as user time zone versus GMT. */ event = { - 'doc_id': googledocs_id_from_url(request.url), + 'doc_id': googledocs_id_from_url(request.url), 'url': request.url, 'bundles': JSON.parse(formdata.bundles), 'rev': formdata.rev, @@ -174,12 +217,12 @@ chrome.webRequest.onBeforeRequest.addListener( }; logFromServiceWorker(event); loEvent.logEvent('google_docs_save', event); - } catch(err) { + } catch (err) { /* Oddball events, like text selections. */ event = { - 'doc_id': googledocs_id_from_url(request.url), + 'doc_id': googledocs_id_from_url(request.url), 'url': request.url, 'formdata': formdata, 'rev': formdata.rev, @@ -187,10 +230,10 @@ chrome.webRequest.onBeforeRequest.addListener( }; loEvent.logEvent('google_docs_save_extra', event); } - } else if(this_a_google_docs_bind(request)) { + } else if (this_a_google_docs_bind(request)) { logFromServiceWorker(request); } else { - logFromServiceWorker("Not a save or bind: "+request.url); + logFromServiceWorker("Not a save or bind: " + request.url); } }, { urls: ["*://docs.google.com/*"] }, @@ -202,10 +245,10 @@ chrome.webRequest.onBeforeRequest.addListener( chrome.runtime.onInstalled.addListener(reinjectContentScripts); async function reinjectContentScripts() { for (const contentScript of chrome.runtime.getManifest().content_scripts) { - for (const tab of await chrome.tabs.query({url: contentScript.matches})) { + for (const tab of await chrome.tabs.query({ url: contentScript.matches })) { // re-inject content script await chrome.scripting.executeScript({ - target: {tabId: tab.id, allFrames: true}, + target: { tabId: tab.id, allFrames: true }, files: contentScript.js, }, function () { if (!chrome.runtime.lastError) { @@ -215,10 +258,3 @@ async function reinjectContentScripts() { } } } - -// Let the server know we've loaded. -loEvent.logEvent("extension_loaded", {}); - -// And let the console know we've loaded -// chrome.extension.getBackgroundPage().console.log("Loaded"); remove -logFromServiceWorker("Loaded"); diff --git a/extension/writing-process/src/manifest.json b/extension/writing-process/src/manifest.json index f663bf58f..ad7c064a0 100644 --- a/extension/writing-process/src/manifest.json +++ b/extension/writing-process/src/manifest.json @@ -17,7 +17,8 @@ "storage", "nativeMessaging", "scripting", - "activeTab" + "activeTab", + "tabs" ], "icons": { "48": "assets/lousy-fountain-pen-48.png" diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index f318f404d..1e63f9df1 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -10,6 +10,19 @@ import { googledocs_id_from_url, treeget } from './writing_common'; General Utility Functions */ +// Notify the service worker that this content script is active. We also +// provide a hook to let the service worker know when the script is about to +// unload so it can perform any necessary cleanup (for example, shutting down +// loggers when no tabs are active). +if (chrome.runtime?.id !== undefined) { + chrome.runtime.sendMessage({ type: 'content_script_ready' }); + window.addEventListener('beforeunload', () => { + if (chrome.runtime?.id !== undefined) { + chrome.runtime.sendMessage({ type: 'content_script_unloading' }); + } + }); +} + function log_error(error_string) { /* We should send errors to the server, but for now, we diff --git a/learning_observer/VERSION b/learning_observer/VERSION index 5f2ef51aa..7e456cd3f 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.08.07T20.03.33.270Z.c17a54d7.berickson.202507.new.lti.updates +0.1.0+2025.09.15T18.58.19.025Z.cb6381ff.berickson.202509.extension.fixes diff --git a/learning_observer/learning_observer/incoming_student_event.py b/learning_observer/learning_observer/incoming_student_event.py index b8a996b25..53479bbd6 100644 --- a/learning_observer/learning_observer/incoming_student_event.py +++ b/learning_observer/learning_observer/incoming_student_event.py @@ -187,6 +187,14 @@ async def handle_incoming_client_event(metadata): # The adapter allows us to handle old event formats adapter = learning_observer.adapters.adapter.EventAdapter() + handler_log_closed = False + + def close_handler_log(): + nonlocal handler_log_closed + if not handler_log_closed: + log_event.close_logfile(filename) + handler_log_closed = True + async def handler(request, client_event): ''' This is the handler for incoming client events. @@ -206,11 +214,16 @@ async def handler(request, client_event): log_event.log_event( json.dumps(event, sort_keys=True), filename, preencoded=True, timestamp=True) + if client_event.get("event") == "terminate": + debug_log("Terminate event received; closing handler log file") + close_handler_log() + return [] await pipeline(event) # when the handler garbage collected (no more events are being passed through), # close the log file associated with this connection - weakref.finalize(handler, log_event.close_logfile, filename) + weakref.finalize(handler, close_handler_log) + handler.close = close_handler_log return handler @@ -291,20 +304,32 @@ def decode_and_log_event(msg): ) COUNT += 1 + decoder_log_closed = False + + def close_decoder_logfile(): + nonlocal decoder_log_closed + if not decoder_log_closed: + log_event.close_logfile(filename) + decoder_log_closed = True + async def decode_and_log_event(events): ''' Take an aiohttp web sockets message, log it, and return a clean event. ''' - async for msg in events: - if isinstance(msg, dict): - json_event = msg - else: - json_event = json.loads(msg.data) - log_event.log_event(json_event, filename=filename) - yield json_event - # done processing events, can close logfile now - log_event.close_logfile(filename) + try: + async for msg in events: + if isinstance(msg, dict): + json_event = msg + else: + json_event = json.loads(msg.data) + log_event.log_event(json_event, filename=filename) + yield json_event + finally: + # done processing events, can close logfile now + close_decoder_logfile() + + decode_and_log_event.close = close_decoder_logfile return decode_and_log_event @@ -434,6 +459,21 @@ async def decode_lock_fields(events): event.update(lock_fields) yield event + async def handle_terminate_events(events): + '''Stop processing when a terminate event is received.''' + async for event in events: + if event.get('event') == 'terminate': + debug_log('Terminate event received; shutting down connection and cleaning up logs.') + handler_close = getattr(event_handler, 'close', None) + if callable(handler_close): + handler_close() + decoder_close = getattr(decoder_and_logger, 'close', None) + if callable(decoder_close): + decoder_close() + await ws.close() + return + yield event + async def filter_blacklist_events(events): '''This function stops the event pipeline if sources should be blocked. @@ -498,6 +538,7 @@ async def process_ws_message_through_pipeline(): events = process_message_from_ws() events = decoder_and_logger(events) events = decode_lock_fields(events) + events = handle_terminate_events(events) events = handle_auth_events(events) events = filter_blacklist_events(events) events = process_blob_storage_events(events) From eb453bf71b8ec57b94888d8aab21abcfe2085e95 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 23 Sep 2025 11:55:02 -0400 Subject: [PATCH 047/327] added some tutorials --- Makefile | 8 - VERSION | 2 +- autodocs/tutorials.rst | 2 +- docs/tutorials/cookiecutter-module.md | 83 +++++++++ docs/tutorials/install.md | 167 +++++++++++------- extension/writing-process/.gitignore | 2 + learning_observer/VERSION | 2 +- .../learning_observer/rosters.py | 4 + 8 files changed, 199 insertions(+), 71 deletions(-) create mode 100644 docs/tutorials/cookiecutter-module.md diff --git a/Makefile b/Makefile index 212c25dc6..a45c90b55 100644 --- a/Makefile +++ b/Makefile @@ -57,14 +57,6 @@ install-dev: install-packages: pip install -e learning_observer/[${PACKAGES}] - # Just a little bit of dependency hell... - # On Python3.11 with tensorflow, we get some odd errors - # regarding compatibility with `protobuf`. Some installation - # files are missing from the protobuf binary on pip. - # Using the `--no-binary` option includes all files. - pip uninstall -y protobuf - pip install --no-binary=protobuf protobuf==4.25 - # Testing commands test: @if [ -z "$(PKG)" ]; then echo "No module specified, please try again with \"make test PKG=path/to/module\""; exit 1; fi diff --git a/VERSION b/VERSION index 7e456cd3f..0fbb6683f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.15T18.58.19.025Z.cb6381ff.berickson.202509.extension.fixes +0.1.0+2025.09.23T15.55.02.340Z.fb5631b3.master diff --git a/autodocs/tutorials.rst b/autodocs/tutorials.rst index fb73b2ba8..580567507 100644 --- a/autodocs/tutorials.rst +++ b/autodocs/tutorials.rst @@ -7,5 +7,5 @@ Step-by-step guides to help you learn by doing. :maxdepth: 1 :titlesonly: - docs/tutorials/workshop.md docs/tutorials/install.md + docs/tutorials/cookiecutter-module.md diff --git a/docs/tutorials/cookiecutter-module.md b/docs/tutorials/cookiecutter-module.md new file mode 100644 index 000000000..97245f6e5 --- /dev/null +++ b/docs/tutorials/cookiecutter-module.md @@ -0,0 +1,83 @@ +# Tutorial: Build and Run a Module from the Cookiecutter Template + +This tutorial walks through generating a new Learning Observer module from the cookiecutter template, installing it, and seeing it run inside the system. We assume you already have the development environment installed and can start the stack with `make run`. + +## 1. Prepare your environment + +1. Activate the Python environment you use for Learning Observer development. +2. Make sure the `cookiecutter` command is available. If you have not installed it yet, run: + + ```bash + pip install cookiecutter + ``` + +3. From the repository root, change into the `modules/` directory: + + ```bash + cd modules/ + ``` + +## 2. Generate a module from the template + +1. Run cookiecutter against the Learning Observer template: + + ```bash + cookiecutter lo_template_module/ + ``` + +2. Fill in the prompts with information for your module. At minimum you will supply: + * **project_name** – Human-friendly title that appears in the UI. + * **project_short_description** – A one-line summary shown with the module. + * **reducer** – The name of the default reducer function the template creates. +3. Cookiecutter writes a new module directory inside `modules/`. If you entered `Revision Counter` as the name, the generated package would live in `modules/revision_counter/`. + +The template scaffolds all of the pieces Learning Observer expects, including a reducer, Dash layout, entry points, and packaging configuration so the module can be installed like any other Python package. You'll find these generated files within `modules//`, including `module.py`, `reducers.py`, the Dash dashboard, and the accompanying `setup.cfg` that defines how the package is exposed. + +## 3. Explore the generated code (optional but recommended) + +1. Inspect `module.py` to see the metadata exposed to Learning Observer, the default execution DAG, reducer list, and Dash page configuration. The file lives in `modules///module.py`. +2. Review `reducers.py` to understand how the template reducer counts events and where to extend it for your own analytics. You can find it next to `module.py` in the generated package directory. +3. Open `dash_dashboard.py` to learn how the generated layout publishes the reducer output on a Dash page. Use this as a starting point for your own visualizations. + +## 4. Install the module in editable mode + +Installing the module registers its entry point so Learning Observer can discover it. From the repository root run: + +```bash +pip install -e modules// +``` + +Replace `` with the directory created in step 2 (for example, `modules/revision_counter/`). The template’s `setup.cfg` already declares the `lo_modules` entry point that exposes `module.py` to the system, so no additional registration is required. + +## 5. Start Learning Observer + +1. Return to a terminal at the repository root. +2. Launch the stack: + + ```bash + make run + ``` + +3. Wait for the services to come up, then open `http://localhost:8888/` in a browser. Your new module should appear on the home screen because the template registers it as a course dashboard card by default inside `module.py`. + +## 6. Stream sample data to exercise the module + +To see live data, send synthetic writing events using the helper script. + +1. Open a second terminal with your environment activated. +2. Run the streaming script from the repository root: + + ```bash + python scripts/stream_writing.py --streams=5 + ``` + + This sends five concurrent simulated students worth of Google Docs events to the default local endpoint using the helper found at `scripts/stream_writing.py`. +3. Refresh your browser. The default reducer counts incoming events, so you should see the totals increase on the Dash page included with the template. Both the reducer and the dashboard live alongside `module.py` in your generated package. + +## 7. Next steps + +* Customize the reducer in `reducers.py` to compute the metrics your dashboard requires. +* Expand the Dash layout to visualize your new metrics. +* Add additional reducers, exports, or pages to `module.py` as your module grows. + +With these steps you have a working, template-based module running end-to-end inside Learning Observer. From here you can iterate on analytics and UI changes quickly by editing the generated files and reloading the server. diff --git a/docs/tutorials/install.md b/docs/tutorials/install.md index 0d3099820..7b08e81c6 100644 --- a/docs/tutorials/install.md +++ b/docs/tutorials/install.md @@ -1,73 +1,120 @@ -# Formative Process for Writing - Installation Instructions -Last updated: 16-JAN-2020 +# Tutorial: Install + +Use this tutorial to get the Learning Observer running on your machine. It walks you through the exact commands to run and the order to run them in, so you can follow along step by step. + +## Before you begin + +Make sure your computer meets these requirements: + +1. **Operating system** – A Unix-style system works best. We regularly test on Ubuntu. macOS generally works as well. Windows users should install the project inside [Windows Subsystem for Linux (WSL)](workshop/wsl-install.md) before continuing. +2. **Python** – Install Python 3.10 or 3.11 (any version newer than 3.9 is expected to work). +3. **Package manager (recommended)** – Have a virtual environment tool ready. We prefer [`virtualenvwrapper`](https://pypi.org/project/virtualenvwrapper/), but you can use `python -m venv`, Conda, or another tool you like. +4. **Optional tools** – + - [Valkey](https://valkey.io/) or Redis as a key–value store if you plan to run production-style deployments (this tutorial uses on-disk storage instead). + - Docker 26.1 if you want to experiment with the container-based workflow. The steps below focus on the native installation. + +Have two terminal windows or tabs open. We will run the server in one and use the other for helper scripts. + +## Step 1 – Download the project + +1. Open a terminal and clone the repository: + + ```bash + git clone https://github.com/ETS-Next-Gen/writing_observer.git lo_tutorial + ``` + + If you have an SSH key configured with GitHub, you can use: + + ```bash + git clone git@github.com:ETS-Next-Gen/writing_observer.git lo_tutorial + ``` + +2. Change into the new directory: + + ```bash + cd lo_tutorial/ + ``` + + All commands that follow run from this repository root unless the tutorial notes otherwise. + +## Step 2 – Create and activate a Python environment + +Choose one of the options below to create an isolated environment for the tutorial. + +*With `virtualenvwrapper`:* -## Install Chrome Extension -* Set up a github SSH key. -* Download the extension code: ```bash -cd -git clone https://github.com/ETS-Next-Gen/writing_analysis.git writing_analysis +mkvirtualenv lo_env +workon lo_env ``` -* Navigate to `chrome://extensions`. -* Click on "Load Unpacked". Select ~/writing_anlysis/extensions - -## Create an AWS account and an EC2 instance. -* Select Ubuntu, nano AMI. The cost should be 0.5 cents per hour. -* In security groups, add HTTP, HTTPS rules. Open up only to your computer's IP address (the client). -* Launch instance. -* Suppose your instance public DNS is {ec2_ip}, e.g., ec2-18-223-122-172.us-east-2.compute.amazonaws.com. -* Create aSSH key pair, save PEM file say under ~/.ssh, chmod to u+r. - -## Set up the EC2 instance. -* SSH into the machine: `bash ssh -i {pem_file} ubuntu@{ec2_ip}`. -* (Optional) Create a user account: sudo useradd {user} -* Download the server code (same repository as the extension): + +*With `venv` (built into Python):* + ```bash -cd -git clone https://github.com/ETS-Next-Gen/writing_analysis.git writing_analysis +python -m venv lo_env +source lo_env/bin/activate ``` -* Install Ansible. + +Verify that the shell prompt shows the environment name before continuing. + ```bash -sudo apt-get update -sudo apt-get upgrade -sudo apt-get install ansible -```` -* Configure Ansible. -sudo pico /etc/ansible/hosts -Add -``` -[localhost] -127.0.0.1 -``` -* `cd ~/writing_analysis/configuration`. -* Run `sudo ansible-playbook local.yaml`. This may take a while on an EC2 nanon machine. -If all goes well, you should see an output with no errors, like this: +(lo_env) user@pc:~/lo_tutorial$ ``` -bash -... -PLAY RECAP ****************************************************************************************** -127.0.0.1 : ok=5 changed=4 unreachable=0 failed=0 -``` -* Navigate to http://{ec2_ip}; you should see the message "Welcome to nginx!" if it's working. -## Obtain a free domain name -* Go to noip.com. -* Sign up +## Step 3 – Install Python dependencies + +1. Make sure `pip` itself is up to date (optional but helpful): + + ```bash + pip install --upgrade pip + ``` + +2. Install all project requirements: + + ```bash + make install + ``` + + This command downloads Python packages and builds local assets. Depending on your network speed, it can take a few minutes. + +## Step 4 – Apply the workshop configuration + +The project ships with an example configuration tailored for workshops. Copy it into place so the application starts with sensible defaults such as file-based storage and relaxed authentication. -## Obtain a free SSL Certificate Using Certbot -* Run the following commands: ```bash -sudo apt-get install software-properties-common -Sudo add-apt-repository universe -sudo add-apt-repository ppa:certbot/certbot -sudo apt-get update -sudo apt-get install certbot python-certbot-nginx -``` +cp learning_observer/learning_observer/creds.yaml.workshop learning_observer/creds.yaml ``` -bash -sudo certbot --nginx + +If you are curious about the changes, compare it with the example file: + +```bash +diff -u learning_observer/learning_observer/creds.yaml.example learning_observer/creds.yaml ``` --- Put in your {mydomain}.hopto.org address. --- Choose 1 - no redirect. -## Stand up a backend server on the EC2 instance. +## Step 5 – Start the Learning Observer + +1. Launch the development server: + + ```bash + make run + ``` + +2. The first run performs several setup tasks (such as generating role files), so it may exit after downloading dependencies. When the command finishes, run it again: + + ```bash + make run + ``` + + Repeat until the command reports that the system is ready and stays running. + +## Step 6 – Verify everything worked + +Once the server is running, open a browser and go to one of the following URLs: + +- `http://localhost:8888/` +- `http://0.0.0.0:8888/` +- `http://127.0.0.1:8888/` + +You should see the Learning Observer dashboard with a list of courses and analytics modules. Because the workshop configuration disables authentication, you can immediately click around and start experimenting. + +## Next steps diff --git a/extension/writing-process/.gitignore b/extension/writing-process/.gitignore index 9a7d305e4..5905017c8 100644 --- a/extension/writing-process/.gitignore +++ b/extension/writing-process/.gitignore @@ -1,3 +1,5 @@ dist/ node_modules/ **/*.bundle.js* +public/ +release.zip diff --git a/learning_observer/VERSION b/learning_observer/VERSION index 7e456cd3f..0fbb6683f 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.09.15T18.58.19.025Z.cb6381ff.berickson.202509.extension.fixes +0.1.0+2025.09.23T15.55.02.340Z.fb5631b3.master diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 959693c87..00ee86f7b 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -421,6 +421,10 @@ async def run_additional_module_func(request, function_name, kwargs=None): provider = user.get('lti_context', {}).get('provider') roster_source = settings.pmss_settings.source(types=['roster_data'], attributes={'domain': user_domain, 'provider': provider}) + # Do not try to run module functions for these roster sources + if roster_source in ['all', 'test', 'filesystem']: + return None + # HACK/TODO since Canvas and Schoology are launched via an LTI, # we need to pass a course to the courses - LTI applications are # provided on a course-by-course basis, so fetching the courses From dfa95f90c06f85e2cac266593b09a62d28054b0e Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 23 Sep 2025 17:20:29 -0400 Subject: [PATCH 048/327] updated extension documentation --- VERSION | 2 +- docs/how-to/extension.md | 160 ++++++++++++++++++++++++++------------- 2 files changed, 108 insertions(+), 54 deletions(-) diff --git a/VERSION b/VERSION index 0fbb6683f..bf4718cc6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.23T15.55.02.340Z.fb5631b3.master +0.1.0+2025.09.23T21.20.29.794Z.eb453bf7.master diff --git a/docs/how-to/extension.md b/docs/how-to/extension.md index ea085c1ae..a89476ea0 100644 --- a/docs/how-to/extension.md +++ b/docs/how-to/extension.md @@ -1,82 +1,136 @@ # Writing Observer Extension -This is an extension which collects data from the client. +The Writing Observer browser extension collects rich event data while a writer works in Google Docs so that the Learning Observer platform can analyse the writing process. The extension code lives in [`extension/writing-process/`](../../extension/writing-process/) and is packaged with [Extension CLI](https://oss.mobilefirst.me/extension-cli/) and webpack. -## Google Churn and Breakage +## Project Layout -Google regularly changes how they do things, breaking extensions like -this one. We had major changes for the transition from -[Manifest V2 to Manifest V3](https://developer.chrome.com/docs/extensions/mv3/mv2-sunset/). -Google was trying to cripple ad blockers, which made extensions like -these much harder to write and maintain. This change, as is very -Googly, was mandated by Google before Google properly documented Manifest V3. +The directory contains a standard Extension CLI project: -2. Google changed [rendering on the -front-end](https://workspaceupdates.googleblog.com/2021/05/Google-Docs-Canvas-Based-Rendering-Update.html) -such that our code to grab text is broken. On the whole, this is less -harmful, since we never relied on this code path. We grabbed visible -on-screen text to have ground truth data for debugging how we -reconstruct documents. We can make due without that, but it'd be nice -to fix at some point. In the design of the system, we did not count on -this text to be stable (it's used for debugging). We primarily rely on -document change events and the Google Docs API. +- `src/` - extension source files. Webpack writes the bundled content scripts and background bundles back into this directory as `*.bundle.js` files. + - `writing.js` and `writing_common.js` run in the Google Docs page and capture keystrokes and context. + - `background.js` and `service_worker.js` coordinate logging, open the websocket connection to Learning Observer, and respond to browser lifecycle events. + - `pages/` stores the popup, options page, and other extension UI assets. +- `assets/` - icons used by the published extension. +- `webpack.config.js` - bundles the source code and excludes Node-specific dependencies required by the `lo-event` package. +- `test/` - placeholder for unit tests executed by the Extension CLI test runner. -## System Design +## Prerequisites -* `writing_common.js` has common utility functions -* `writing.js` sits on each page, and listens for keystrokes. It also - collects other data, such as document title, or commenting activity. - Only the keystroke logging is well-tested. This is sent onto - `background.js` -* `background.js` used to be once per browser, and maintain a - websocket connection to the server. It also listened for Google AJAX - events which contain document edits. This was changed with Manifest - V3 and still needs to be correctly documented. +- Node.js and npm (the project was last updated with Node 18.x, though later LTS versions should also work). +- Google Chrome for manual testing. +- Access to the [`lo-event`](../../modules/lo_event/) package, which provides messaging utilities that the extension uses to communicate with Learning Observer services. -The document edits are short snippets, which aggregate a small number -of keystrokes (e.g. a couple hundred milliseconds or typically 1-2 -keystrokes). These are our primary source of data. The keystroke -collection on each page is more precise (we have timestamps for each -keystroke), and helpful for some typing speed estimations, but -currently lacks a lot of context we would need to e.g. reconstruct -documents. +## Install Dependencies -Each file has more in-depth documentation. +Install everything from inside the extension directory: -## Setup information +```bash +cd extension/writing-process +npm install +``` + +The `lo-event` dependency is declared as a `file:` package in `package.json`, so it is linked from the local repository when you install. If `npm install` cannot resolve it automatically, install it explicitly: + +```bash +npm install ../../modules/lo_event +# or link it for iterative development +cd ../../modules/lo_event +npm link +cd - +npm link lo-event +``` + +## Everyday development tasks + +Most workflows are exposed through npm scripts. Run them from `extension/writing-process/`. -The extension is built as a node project. This structure helps us allow for testing and for the use of external node packages. +### Bundle source files -### Dependencies +Use webpack to generate the bundled scripts that the extension loads at runtime. -For building the extension, we rely on a handful of build tools, like webpack to bundle the code together. +```bash +npm run bundle # one-off build of background.js, writing.js, etc. +npm run bundle:watch # continuously rebuild while editing +``` + +The bundles are written to `src/*.bundle.js`. Ensure these bundles exist before packaging the extension or running tests. -The extension has a dependency on the LOEvent package, located at `/modules/lo_event`. The LOEvent package handles passing messages from Learning Observer data sources and the Learning Observer server. +### Run the extension in development -The LOEvent package has a handful of downstream dependencies that are used when it does not have access to a browser environment. These are used to mirror browser behavior in testing environments. +Extension CLI can watch the project, rebuild on changes, and output an unpacked extension in `dist/`. -When building the extension, we found that these were not always ignored when bundling the extension together. To ignore the dependencies on building the extension, we had to add them to the `externals` portion of the `webpack.config.js` on the extension itself. +```bash +npm run ext:start # Chrome/Chromium development build +``` -### Installation +Both commands keep watching the filesystem and rebuild when files change. Load the unpacked directory they produce (see [Loading the extension locally](#loading-the-extension-locally)). -To get started, run the following: +### Run automated tests ```bash -cd extention/writing-process -npm install +npm run ext:test # run the Extension CLI test suite +npm run coverage # generate an lcov coverage report via nyc +``` + +The default tests under `test/` are minimal; extend them as new functionality is added. + +### Clean build artefacts and generate docs + +```bash +npm run ext:clean # remove dist/ +npm run ext:docs # produce API docs in public/documentation/ +npm run ext:sync # refresh Extension CLI config files ``` -Since the LOEvent package is not published, you'll need to install it locally via the `npm link` command. If there are any issues with this, `npm pack`+`npm install` is more robust, but more cumbersome since it needs to be rerun whenever `lo_event` changes. See the LOEvent installation for more information about this process. +Use these scripts before packaging to ensure the release contains only fresh bundles. -### Bundling and Building +## Building for release -After all the installation finishes, you can bundle and build the extension. Running the following command will first bundle the code and then build the extension. +`npm run build` is the primary release command. It removes any existing `dist/` directory, builds the webpack bundles, and then invokes `ext:build`. ```bash -npm build +npm run build ``` -Two items will be produced. +After the command completes you will have: + +1. `dist/` – the unpacked extension directory that can be loaded directly in Chromium-based browsers. +2. `release.zip` – an archive suitable for uploading to the Chrome Web Store or distributing manually. + +You can also call the lower-level packaging commands when needed: + +```bash +npm run ext:build # Chrome release bundle only +``` + +## Loading the extension locally + +1. Run `npm run build` (or `npm run ext:start`) to populate the `dist/` directory. +2. Navigate to `chrome://extensions/` in Chrome. +3. Enable **Developer mode** and click **Load unpacked**. +4. Select the `extension/writing-process/dist` directory. + +## Deploying updates + +- Upload the generated `release.zip` to the Chrome Web Store dashboard when publishing new versions. +- Update the `version` field in `src/manifest.json` to match the release number before packaging. +- If the Learning Observer websocket endpoint changes, update `WEBSOCKET_SERVER_URL` in `src/background.js` so that the extension sends analytics to the correct server. + +## System design overview + +The extension relies on two complementary streams of information: + +- **Content scripts (`writing.js`, `writing_common.js`)** run inside Google Docs. They capture keystrokes, document metadata, and lifecycle events, and send structured messages to the background service worker. +- **Background/service worker (`service_worker.js`, `background.js`)** manages the analytics pipeline. It listens for messages from content scripts, observes Google Docs network requests (notably `save` and `bind` endpoints), and forwards data to Learning Observer via the `lo-event` logging framework. It activates only when a Google Docs tab has injected the content script to avoid unnecessary logging. + +This design protects against frequent changes in Google Docs. The network listener provides redundancy when Google modifies the document structure, while the keystroke data keeps precise typing information. + +## Maintaining compatibility with Google Docs + +Google occasionally introduces changes that can disrupt the extension, especially around Manifest V3 requirements and Google Docs rendering updates. To reduce churn: + +- Keep an eye on [Chrome extension updates](https://developer.chrome.com/docs/extensions/whatsnew/). Manifest-level changes (e.g. the MV2 → MV3 migration) often require updates to background scripts and permissions. +- When Google Docs changes its network endpoints, temporarily enable `RAW_DEBUG` in `src/background.js` to capture raw traffic and help reverse-engineer new request formats. +- Test the extension after major Google Docs updates to confirm that keystroke logging and document reconstruction still work as expected. -1. `dist/`: a directory where all the built files are copied to -2. `release.zip`: a zip of the extension +For deeper architectural details, consult the inline documentation within each source file in `extension/writing-process/src/`. From a3fa17c99e89ca1ceeae187edce86bf5253d2df0 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 23 Sep 2025 17:21:23 -0400 Subject: [PATCH 049/327] removed unused extension files --- VERSION | 2 +- extension/extension/manifest.json | 46 --------------------------- extension/extension/wo_front_end.png | Bin 44309 -> 0 bytes 3 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 extension/extension/manifest.json delete mode 100644 extension/extension/wo_front_end.png diff --git a/VERSION b/VERSION index bf4718cc6..f19fbd1bf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.23T21.20.29.794Z.eb453bf7.master +0.1.0+2025.09.23T21.21.23.699Z.dfa95f90.master diff --git a/extension/extension/manifest.json b/extension/extension/manifest.json deleted file mode 100644 index 0ebb21523..000000000 --- a/extension/extension/manifest.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "author": "Piotr Mitros", - "manifest_version": 3, - "name": "Writing Process", - "homepage_url": "https://github.com/ETS-Next-Gen/writing_observer", - "incognito": "not_allowed", - "offline_enabled": true, - "version": "1.0.0.2", - "description": "Tracks writing in Google Docs, and provides nifty insights to you and your teachers!", - "action": { - "default_title": "Writing Process", - "default_popup": "pages/settings.html", - "default_icon": { - "48": "icons/lousy-fountain-pen-48.png" - } - }, - "content_scripts": [{ - "matches": ["*://docs.google.com/document/*"], - "js": ["3rdparty/sha256.js", "writing_common.js", "writing.js"] - }], - "web_accessible_resources": [{ - "resources": ["inject.js"], - "matches": ["*://docs.google.com/*"], - "use_dynamic_url": true - }], - "background": { - "service_worker": "service_worker.js" - }, - "permissions": [ - "webRequest", - "identity", - "identity.email", - "storage", - "scripting", - "activeTab" - ], - "host_permissions": [ - "*://docs.google.com/document/*" - ], - "icons": { - "48": "icons/lousy-fountain-pen-48.png" - }, - "options_ui": { - "page": "pages/options.html" - } -} diff --git a/extension/extension/wo_front_end.png b/extension/extension/wo_front_end.png deleted file mode 100644 index 9b6e33a621c4d82c48cbae94aff8f1096eba535d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44309 zcmeFZWmr^Q*fva;BBdfCFd~xDB}0wU-JMD|lEP3UN+?KocY}177m4h3o9Zap{5}rp;%*K09Qmz z20sJ8knI)4o+A}@KUe|&kT+77FqV-)q6a=>A)z1>BB3H~0e+Bt&5+QpKO-Sg1HXZy zl9B&>n~d`7Thz2<)L)-btPwX7H;Fa@g=m;5t2?O6NP`V*te9RH+PpMkdTnKkxB-dp zH5mA4W#sSz^xDeO+8+FxpYr++Fz^|1nVAxFeT#zyKc%{iJV?mK&IrWC#KOcvDS!h4 zf%xnUjlqh-qCX!8{^F-Jb#Sl+Gc!9oJ2N@6GuhagFthUT@G!HmF|)BT0(UUlyI4EC zc+F^S|LC7Wew8C^WN%<+X6s;PV+}%-`{JdIqXR!BC8DC=|Nd#GgPHN4nyl@Ab_?hr zGvXU&Rwfqa-(>@j@*%E*DV}m!a8@x3$2S& zC|BuM3-dQ^4%TXFsxBF64|PXWoEa@f9MK8xAfvC~zu)gA0%61UuUurS#@d3xF) zdpt#Iot=zJiF*R}tUdAeJ^pl@65?1OFC>(|{(Gwc;tCjQ7bFk`Esc}# z)xXQ|f_y^967^=3^!TgYi0V0U@B@a$zaanTa`Rna$SP=09{#)1|84mH!x8txbMpDm z+z*N-k9--iu#e`azQ~X=ch4Wc<*-W9=7{xtY(EI-U%~$m{L7#?~ zzFy^rQ>bo*PM+aOhJAT$mIPPEaI$&a_+Uuq)Irv5?n{G{p23VfGbov$by}F0k9xNuC_Af3bLRXNf?lGEwf<~d7Qy!^3~~Nob-m_UZJ+jkJ1RXg*S5>oC!$%D+G>H zQN+vJA26qN4N?2T&dQ@md$yQ$f+RymNAI<<7-^PS2c26SYF;Vv?KHg1b4is{M)}Jv z+F(D?uGP|I6MD+bTb^}u%U#)9Sr)pb%MOdZWk5EO<|yAWgJz*(v`X=%T*`u8$h9nl zVt752`L1=yo^0;u*~!-+t$F!p#bi$7Oq@A<<9H3@AOg`Bu=;_=wW@q?3S zk(GKJqiC7fyI(Ln<|BFr78)dIz_lHoNzhr=-KHU$h{h4(rJGxnU#WX920qvu4bKMb z>X&_fHdLo!;j?UBvz1GQ7nR)C-?Y@iSR z$e4aIe)o`mmGc0uiNW}Rw4aBXb}(JY@nS&Co*OQ6DdZr?DrC#4!8+j4#f6`boXXZ&Ke6!lBdJv;$Z5!igt_@0Rgrk#z{lZ zQkaeAx27XZ1a+AnXJo((H&*SJNgN&br9pZ87RF7Q`SMD(PNFZfx8#!>lUq}x-}%4c!=B@@ErG1Ef`{pbTR7P4?xO(V+024gyx_nQ;e1v~{3u+;`0Esk~apD}n+ z4_?LV*V#u8z`V#pQ4vT=zNUfwegPskmVW9)f*%*bQa@vDG z?$r+mnFe&=?z7+5M$>VR{goUj=OJoe>@dmDsWRu>=Ju48h)Ky1L{Ta3u8d*yn5ss9 zo3Dd=A6<_dgT1O{6m&`*v@2>PhT%MZOa$(@UmCewR!KZYLF1eyOX_6Uv6oa>CfF@7 zJ>AtMEbZCgkiA7MS4VyCK$u+-`?r+gm2LTwl1u~%VhXpzD zgOv#Zq^})RGzMMHs7edXUcAb2vot>KV&PAM6RpJwT#WOu8T8$aF^JsibCh(Bd-w(0 z_%r2(0-4z`bN%_gF4xQ<|Mwe329h$n&qcCPe=jK{ls@|8dN=Oaa>!n12`JY3)Wx&< zGT!6P)53VJfx z`W5ew2L{zwDsQ?uHt5*wd5V#pyoc+vguFj`bFi*-p%ALu%#6M9Br!Hr^Ky;B#!br&e%t^N36Uh34>Fe09A|cD@fYB%|7EV0uo@P&Jq*TMo zfRv_-azQVda5LCkMnsxUxWAoP4lihbETC=bXS&1x`afF-d<Zn8)0&xH=?{>G)?T{!TTO_*oC_n(f1rI2xd=P__M)W3 zrM20xVGkjn!xo6U?OboW+={A{dKyNNeNIq@fJmyJpNB&GAe&^Skpz75Z|GNk_qY@H=P z*rl^T3)(8aOj$5u%F=*vx!C^M8>_>d%-TXD!kB@KNdoW*3eS?8(aTJf8z20$z7ubV zcA)l!x)J$O<9JeyY@vQ0!%}`c11(yK5}dG5ktilZG%i^Hg-!zdaK9lzX#t21Lo^KC zA|P56HQ6{id$mpcrBae`=`;=^IT`)=v+t}h({PW}9H&t<2h&1~WY?mISY}TS&=55E z?Vn9Q#0rg%D1gv!IJ24u12%($AB-^)Hu1~iVWx!J!Yq=Y`!W<7tE*hdD2kQkSPQ>n zKBW+7)>{Fkuk|=tLDJ?1ez0q;dk)#JAcv0w^SdRAEiAMX0+K^RA= z?whSUqC5e}+_<&Zc_KI*2Mo;GL}t8~S1sDh zml+FQn2%Fj1hoq53brIS<$9{~0>UwVKLA=sDMSo*%caZA8?3j&AnL;6^jogaXT!i_ z=k~+=bS@-YzVn)f@BcK21f>vH6wlIC=y3Hd&Epe7qBvT>W{Gv!-T?LyLWe(|{Vx5M zi{?wxj4_;bJ&&jdqsKw5`8P8}f9JB=F;yDS+UvBO^!Y^eezHypa@DM7x_CJCnQQTzmhh(D>DxOL{ zFEy|_>~<&5wFqJUWlLUOP;|r--?&T7i?Qi8htdqOK={F4_IkWWE|3^o!rwPSgl|-F z-3v5T!3p}^)oXA{z5sy7%K6s+gYIFy11{4lw-Nnr+;#VoHGzm|?lS8C??Ui#fXnjP zp)|kiyZ#N*YA49(WGz36zsvRw| zzq8!ymcrz*fb{Hn1mB-^a&6DKcl?T+n0YO3N7vfuFf z)b&nLXIuS;;gmA{_MmUa{JS1i)taEdpZ%P%g00s**J{2KS7P`XmAy_!!bG*k<^xg^=;!S^73fk0)6OcRu4=13GpW`2mnFijVleZ^ zbG*Tl(g6%ubZ9?~;jKinj%JDB!n~B^fM|c7K?jRYL|rui#fZ>cM*%Pn_Qd6T3quC8(Cv&xRj z4h!~vqm@(XHhyK=f;jGw;!HKWU6+f;7J7`Gw>*Obg$ z5^4%vcL-eoG-%+iVB6`&*#^tn9p=Gv+|RKEXY>Cv6lb(Ho@Jk_w7xs-XlB2Z9^3A+ znULfcxezlQSX}?D+ohqgQM*p1(9^PFe|_}1KozuZiwRpKhF;r?`=5ClR02JwYhLUf zId42b#5#6vS+V5H>sSZ23D_IU_x#uwhuUoFWi?%;PET+|7Z&q^g7wxHTd>R>qbW6NjEKQycHj7)ux1QG52+FaEQ&Z`-_n~-%S6?bF z5L=njuCFYp6uYlJeLI)!MAv)d=Yl}EE9J)k^dBLOJMMd6&7k*Wg3`H;Pj55HA=JTK zsn+^5b(XODa%YUol*G=GG{zzF@J%LsMizCv(zqzhvs0bX)5E9%H`(Fod!o^&^@iQh zX-e>TF7LOa<5gV?P%b;Np0ljrN?$|u?U*r(rTkGQPpARR{jMqvQLJ6_&Vq)iy#4o% zJxdVSL*1mhc|VbSl70+hHK?(15W{2vbL5AJjAMH@LvUM=rxmIKF4vXqj~%vbs09># zBV!0;HMCg27(KT8W3V(sBdo+m)%`Dy0r^HJOf<>b@{Sv={;Qn4jbaN^`Ehyxu%T_LDVO8uLjK6Qf+v7wN-sP%~>u^t+J#> zoajm>pJ2}M&8>N^u=_eijt97$m1UOW2p^o68>{DMo)v->PAS5u+o)TIK%c~X?>edP z)@Ck^a-*kp<vuw}B`yg3?%En2)j{RGzk<{_Sr6pZM)&u0qGF#Ei$g6b?+qu^9+BnmM9V+uMF6E^t5l+~x9;3l z8Qqdz9ISm$vgvvz{Z0AD7uSZ9HtDD7D{m96@;c4bi@2PoYpjgEpHhr|-Jcrf)BzV} z=?FTVHb%9wC*|XBI6mm*?7Brj{<6Kl)n+9|zs$vPfzLpkCg$`M@9>#xLZ<}H=l=Af zgA>(_j9~*erR3Y7$%63>QZ z1B!Z4G>4|MO5T|+HM|^zkydja*uBa-{p3qQ&kc(pGi`0llkIuivg%tcL;Cw^)uinJ zlhba}w_ztd)S{62h^ZapuO!6{?X~eB=A%*O+8BRFj+4W7o)4TBHnD1<>~9?+G=|el z<{RJ27=1@8kufPAO1E%VjaV$8hi(p=eaQWI!vUJb)irOKF!2-C4aF=JXfw{Rhyv3+ zuqs@eH210=+;6pk#~65)IqOyivaYq9X4!_fUB%Xk{Z5l1O=@2HgKCdji%gi{FYO1t zzDj_V3Npo{x5mf^!qlVE**DF1lWwb*(fak}lAlNFtk`$HU{d~BFYJCQqpGy>MM)gzZZ`lK!NK8g6jkhf+$AIAqUlU5yqyO7!>bB9y_&W-x{mC z(i3dAV(u>IxwKQR+>P&{=o?~+DPi36iuW8bagtFWTg_QoEscWb9Za^9?KWu%w#QU@ zDtjb0*uH^tn-mnVfeN}<@37&1j++ixc@f3cSI%$aZvAojt>|f8-etqV3D0iY82S7C zxITVi8WqjBVmYSTs~c;X$k~@}Cc`52U!(~$h=|KMiDWL|;jHQs<02z0LocdpxbnNR z^XjK-I)jGwlx#|!^21gK7G=rHPd0e-tR00MIE!o}a<~>2@BKCc*z#=vmP8uY@y6Ft zQufT1YP>fl!^B!z1eTz|bY0D4Wm|}`G5Uxd?O>(o(lVxXu?1w86{QEVP-w_4xN5yzM5I5En*qBNT>v)>f# zHXiBu-;zjpYPCopwsJp5F4iCxeJ7?5m%7#CavH{zs{x67|y)6g>t3U>+uUQ(!L2=rNZF8GN zd1*qz*sA~Ytm4V&{x{=jeRZhPg_70B9YLCVTRm*B5)47Pm<7woXuwl;9#0f*D9(>$ z9_>n(%6Tied$5k0K}J+}cLsNM`W?;z$d-kY21O>ZMW+Iw}b-jyD982x313TL@#@dWtFAE2yJU$~NJ8eiwca`{9N( zw5IA+YMH4UwfD$2ANzeiDZAX~Gl9$_qx{~`vcg#`uD^V>7o-duKR{ILgYTyXB8pQ* zAO{F0gYK>4za(pL1Cprufi3Q_hpohk6Z~)0Xe@r)BoM~@s1TTb`mmjgh9id7Mb49p z%_Y=ysPAIL#!J$_H<-dHKs>n3<(i#)-d->_541$`H1f$sX?kH_B2lH;y+yE^|PR5VB7kP z=CRP8IELMq&j&p)?yT zX*6W4Q;@`Adu%cprs!ts%duteD}FPmX1HjKhZMGb<0;J4OroLs9Z|+Y(@N;5x$yCg z&v&i|o>CIALyN4mSyFa6iF`$%;)Js%17pbQ3a@5x_S+lVH)d>6Vo(!v#HMr482Y64 zSRf~CsCE3b(2(&oA^a`{PS7p2X8^~Fh3|*)E=2lw_AZBA1-_@UQkDKOlxuw}w6`wl zUC;DIx#1;C+kRvu|I_uH;bbH45wK} z+&E$m>pUS!e`+IzkJSn&7@j|dfbP@(wM;1WK$LG3j6V8XJjp?&h)7Rk{1?^@FB>!2h&N*k36C(4u7NX4r;S!YJ+DnM7z354Rtc zApmk7-06iXnsgbJq@GIJ3H(|$Gdi$V98tVVZ>F98^QzkN+CgdKaFfgBgy(oU&Vp%! zPd=kLl)ae>LrWzXw!KaKE8WE^g$QG$nTHSlaI58bOBB3H$nq7l(kCXU8NFw!)=zZHm$zoM#eeLjDBH+wobM`1XK`_nD6bhlI5EE6<` z4ZZrKee%Kdqx7jbs=pR`E}`GCzA{5*PcXQ2eYJ!c8Z|+`2rJKB?Q}xJ$IA4o9@$SE zfXanUeQ=cv{WX6;PqSs4h?=uiKLOxq`^dvCVA9w1T;v=Ni~;c)ngnEvvwn$VMYGA3 z`Cku7G_f~lM;qyB-g+%h7<*Le*bUg&{N=v3%z+8utOkW3TdegX94qx%N6Awk{%)r^ z;r5_jAnU8Z$Bw;3gh_*K!@R&M2#wnDkil3NLxLfp?N9YXrNgG|UAI>F#s6mUxlne> zd1ymF`dbY?2O z9#j6Ng}VD4Fe|WSqHRN#+^*>0ezn-6Iu$#v=)|Be!~1R=+a|S73o{sDm)7CnbeL4j z!Wx6TV)&!SzD`nhBNprRs?+D6T^cY_p~RDxs0!{4oC4Lnk7z!RA!&CUpkypwGIb7z z;2CFH+832Qc$(lfcu*jU47e0n>+Nkzpu&*B6UsB97@4^OMVih;Gy1X?G^YB;R?E0k zxevqpHES%J4w!tErlTMW zl)jqPS8iq4R2BDMH0Jj~GX~vU(vWkegnk;s8#*9xNCO-_60#Z&zF$p=25oo;I+nQ3 z6y!F7i{ADEw3?XrL+AnDIs~`^mGMuQh;S(WD;z@Hf!Mf~_PrX2ALhs?3ToVV?>^uo zqx55$(Y{Au$im4$2uI_(FCq%WQFJU}3$9r#G;;1HVureypOH(A+F-8@26e2{gGTI`j zzMr&Q^r)~Ik8RB|#aCcbuo}IHf;V*>O2Z@PJEkaXf{poYA~F-0Z+X6`N?k%L*~76) zP_=9i#m4L0*1pJ=pT|zO8MC;t;l}l-2xF6uwK*FKe-jGK78#n|NTWWgLWnv_AGqoj zElLWZElNMY8jV7gwiEy?-%L!cVVvFG>fJw4m^UqNcW`(Jp!)`f-Z{AZz!Lpw1N6jx z7X7M-IQcMxhCelesQ3=-(+yKd?vde(L;5~w_*)1I8a(5%l&Wk)I)@ciJ-FhgXyiN$ zQjhi*&4-qDus3H33zwT#X zb>xXKAi(l(iWo3%pNQc7a$@N-PpJ?}M|4j_LP$yGFTV>+kPI+E*5jXyF zADEVK4vwLJr$!S%9<`b|oc!cpX%{3MpcX{`e^xYcl+h3PB-_c(7@N(|M+}AqXNHOn zK&N__@y1`u7+{rYfdooE$gQ+I-tPBQZ3o2K3**3#KdES2+XdWrt^W{wb$Lj0vd6HO zQI)Rz@})4w(LJ)^HG5XHReBcZgi%NKk^sKKgn-TI zXW&XJ)e%bu{sus>yK#u%TpSv$Zw|An=q4jO-M$^sYOuu^(&I5o#aptw-iW6eu=?PB za`eN-bmDQYc~kA{1ik4FFv*3c7)QjjB}z~@gro73y7lYXwNDu7a_(iF=grlFl#d^O z>sZJ-uoJxZI6xB?+OJrBR!%Xmr&my*pM2EqL-uZwMyo-$LT1z5{>31=%pJ&^?Zq6t zsJ0tP1vj6|8vY_KaUVih;P|Tque*NK2bCaaW2FAT5icj+-yCU(0>I|dmw=LYVQe}m zWUeM%BpD>~@h%M5`js0J~H3_F~+wDcZZg(+okBcxQah%iPz?y6TRVLFzz9O=Ns zAO1``l81q@EYF;U+`$rq!~z8U2>)rs6OG32sd&q9$;8Xadw}*>{1Irz751CA$<9B0 zkS<_xI(8IiX!T8i$2MEsLAj|n(aLa^#64XuD{|ok+=BxqJ)gF)U1{tBB+E#v>wA-# zE@##wOW*YVt8lIl4eMFcTj0+P`?wMe&saYkJeL`06XL5Ds>MJte4$Y`BY ztyOMSK6kXka@UU z9c4r8sRko0eQ*KPE+Y=RW;N8|-d1^#+hc&vQ++B^>B(o4hAW@-Q=Iqi;)iQmkM$b+ zM1usBM(@fl(9OVyywQFshI-q4zE(?s^VtCav=F#Q4oh@!8^6EIhsQ5i;+)!aUB#}H z3O7#d%B-;+ez-h88$U2E`>MV&z%%6Re6m*C`3Oapxzc*jf51GfyJ2qb(X9ctW&6*k zX+o7Yji%cK-``pYfvoNomb@ZEcuyeFnPEO(w%AJ^e0m!>=W-|8)6YWg4fTe|afcC& zxV9zZ70yk`u2wYIDfZ2^N!14RDv{0CE)5fcE9shejLh^*A!}W`68HUX@l*s#gQcL) zl&oyCU8~OeBAqT6YC3VETD+GD@G@WCrldRY*fP~K$GhtsehqUAE?oEk1X4Po?ZI zTDlXRk=;-M%htU3@p;Y&(D5EB!lll7c|S;l>PDE<4*p?b-adMt0?U?-bUIn7pU)no z@-HyrfR`HF;Mw|8$d<3B1=St+hHacVjk>#YF0*@{#W266m)=3U*Xj)(<{p}t*SK`F zYH8oq{|QSp6Y5v^>Pv{e5Riq$M&qjqgWQ7W~c0%}~E_Eg8(1(Qm55b^l|d-ZoT3-G=wDrlPg`Scr)?MV!cV%81;xzkk& zxd>L{6=EG6QJUwg)+mA-GPRczbL%W4Y65ac{G66WJ^VZOTwb)(8JlGchxV6+kS)4) zZ!_&?>EV?aMVD8tlh|ZIt~ii&09E}>4%keYg(!T<$T9SxyY*p;g&2IJySVwh;9o?H z*-PWuVG3Lny~Yg(cIBrc6>$stZcst@4%@}vZo4>Eo222gVOVzJRrBOrm+k6Qf2C9| znQpG3XM_$LNo5VwOP6@5C8J^HK{(BKUT1DO^Jkaf!}2?KhUL# z&t~N}2{TRK__n&2&mhO_ay8-5x$4S(W6YhQe%`O8-c8GCNp-ZShuXXbzQ23w{ABe^ z!sIZ=*6q{O(`P$|L`ddHt4R+2*=%^R4N10|J(86pCUZR)Q8K3GmO^8D z+Xrn7z4mKxADFK1-amdaJFqF_DypzcodWT|3qPm`s_!zD|HBmy{Ao{ToM#dPLWk|=6xtZuNAC>fohP9BEE*oqHe z^N*{>eEpJ}osg*X5Su&7BbX8kY>E&URf%|x1Z5{$q7-b>cl0g&9T2PtJ4k+LlW^>~_~L|DdL zZocfp_UAC`RUA+6iQ*E@UE3Q63#%!?f9MZ2c7mmBY5QT`M)lo{owh5vp{2}6+r^jP zSLD}fr~#6vQQ9^#K4;Y}fwekCQD^*9N_(5*wKGi>0wNn2&hw-^UkU<|@t_r<|?B1QHg4o@vVVjr>{QG`1!j!9kJ z&L#hx`HgK{eY2yhvd8LFPi>mFxv>V50io*V!XF}^UhC%R?j9U(N1F)j%*IPVl87o_ z;av&zV#-?jxrg44Md}G~Ef68C0v5C8WV$F?D(-~1c0)6I%}>H)WxXnP|8iT>&Znku zS1b2hPSO=2SNGxR<)-UvzYV-RXO)2RSG3C}Zu zNA11Z#N1ROH)5KAG|X};0nWkD=+kYNyAtBboWlm96CB-oN7Q;O_kJF#4j|S10{4m% z7Nm4Jq#BNCbexo<-e8M>jb{3|#%Tn#jS~$R1!f5`yS9I1;T1)>w(l5yCx0c6M7nz; zs4g-raQKL|G+st!WqG*GX(YY{x!~$mk4N2vr_#xpkLmdChrNH^eu23Hx$!V+kW$`V zKxwXKGiHJ}Jbj88cNkCTr@HYyvGvZ=fA|!^m_`NF*bHr_m^L4rF7`L4A_0XN(5ps| z@NwOE3x?wkg~@gX*Gs=br?%VfQ`_gY0;Lx3R}IBn3k9InW+orqD(!ri<$Kv}uCmYh z+<%~zgI~$2Ae&iz%n3HbpE@^|#_LO|si{~h=;OvrEgAWV+tWDQ8&Dd3=%P5h+Y#z*3b&v|Y;sgg?R?z8N?PnHs3X}SFVRM3? zpf2j`Yz|6W+gydGD|URp@ja<`tb3SuV?!iWP*&1&g>Wfja4~w<+k5}HcRjT50aGO( z?{^HPOXMLD1L$asi8p`F$3ocYm%y}nxL5;W0*m=mHu#a z{cJM{7k>Tn)D`)wE{ktR5laFZuf8}MHpzby)Ri$|)pMjEyD|(|;t@UyU?|t}P zDT!yQ84)H1%jg&}TS%E7)fqfbPoq)?Y@##JyUv`A)HS=*pgxETdAVVXHlC_T&)_ua@XbCUb)p6NxWaK`p@w{#MGMehz^b~RAr8?;}BYjhj?YrsVtgID29A|6(*%sm`uW!&7+VOTsyvIt%lnvgD2z{Mlj_Cre}|tpmodxA82T zBxH4A%lY*eHR)|OvH(+9kV}70M#7xx>b#L%*!S)lJPV#SRracG`K=m}?AqhBPU$%n z^fcU|3de&VuhCHMjCvej4)vi-XK{CeJ7AFsdv%O6Zd~;`9lgU$nS)eUQrcz>BEy22 z4iayoY)FpCI0nKwMQ7sZ&4POB$#pJA_#q?d<1|h zj1fw^^Ja+}(nzQryoAosaz-o8f)t=h-tdB2%`uN(9H5soI^Q1g93Y<+zuYXc zl6qW0{VI~uT@=D}oaII1Dr)cP+I`q*N<_`EMZ<_0t>Lf|-fEE%)$cyx&;D_8q_DM1=%l1g%mbyCac6g@BleMn)??)&UqG{*7h+ ztfRy!@7VpsL1@@-UIEBaR8R=W0?6U~T8Bl)c?EGy%pu@;GvmGd+>Ei05I=MW>d6u) zOP8+1R@eFD^xNZH!(YP;7Zg@pJE!T_wx2Z|1O z*vr6^hSHX)04g`m90;I#gH6il0IGNWrVUmo#1K8r_~b6x=@Q?gTp{}b+1Jkq2TDQ2 zFMgc`AbXP#a}4Mr3)+67C66r_*^Gsy4FL;Y7qFcT`GS^~@zs~gqHn9+q-)4uQ4<#$ zL9P(w!IGmoe*-{opF!@Qbcy5sb3d?g3&s`}X3I>vAj@F` zGWJ}aoSTSz@j8F!Kvu&{dpE{lh+u?hZAuGl5!SofB&H$8VcI1piuG2^%Zr1rTl@D& z0L1PHMw(09R5<@0Q&{L5>9w)^GefhfBUx7VRN+u&BM~H63yK(8y5JNDfc^^hFRYAIPnQ%C$7ihydR zD7xJ>;Jh7*P;Xa#vnsHEE-5FmYTFRinR5e0fiW3C#z$gjW5XwxU|v+t2~@03>B86+ zF&HSVJXmNN5Y)c<57u1OkR8XF*WWWi|ehc*)0Wtb4qy-*Tb)o zV6KLB0lah^8D707jF|k*nwhYfSGQ1}-L*yO>koB<%4Od2cpeJYyFH&5eEs@>*9bx% z?ur|G3K+{adi;w<)?)uuPc)07fJ+7G=SZ+^>|@MSgj&6x8{n}1O$j#v2z`2?H95}G zD*%ZP;$|5_bocoa0OEhCUjnc?y#S!?GZoDMnqh_@-gJXrV*oWk20E+~Fh>Asia-=# zc^79v0Z{Qo952!xx!$n$6hpf16L=huq(Yydhpbw}p`$aL+; z5XfroVloRk5eWZ4-CGfXG9<$Qo}9D_xrz_qvh)CpInD&;7Dk(NZT>KQ1TU@?ehxsm z0J@hBpnEt!2oTkCPz@nghc+OtS}nmyc?zs@K7d%5(Fj%A2e=ARn{g$3pm@+Au+2=l zOYI4O%kseY7z<0Y1WW+e`2$yc2eIvly78s9&W%8!4za;$sU|gSj@2pQXOOeQyDJHx z%@3dsQY26}%;AG=&xHrS;=Wtw+;P+j06Dbw;mWF96#2rq5Mr|#P zRTiQRDD48sd!N;mnNdpw&KX_7P&CS2iaIsxR4(~V>d$|S@t~z4YuevOX(j~H^U}Lh zAnYzzap~u!`Z{mi@cmu`siq}eyAF-x<5- z`P~<;yC(N<0p$KH!=Tq4K!kvQbr`h>hm=jTnjsE55Z9EP!{J#u3;AAND##r_t(SQ@ z=ZkaZ0&MwlAI+ep-}ieTF8-o>)rSsCO{8f7g_X4!EtSb8&6IBHuv1%W$Z}8Q>S%>G zEdxHtj)E57V~lots9c2V9&WN(q)lfy@Sc1zf2!Ox$EhD=P_P5gukLQ!h@IL*cCHKU z?k?rc=Vg$D7B6{)N4`f0wF5Z$^VKf%gVMRA_+}qWFFpJpPEz1^2BhKM9))+)le2}V zE?pDc4lk%R0M*s42lOS56!6kOX}+|e{guI8zui?I?-P;To}%H{ADvqBSsQ1M8eihbm#8iEb>>HpiEhQwffiob)3)wv#=z?`kK3UJKhsBMcQwj3zt1PecX0$ zPb2qp-vk3m#JojG zN#5EB1ymDz+U2~lRI5^bOpF@)J6X5c2@BM|w_gqWxl$p0rcdTiJ6-Ve;F35X0%o>p z>tc&*w3O*SG{1}uSsx^U3b)AYDY>dTO>AT`Xk6}TY}8@yndYnLM-mP4T(8gA9Te+u zlZyae0+>Hw9%<$7sBGhPPBf!dFjoc+i=Ym+ci!v@v!FPUjDLYGt6Ot1=R#`b1wMHH zV)sMHWW3Jd(KoU&yFebBy~22$aqj4i)4fEJ&)Q1C8b7{(>T`-3Jz4ip^sVG@=i`;t zmG!Su6iWd}oj)}Z77IR^K7b$XG84`7(otuw5An1Fh4@ZsP*HS^%Nw!eT4hQE9mu56 zhi!3A?1FRlzNQNPLvT9ZSWXX)J&k2{)N3$`ue~9)lKOn6-HhD`I7h(gbANWWEfxdt zjs?;t%D`TR1e66;V$1~{;7W?DK)Llso>kkgNe1i7yUYOwg)6vsNrpyHKuaLrwSvRK zZeF_XzTYa#%v$#f4L_VaDm7Fwru1d)`9>f*^>#-Dv49qx64TR${@I~}3505WDqO@n z_u==75D61AX470;r^?MX&U*W`c?x#bjwHPp8*h^(tqvh{kzK8UvrL#NAd0pdI6*a3 z->L{TbiG+l^SZBQl1tnkX9X=owkK(CYD{myX6ZP#8_%cFQ-jhF~&Cya) zOCCX4T+Eu8Se=;&o!8669NjIM&3vbIsMv|E zBKQUv3Z@!XyjDa;5*7F-oD~b?BioKnfvoLUq5^@StDA6m^)w&mqaNlPNH-CP_dm>o zqYh1?g%n+_aFFy>CXn^#w17FA+%75xthO^dz8oLAo#?Jj5Cw%0XU0paxRNkK3hNT=#Csr;7QAEzYo-4tMP=o90X;xM_-bqBUq#=h4_M&4PxBL zwH|)i_cD<4_NA4Dk$#X0RJ8V9mgnRvpLo`?u;t)|FK?e}HQwk9<=&cb5k1-Y;Yx7R z^Qxqfv*jh{r1Ow}|MX2>SuQ=0DgJ1h(2bL!<;~r~m7GHvSnTQIt828gc;sP^EGYME zJmv^-a)*%d)3RGMM{;`SRbMv;nD4@4K*JI#Pr~eRJ^s>E0l_c;Oz3!Au;yoOt|<{@ zWL5GCl2Zr&ed zi48UkbpqerG*TpdS5LEo7Ol(T&V84CYNRh0X83=la{vZ-L-|1?@#Nj|!umtkm3~G{ zY582d0YDW^B@ipSJXX=J)&!g`pb6#Vg+dM z7!pO!6*N8=74A#Uauy-gJjrf>EaKs-s$5svi=e!9cb%T0rrHXLBwmM5C8sQ=?n9qT zGN4&tX_g-AOT^h5ZTakZrI?;cdY)^+ zOSz#Q5^U{!jk!Wu!08^P1>ZfcPxpY|EI+)Wd^~8Bo11U>N9OD&i|i_jYI^k0n2so+ z(_}dGCW(F|O^!wXk9siKe#6B1E;+*$Uwjh;`hpb9!`}=X(D4b5)Y=%|?J_hpa20P` zhZoT(K$ z7;ZxR*sJo&BBm8}c9$UPEG9=D?(pwEa6RBmkKwj-4|esb+O;PxGpk{ijt(;NG=LL{ z*NdAr2-?!8QPiw?sKm9=SuEJmX@Lu7(DLMXV3aEZyiNPtTL9+{0lAFnl814{AcBAF z3DmWTWa?Ym&Xt0*AN!g#G78Rz!^Fl%4Z;?G&{$J z-@>(^^lp-|KvwLZBSr$gT`u{iNnei4|FtB5L^1$l^zcabfprv3pKjKUv)dEkZ6D>b z5xVbuc)2|*W?s2#9ml_q}}Gv4Aqy>gj;Zhv2?mP4?y<0A_qR9V24Td5tvk zL`D0*aR7iu#<2Mj16MTl|HIx}#YGvd;iEEwph!rmNDK`kpaLR2N_TfD-5rv{7>G)P zba!{RO?OCxbR#ezL!C7O?!C{sIKOl8zdJWv4PUJFt~a0O`94o4xT0H~S7XpY^Ssxo zIPf`@s4ggDuhxQ+>cy%A@6KLu8^;l7jINckqpa79HV<@9>g>xXWAn>8S1R3_4y1f| zk;3yo_&LhWl=|b!hOUr=3_1HSA5}~OMpX-b`(TAeMG&eZzc9mN)yc`)+as<*D}f|C z$H~VAe%O_(GeM}=$)RhKYcs-&|8IAi#~=XX`|L22o;wVFGSxi?^1RmTWwvR1j-c%z z#k5tk_x$?Kb?WnU>Medi>rV?cwa&-?pVmMUxeu zFv$tIuJGxy^r4E@Ol;hv)13^Fb~h|b?ZhW+2G=(yhJ1df7~C@NLq2~SWAiZsz}!o% z%JBZZ2^56}A@wehhx`@PnCwMsn&1wtMNn$FXYv$DDu)rx{Y=woV_B#X)O)2ejE|JN zTw56yoD~!mC1k)*7G)hC&{690gg>2OZ1I3GvA3?RHPCD4>aZ1Frhc^J`wsos=c~0Z zj;UH7HZ+kpmp{Uge_NjEcm^ORG|tkkJ!(00OJXR3*N8h$DB+F1e=n2atsQoKZBiR# zSH|6&^ks<_DZC3toI6&2%O(R<%4<0-Ov^4kmrsch!-(PC|ZS(HFNt0F6i(9`a^MSew z1EGp#82n=qm!OMNXK_36Aq4}+)Wa^go93h$TebK$=c0_^=zS^5ZC%a6RxwaM2|&iD zW*ipo;)v$?-Z=?+r+%n75Vv>z&0Y5)3EysG@7=qJ?VSH_Vi<@OEN8B+Km{K*8J|&= zW5n787`q!s)hnczb1;?m?=yzd-Us3SXd|a6qgjBuu$xQRiqFH( ziP!9)@^P{FqIeG!n9X^R3*d_lGKI>4{}$BK zxFEw%7)S1JW_-QpkPtQ?nV9rY{fe^<=@D)y-FZB&)(6xWq?{-k{)b_QQ!nIHF~0L1 z^1vaxTv9&bW>!3{cU`(in&SZE{B>7A8Ln;iQ2uYnC_As2^;9nE@T8_EF>>^tl76j8 z{4SWZ7mnD2D*JC=;Dsc(fk>c~8oFo1b4>u8E_a}8RB4U|t_3)8cLQItwSUl zL4T8)>2F5%7*cE8J}?Xq;c3)0;&FMvOPQKLIfWIiK>>`+}eoCj|8IC>xW%}a) zXFvz)-L4<^7BG6<{FLGmpeF?ySTGi@n*?3S9~&e9G1EOAcCe=WaQ;6;*jkeG3aNk_h3W-aDre;6Bqkca{B=> zUA=g(o)?~ImcUMdSL3s?H|U9N{o{EO0J3MUeVz^CDW=*v1AGjwgNEG?)VE$o!2TNm z2qYKcTpKli#kp3ZarHtN7RRG8WjD<25oeu#J{FdiauW-malNpCnWHNlH?eSJlZ&%O zZ66_)0;sEgUJu$Fl1}77n3pkLMVPc`0V9Wz0#Oi?)56{LcuQ)G>|ggE(GfoSFBtyy zu{VM*QZ#vnrQR-B2AhNS?PH7_{1FBkUzqV#0K>m%_*0dePB0Psi>ni>Gu!w)FB$*y zbr>KyfbQVWlp4%b(&!g|@eIInxp4qMf3TD|WT@xmnt1a%gm1v7wLrNV9>ZpF-q|15 zw`|jR(+s$%H76w_+k<`AJ->p9{a?Pca;g>fsHzh21&szKf(wBAYEVd@-$}H+Hzwrf z&!%mvR)GHQgaU~Si^;{HX3p7;E2NL34d{o39?C4_|Fms?0NAtcd;3NiR}to~DsgX~ zC8AJeELz%IYPyg<$zy+|4Rf-V<7M7ffCp!gG@n!e2=Sf{9g+v9Yobp5luG*o#Qyq% z-jN-`0^#$Z%9_iG6PE$NH3^FLe+M zjBn}cyLUztQf}q)6Vjnh#fprvt>k3+EIRKO2cA&Q|GpzGWe7o-Ptfy{pZhN_EZV!b z2450~pdL{d-LTJsoov_{pT2Jz{rv5bboc;`f{b+<*~Yzl8M*4PtioZKGhnfs-0B@R>;M6t!>$mUK*%2fcy=z)EDD5kyZ;a5u zfnbXHy;5I1QGnr&GVEiB(Z=`E1o|8vHEoFnI;MLxXeNwSjeAkS>;YYE+hvU;QRvDD zS(f3M-+gTWHGHL%K?}t@#r9*RRs7f-idb@%lI1VS{W7v)h!8v^Xq#sw)GKpIVw>lX zaEbC{!e=6MafnmmI&+q^O3>6-N?1(Lz^}oSCVR2441{^!4gEY*)d4dg`B1ZaavR+i z)R{u}qfR^y?!OCsZf>jUbt#+v%zr*7L6Z;)KyUHSyBTGm_Cx58LWpjSt%DS_^sp%; zkiXQ14G@rJHtLLb%zcJeZ~^53AkZ3P{w#wF`M|DoD?mq9y1!uL@!YDKkq) zWa_w!=|LnBOC0yGtom2Z)JD-8J07oYhvkKnu8+F)L>_$KIc%SEIuw&VU|~LwAEJf6 zi!YUIt}#IeVXEn(*PPTPY;lzwF?H_|5))fR+R=dJCRWoace#By?^qU;%|4sDOaR#O zdEF~2>%9LFN_ojJ-TF+`feUIgxvJhevi0&SLuF+2pSfo-p#%^m4uJe;1;~FX$Kkx? z8-YCvB7hh5&|y@zwXL;^`%k~!m3Gps{r5eiiU9ZgHwyZTVsu|g8@&Z){guL@KkrAN z6&Gy?6h|JJtXdZPU z1L#({uJ_b2#zULPCj{S%W%Hdc0apYFaU!iwdf?X34u~*N#26NMD1+{K>sklMHW)@9 z85&pp59P%K^wGVDz>^}F3I9Atveyh@rn(=9Jt90l1@!wa!Qau$*}Q5OIO-};In`E} zFyBN!5Iq7ApITgi_^k+*31X?-N}?r3gddy5t@NK{5(M3G>yo@Sia-3B`QKbzAE+t?oU1B{miX@Z^C8UXi2a2;j+sHT{w*_E%F5Ys zgHAI7J}*zj6%+KWUeYIb`$yt+vXSA5CRIC>2doSWN!Em4Bo&U`ov>oiubMlPvWD5)Rk_Xq06=f#!{ro?_Td|YT23+f%(cSA1LxFZ9`HW3H7?9(AfciRVwcTxKKE@? z#9IB!Z5L6k#*D}p6c=PyJX!!fhOX(7psgdZxi;V!ZB-*taUAFp0JKvbH{Sig+=R?s zWI#9oGCble;wv2qa2U@(ukvrF93Z6IK;#htSd5@c2t5AM`E6`7Nr2Lieyq9?YyT2$ z065INV(1mOWI~Su2z1Z1#L`@u97rHEBt5;7v7keb!!du5e^p#?>Z@vx6@=s1ETcoW zTn)(1=;=p4RQID8`);L{E>uDCvz}Fgod+ImVoF_VHtz775Zz&`5QzJN-t!j1pNTP6 zxUt^JuttTc+qd6jMkvt$w8CG?AN?nD|7Wda2*s=DL5Ej^b=*=ZB^r-h@3@)+0Ed>@ z>=KRaq(5t!hOea7?NOF99KoBY=%b>$ub|V{tyoxHxiLSAF2jOud9Wm7I9I}(RuSeY zj%>eiY#p|O)_V{Z?h*%DQA~Th(wTakPcuO-Ge>bRLdvu+7C!D8>ufbFux2vz5|6G} za0mGQDzo_!h-}T)i<)h-hC7+}bxF~iQG%u?G(4T^%Gus#n|2I{e=pd#W<1%kIV{NPEgn2RD(^H&LinrvE6#i*cMV zGKd**{m`J^nVlcpHIyY%jK-0z!hf^;Xj{Me5wAN)n(%Jmc}bOc19}T7tD+ogPS*1- zV59K}lXvxXSLDpw!MZs&1#dR7Zw$R1M892zN5YC8mN68K>sD4*`pj%C%J_+UHDsS( z1qXV5j<@__`R^pDt5Ni~Cz=`xdI1uD4xk;GfbK3;&U0rqI*umE!bgbgJ!dOEpd5Sn z=9SNH*gxJ|JzCZNje0sh4h5Ni@Q05QMbr!;o|Pp!LdQPgNArW5Z(eYf3ejTAK|KQ9 z_uN40V*RO`YEovw;A?iWcnPDSVSv(uNX;iV6fu^elAB|=?L#AOU0NIW>-afkr)oHx zb`Gpf7bZPN_ph6tdTt0Vw#H>j?H|eZ_naP&U2|Vf<4CLPb@*9pD)HfHHA9Mp^Em7OsC&TT6%oM*JE;aNPda?PC5TF&0aRIzqZTLrjD_!+N!~s;X#u&mZ;Be z=UvIF&zo8}#YfoiyEk}lLd{clOkS|$ZAYE$`}7QYF+Cj%!t+=QC6q>sqgg7GL6q*^ zuQp5UXmZG%%Qlm8*>dVPk}>{0>Wxw5`YqCM$2!d?aFHbc)uiiU)Q+(0iNmwcS0@I3 zsi=r@JQe$AY=(N^01Zh*pU~K=KAZD}xX<~OsU?TsLmhlwU0{zSxO`pm^k|fiGd#;+ zmKSR_`EsvLqAp_*+t_m)1#(^b;2g26hkaqQF%gaDLkbuLa46qz=h-;0uQhXgn=EcMOPI zpgj|ac#@8b^M}rUAv=-gs^oD_xYgLTqm3E`vCY%met(~X?XSH$*<w06}ZW)!@x2pL;|2+==RnA z^vmSUzXKS(YuLLjAG7Qd8L@aVQ$z1ySe`F6!W<+eft5E>1aU+)0WjfcdPiT6HJD1z zz1pD4+FcwA$ROUHDT*dXX94J!K`?{k68P&=iUp3SH24RvzTk#NeJT(4z?@_^rO0cd zSu*=a9b0OWt>?*!udf_vlh`~|X^r{XaQXkJ_jWj>bvG%b+TW2j85RwW3K; z@0kJoNj*uPT8G2fU_BTuqnwpBZuv}NefZG-l8%fFY{SOm34tVQP zuS*s}kQ6e2&(Pm}1GrmVSV=K2uQ~P0K}U;pO&p)u ze_5!X_n&=%ubT8e!)gtNQQ(vlNb+pv_`lLWoczY-$tnkpjfuP$e7Z()o3prQzeD$; z(TMXk2j&>R7iUXHSOsCNBxz48DhNk?H*LbZvfFZl@&)feK{nqyM;@{+K(p-`(!i6R zkx}w=gV*s?ChvH~P+L0eXc#Na_^7AQXMWZYJPA}EGuQHtoW}6xy>Qk|cP9N>IpH+T zXZ;(F{d}u+x4+2+qB3s;h#wR7!Z4q*Zq3Ernfp?4_*8kRF)TJD!f5!Z?qSj8zQ8)| z)9%)(lXOO=+-J`3n?|b9`J+EB;y9z=)Ii0h`ianp^L=)dEYmv8GjE>t-q9s%20%Ow z!Yz0TwT5VP-=e{j3-UD;FA%3>F8X-cQhoP*&X;@ys#kJe6Uljo23MJWP{eG_jF!YO*EJ(kc7kP4JolR3V40OcKYrvYBAhQzO#$ak6^1-Lb8!tLK`o zFz&4p_g!=T3p4y{Ue8oOJdDGq==`r4GdOB%px0@+*qioWjcstCeC5Cix8bwry66C( zpO-RlUJ@jNEB|XG3oiZ$SZ&2}bMHm*b#{cCyTHr1QVEU*U0C;Dck@#fG)prtOO&0F zzRr(320!{_{U3U0SZTr?g|Qp{<;^pc@X*+G1!+SM9x2(bAZO&jTbSy#$K+ODl??9j zzA}|IJ!MTT4dl9Z?jcgqYKo}uugS!6VC$1n8J0WLs;k;xdlktt3evT3oD*U5nVt+R zc}?l03BB%t$$z`j;D3t)!9v;iz4vp?gmp#*OCg8c3*;mv!{*j#!lJ|aW8_k8F;m5p zGjg=a^D49V9;bT^cGJVhk1^8$DwXT3ZbvMEWeuDxNipe#_WTNI!*i2fPlU$~(PxrL zfBN&5p25wSt32otl#m;OWB^BY^j9`$WW*|^(42WhK$FJ3CAR;kr&gZC+@dhNRE_8H z<=(jtA7!rP+mK#)3gX-#eGG4_!o(YLlCs3C&_Rs57aeNCEi`La%5TitKTp!R5J+3Zz^3!$icz%FH8YG6jdj0Qbew0u5t4Q@Q7it%O- zed$0T`Ba$?XfRKwUBbu-R@6Oba>N5;`F?QIcY~TZn?vtzMpB3BSY<@)D_#*(naP$h zF+ohXHQGraTA=`7ZbAh3VP?vfVhlXbH2yqa-`douvd&S9EB1vtEwjL6E(TC~6$3 z@&2IC9c3okfN;P^OoK@LiYFcO{JKDohAUD$yz$RH#hMxU91eZ!!r?>zg}~~;#d=+U z_XN!PkSn$l=Zdd}a^UAf;t?kl8p#XoKhj;hg*#nX+|w8U7Rh?bQI{K_{G7pBrj(_h zX955Gh7az*hPPI3RTt+$80VqXr&gyydG=+WC=t-!#E}P)`?0X&nY$pwg|wFRTt)f% zazNg?9jWC$nlfXTlVyu|c{Nzl(DJ51sUzqfynfPrO|o6%SXP??sa!}#(tg{u%oy23 zd%Z#lG~IrxCD&Gd;_^Q3dRVia=(aW*m~HNc3>D{9^w9JmF_n@RmsTxr4GR2OUN_EF zms{Bz)ES)nh&Vue(7q=cpbo6z%A`}NwyknuFMktADT^oBt4jct`{`G{q#=<7(R6H< z&r4!$cCLzh+s_hV{*rnI*D6@H9h|vxVBG)d#fryIl(xPKb!F*n&h%xIx3f8Q&zD(0 znQLmYaFJt$J*z0-O#+?UyNw@pbA~IJ?FJ;`uYk17McqAMNELw9o}qF;gQ2_ zgh|7ok{D$7uMvf;T_jBBZutZpCX}5x{+Z$YODmwj+FoJO|8EfS^*sen{Uk2*AE5fo ze}ikk?1f^q{;#WtPB#HJcxpO#;pES6frBnvC1Iui8%1#ba5M}3Kd${5T6|hik~xsL zSb#6GocLia-$Ss9dDpBS*~{maKZGeI*+tTD>gG6fNvf5SW?8UHrRYnr-me9{ACB4_ z(vocva~+LgLpJY?@v8ek*AaAvp3MELCjJIS!X^k?U!SvPEK*?tBZotek$WsDV&LVw zK9d1E29~ra11`4CiayPTkt2$cD#dFG?%H8}o?yu`TE6|yO2PuJRd-2NaSeY+%aM+? ztOOpDh_`g##De)yRXS3i@lE(is;TUur>Z@hgf>OrxMJ?M596T0kyLE(nnn?UWYmLG zRsqhH&=BJPy{y+Ydio40Wo->9RslK3w^Q_b-CkPCb@B8;-=%Xjy~Cec{KjLX>5T~Q z-O1}S+0|oI@NWIF@Nvx9n{MuZKCrbUim~c0D!7{YD&|WanWWLYwiCaFp>}AxO9CzL zt5X>wm7R&o(h|c!RroNF^;#Fp<~i)F=}(@-;oCFftQ&nyP|6Ob4(ATHS#L&*JVPX>= zFnKdZ$3Tx`t4fH~?!I?<+tzMw;EsY1?7c9`uXbV&H;4aEW4c??%CckC50!24=vlTP zx`mI=2H1$P|2t!Vl4Aj%6CTS!ZPm}^y=t~z*pvfxc}J44SMP+NSWT^cwJCM5k`xCW z;2YAc(7!ueq=6U|Ukw=>UZ@pOZgdQCpX^0KypLK=hUI)?dA40!*St%1oG1NtRFmtw zFbmc0oN8=~Ps|8pO{v<}k71^^j=ZAZ{Hik=kDD%}2fOcW-G7OLnnC^6b|aD<^vG{DdPZpDL{Y<>z8)F}08t->S92$0!ITtRkx9Nw($;amI7O+LC-;=s_inskMtdt>{ldk;}th1qkg9JPZF4WQUkP|m<>{?0D6}9Q*HJ)=hc#L zcJhW7%dJ!YS~1sn`pmi5F-K01#G*tiRnDZlgOu6>e#=`M@N6A-EBcJ~TdmZd!8L+B zG!MiYfE@N_ctm}uO`+SdVjkqj_guUcvgxvP`(MNhYQhpZNm&DBu{B@d&tDo+5>ik8 zzB!!Fs0e!U!wZ`8e*78BTdq54Q>*FS%VRI}RFaWc{Sw0{Z}+71O7q^<6f%bGh+Ve9 zuB6j|@K@BbDxCd1al$xrIX-54he55bEx*@HT_L!zonw0%w-BCqgVd#}1SO;EU2KQ^~2y5B=wo!Ti1Qos={RBQFN$_SskJwKc@qPDKGbBKKf z(jXVmSWvSuJ*He{(-^^i+DMX!qBsnw{W5zC5=zqZWMN!msAY_GU(&`q+&Gi+@J{bc zt+=}crGg^-Yu!@$lOK5EcVa2FgTLv_2P(L>MK+K+Ru@WvvfkuZv8`i;2fK@ClTlu~ zR`;ovx6SDY_twwaBIQYxbrcZtFxZQvi0sSdYweT`Rl0m_eoV!$Wj9=~`%>Xaspvvu zt-8>Z_B~YO>=VJAxl$*;whXh12DWdOZ;>l@3F~81Cr;TYql)hS)jA0?v8=>_v4FU& zRWHH9f+P>CG_PXQqLN`Zr~TzvhQ)w&Hems~*Ccc4HEfok&E>9HQ#7Lf%X!!cSNAJB z#XkMquTLctB*RX39~AVgGb9GBexM9gv)!o{%ud{Qj@sQx%fTY!WiErW#+BDwY zV8^Qlma|kzqmTb+c;lfNvC4#JZM)^fP<+BMv6Sp4`^VK23Cl{Mr}tOzKN#VNDkm!_ zRR&Ox$_X9*3OSO%^17MyphfE#uD%vo>&F=L;wjIvUc|h>#zyC-ZS8~BBq2gU&c)bW zhvSYMd`0;FE2-^H&IW8mp?ksp&2dyLa_B%?U613#@CK)_Mk2qiZH-s`PCRm9{bSvH z76IJ+CC%#3TFMN^Rh5j==Vmc3E$ddvF12j=6QArOj|*4IeD-&T59hdmpMea?LWdgIC#=ME?jSK6Q_G9 zP0;SN=}kjjIL5>=d7_4t2pD*@cyQLrfmLG>g+1)#ObbFOSJ*54sO#BvP>||AS@!0x zODdBTj2r#dZ=xT(I_75O*7VaOu1LE>f}=TN(z}-4Y;QG$qX+eJ+32k}#iDP8gn6#V z6`qiY-eXJ?-t`@?`o@!LCdJM ztszR3)+a}O;d65|dU9GGLpuZ439}O zrAJZ=?C!&+@PQahK@|?xK=!P0A0qn%U)O2I{PrlTLhOKSb)sC8)hDykRmH##xY4We z7p+o1Sl;xXxzX3^P+lwF5mPa{nP2R;Z1OD|NQdrx7GVKjG{d&(k*eY_*CUQhCA-+|lfwL5#CwoxwT zjd>|VgkHYZVbfGQjv?r%mdvSbd%S_^l!O05uYXGDC+(mFxyjlzZOv&@*Tb>+bb6+? zXD)FYmxmJ>(y%?6D(FJ^^j7!xgmg`Gs+Q!{XG3yPOJv}Ri1cj*$L3ymg{Z2lWE4dDR8z>}!FmFFaRUsa7by(pJ^NwA7 zt|_Wc+EzWchHd||3U*6Tqf=?l%5nF;U#)c8Srt274Y3e2i?+hIgNrv*PBkQpSyl?q zlw7ysk6bArcsD8ZZA!J`Kp&Yu=TouXE?Kd%AzP8P1kdxWj=CC@H)xZ){x|0S*t6N% z)!J|Jn#Z#wop7vp(|I*)a-BjU%0tj+t{L8Oklrx~aY&?z@Dut94&nDc8lSPLW*-^!XMJv=)OlQta^hq|p-c8$3C3zN8AZ5N1H{scPG{;feuX*HZ18Vv^Uaq)0 z-}bJmG10*Ogg2izI(HSF1N_XyV5bHpH{+!u&{0u~+fX^K`+18ob51HM{3N;1djEr; z%;cV(4h3GDXIza~jb++Ole7o-OiH4_M2tgEqJ)Tq}0^p!KammQX6=NDwVDI4n;P*0!R65 zY$dh1_jJ?oPQVa%Vvx?_<(&RD&-!8ehyuI3V^u5^Dj37VkMHMhhU3t3#PbP3GH#0( zJWlc)d&U`*5)%rlRfcskOttq6=Qq6W|G47Z?GmTQVVEB7a}skl#fPP1?cS}^6Q4+_ zR6lq_!MhcC;9&D=a;MaFcuJ3e(zA$6rj2^v_o|_sV&(7sA6@S5SxKA)nx}W1#Ja8y z#|X+5v?EWlJ@{i{ZGvUKjq0SYE}trXa&%o?zO;&)8?63iAaC-{fQ~dCm8n~U zo?E@+LyxYI{F5oVTS&haUQAjR`=M<81u{*_*GpIimFq<&;-QlMgYcQQ`s z8!iRnJ0kO{(lxeSs26Z~rO5hKI|%J%d8o_DpW@xoK^wLG{>TRbI5ISekBhTe{j+ zOj?Oz`Cn!z>&^%p*(d7$l${If#w3${A=)9k*!ZSTvqXI&Hz{(HP_9)P-%!%ngbSX_x1 ztdRGru<+bOhrz0`l}pxh9axm_hpIwXKpXz4c*8aRLQGxd5m&~+3SZc&GuxN`L;H_5 zf*gE$6Y7-jBQn01O9xtr$u%6Ly{>y$ApEp?^1Dq<)ZP6=+wrmPXLYPmMrYx~ITChw z%%V3ovmWn~P-TTK$+2eng|c#XJlcn~U0;H_+S(_-w!UE@xIsho^o8`@5H`Mw*-eEX z?E6JRtOm*60zRh&J`9eI0J>lb#oW}u6sfMGQ_4yGgF{ZTs3$TuD?x(Pz6It8!! zyz5VVS+-|ZyCaLT7e$b5`O7)2jD&+sm3g;y-K038)55dZbRWGKF{JO|o2W=TE&&I| z>Y(&U94waQqTgm z0NotP4=U6UeN6G}ksm1yI{U?aMU6sJSsD)prR-u-&1jFMJWO;GcAX+N!boq`@n_xC z^iZ_9`HMXvqtc^y8H@sB-$d&c^&U{2?t2W2*i2$;XR*`k9$WM`yHX2H7Eg^+OFUa?WZ*#C>MXP;CSiag+Al3Gj&)iaCVj)Jci_Si=<(-dvQgy5AYXA8- zCKp;i@(Xj%6--@BvXc$3GVE+0B)4Av-fAwJ;iXG=_oPIhsL~9MSu8EmaGZ4BF;(c* zdz+h~)cJGS49ATsKQfqyg3$ZJiiVxm&&;1b6OJ8b4Y1HUU+0L?F0rgT)W?$QHf&^+ zm><=KynssdO+8UOTN6fWcD16YI$2~TDORodAUHP ziUz#rl<;u(W`U(%rz@&8C5Cj+#Nd%h_R<@8^~*Wy}A*Me^5H-5sNZ(Ou)!FMGmG&hban zlWww5kAsPV!>3xqOBxN^n?|;#ye?3eVFCqi8xK7j!8EvTKdFjB2$p3EqZ>;PpNrPa zN^qU)ijhaS`$Hf0=J5GPDWjGJ1XQXaeh@CG7dz)TYdn=B+i3toCI(oe88+ z2HoKGeY>JqdY)Wi_NBSnC8f8J$7jt)7YHgSYJ`9-3>?g1$EAQPE440noOQr=YM(+= z#4`4~9*>3aGgC91WqY3Nv!AFN{0*9LUF;hl{4yw!H_z+~< zI*OpvX;GHU%H|5(_~k)W%FUHHPPdXJ7s|{W7rX^Mo^MIHHDnl75X!74m0J<$nIy)2HX(s!P8P zvIQLs@3AtUMpsZ=E1B3MsVBqt2g~xY+pH3BB_>b<4|moI8wXK+WqzV+o)&+FGJM?- zDhg}QO~J)(wfdHOLvzhcT>dVUFIK?Q6v^AbE5jnLE|Iz+gX^5X@O*Cznf$TG=;DU= z<8MI;s;ky9`4U@Q<8GH8l)PpAQ{%ul?%yoU9p+v^{0%@i<<`v?s0EAd zkH3!x)Okk2a>+9L@^)6l@~M>a*jGtI&cq=0NQ%LS%DY2|{6}{VpI51Ka#~j1NNYg% zI0zspvb(lv+ZgX<&^NwwO%ubS+EntYsLh{@VvF#Y+y6T&Mf@QJmr_Ju>iec!E~kh5 z{n6Vi1OKMy;H^R+8<0MNp*6f}RYQ!kP6Mz3co?)||9~Di&>k%aAJqE~iX{w8>pO$UYUW!_wzoc42=Tmy4Vc|! zzg_~a?f-=3KkT(j2ua-d2c=m8hwaPC(Q&r9K3fJ>b9-iyanl1jIyj;Y%l7Q!U@S00 zmWkGHKErPSVGihhOIV5kyxqO8$ulTt9Y7^a_C!9U7pAn@tOH1s*5g}GK%BubR3W_x zJm5&okn|kNtok~GQ>N01owwhnwqMU`GKjRvWgxWq^69NSprEYNzsS8{J%JlSDIi$9 zKrw+MvvtJCGwzp$9cyU&rjJZ#$fLM!Qf{Q-x>7DsvFA4{U0Rfv!V%R5(}%ua0~dS~ zwAn;s^{IrLOuDGdf!0lQtSg8QF8tD+hn;n->5U~?IHF$!a7f^~;BjY(9G>LkJdVwk z)1U}cE9qlEAz&RikI7l(476h{4Ko#-(bL-{Yef22%!75c@Hv!Szymo8YsY8}2^n03 zxfuaI@(!4IHsUzY^?1!CFIyQ6n&xn55%C;nrs0Uzp~uW(r*#84%S%oD=60Ox=sjMe zw_ksgHouXl;PQy~NyF@rE)%vLpAz`w1o7`2zEa2tm|Q=7dD6y@o+AT5PP>8)PBm%v z!S;h3-F@K|-4Bva!;A?M=lA&V|6=+vnYKDPvD^1E3Bm^=L~FL|X9VcTDVSohL8=?5g^_!*%RcCv(&7DoqYA3g&|h@cGmE>PqT_uEaGv|?eM;N4QVj) zpbH&xDJ78yT3R^=4(uZP=VMz1u(f|E+&l_^PRIc{l#mzkJr}85dUV$!cf#au=bFh1h-NJ_@Q^@XwcNR91be16`3gMWhTyVy*;%fAmtwk1EU4d zJUqQg5C0`p(AhhS*7gG6E$IRI^T@+uL9A9T=UGtqX931%>9GF^?VS8^-%mcbm) zIVYs?gIs6yd4##qPcY;CA}@>Oz}(|y92`+l-F4f47oCU(QN4uhG>y204|`9tSXUraJ6mCFlM9Db63jTw9?diTV}{Uib(|g5bS^eGqBW zm|7ce6f2626MUh5>u###xfdv|1LMC5iIBawUfZVrRo|Z! zEz_PaCs3ciPwr3d{_83DHM?Joyr1I5Fk0^2zhN}dQ-k+sX%KV>%;t@3M3)sL!McdF zNj-mXPqA*_BxjPZd-pzXSrSRSfCf=mpHcM>=L-hwOHxVv%1hgHgsTvBn0DieS>La0 z4IQ`wU6>vWi+*MG@1pVN=&geQ&>LQKP{41-DDPMbm-kf26kpn{uap+E%&+mpA?GlxoLzQ1|XN{PUkwkl`+*W z<>J?#i)4yw{en9zo{v|EFb7aXFF2~$e^BmxFo(YT58#D@wYEUML`!eqwzaVh@_w1; zwzWCGKfwz^$C9*cU-sKSO7VvBxpf)yBEM42A5(Au1;DZK@SV92kS`j~27I5o zpG5AY!}lpvdO^EB*6i^rdF*H9k~-LKes9BP<(qHLNqOLSQW*F?+x;W1i?{@NPP8=4 zHinsQgiRVlE~MF@QCPdE$C6h_U=fI!N;98+|Kd!7p#f$Z&GU3ZFw;{_hBC zr?s8R*A*KE$AbyG)9ZuvRl65U8WoU zsI+et7h4Zo1S{wo#9u+{>w6Pnm&mKRpeHQ0E0hej`Jvf{VbWz~z#uD*|4;1<=-OQG zue{2H`Zhm6l>OKxYaqxL#$Z7#JrD+N2RU<49{;!sXu%lJ&Hz|FJ~Z;TM+iDmU-vn_w+J)UOYWbWKD{mwktO#_( z;aml2>o+BhdmvquQa^2{Q)L}I-(TMefc9AzdRZ=Phz1j;d+apy_5C805V82Wl95^o zxxF$Qom%;$gUMysR%A7y&Q{(LeBcE&C1H7T3*c^Uzgx+^Km=KXb+g>TNIwX@(StBQ z$W4lYsS*(}@Ooy0A-!m(qoo6D@s45zMebwTi8^D+Cfk5FI_Wr+&RptJDo8TqW|~%; zx-OGgmJln5jkK!#{~l2f{fK;y<@|<_F4%xl(XSq^R%$mi^72LrDyO9ZmU8%oVx1l_ z+Q1<*Uwit%4KKpmHIPIe^?^Rqbvb=Vk?lOs`1u4BjBEF$%S-w(aYXq86W`k~h5$TY z>+OeQ<+VAkQ4t04bZnh2k5;idFDUquXzgg_xLRxQX)nvXnbZ;`Xo%p8NaMYlujT0_ zjs*aYrzI+AB=^tAE|Rcu@CBRi#~PP>FJWzqkKYAY$hdLjw+|VPUlK4PMIT*Qiwm$8 zP3q^U#i~n)>?vbo*mSh7_B1Pi--U(oj8f!H>?q_MY?l}dv#D}@tyv(|3BhdHJU|exg}HxKAAJ?@n_k~A8S{-7K@ll ziFKv2&{MbOq)J(%p80EqBE`izX#oT8N|P89VFVg~52dd?ZDvW{Cuh5L8bVKRlKUng zwo|{MBZSZWoU{!C?;3!9SHLG|yo~c&0m|T(J{q?l+~upfDb~iBKC_c)eD=a?0ABhx zg`l|!CB)-p!J_SX0xj6$Vi7QD+=IIo4| z^%Br}h=*S}s2IA$0zo$)6cLJUn?rA^45iQ2f`Bp)_?OX?l;<-f;2v4*CUn#KP?oYH z5_ylIn)MHpZ_9W4V}6-4yCosg&V31CKX5(|1nZr<62PMJlLpZc-bQ>K@M4L7Y|vLL z|A_RFdf`WOA>p*X(Zc1ceSS2dmLLSAnKGM8(gTB{OOd6-c>&;@Awiz7hljd`?AEyx z3=Hi>VW6a#dt;u_u|24 zmh7+6(@O(XD}z~!waTls6aXgkHo)IRc~)Dd>t5K;LtsD5cL-yNg%AL~n33@<<*p<> zAs#g+1Ko5KY!4_o@~q&0Wcsuw)>g^k^V{LU*&bJde6s?%)%yaDiAFEBt2n-WK(|6b zF-%Knis+cU`QgMZM`gPgp7p#i?AJwVc@6!x&j`(*8ed^5)UmSLy_)bMxnu)-z4<#0dEv1CI#^#eaGY&;t+_5p>t}0O48HA@-S8uL=zp<+ zmFOB}zPQ)?{C&@J%So_ZdsM>O|52w!d++}^=KslCJ%M$OdLEhoN0SKsAkSn#F|LDu zC-7g``uiYj|0f^1b(Uy+DZUqBp!Y~$ziAb6nlLI=BCgC$vE;8{@p|ANcfDRIHJSO2i9U3;?*|_FzHfYPcKi5c! z8ta)0f!~|FYv)zk-;qmIXchK(+&SiPew?nL(d!?J@)~e0S|QmMi2Lc_`b2w9yBLsSlJx z!WZ(}+l(m9Pe)uB4fYqokfS9ljzG#`{zj{$Or$=R)(Qc$*fs#-pb;c_xAZTPJOn)wZa0{S|7qzQ@Dd_d*FMIjOAWUf!6!~W*}x8;i!;Nw zbvpTnX;EDL`rnuq=JX;&C3m#=>$EOdTm9AmV*Bk)jaGo56TFh47aq28; z;wRwHUGL#NXdr;SU{5$QlVJmn12-$=LL z2m4k2R@0VxU;d4So`JrCHc>q-AjO*nt(d&*9UPM$EicU(p&1q`Z#mi)o_THiaL3An zth^bM%v0KO4o!|K+O&=YEI(V*9KU@Vy_hP|PQ!`qugb*!UC}=k3Y%W!@2M)O(`G-b)|9px2slDnrvpkGDG)~VQsu%W|jMbs<0=YC>CXvu8@A= zF^ZYkS?G9((QLBGyI3rDu&u!e`)2F$sY_(7AdiM}7_mult=vAssynRrGH$}K--=wa z4PNGn{lIPW7(v`J|sW)>xJil$=PxNsPqT)}|o_4>KT|78@Z?EHW#KY6?IS+lz zH2|ZCyJ}wl#mc3FK{xqFQ4OaD`orzs9!+8ssd@dIaOc zMNe`}bH<}L?{k5U~Y-3nFZA+DMQtTLTGM~lU6SsA&ODBsRQ z?VPAzZ<^$OI$IQUpVOg>cttKXHa0G!4fj7AsIu_pF7trYRPLA%n{MqF3QPD0+xti@ zm!mnz{;a!SEZd-kn?s;WPIr-D(3K93T(gg>cjCOee!RJe6ut~SdqNLZnbEWiHHgQl zQbK<6faQ3mUO~63&*r|J&Rc;-G7Soc#4(@bw)*|@=76l(E(qiWvANFW?6w#NU_>el z0auUb+`7H*$_!GKW>`k*a6HTi_bE#HG*H%$A|ED^^;YM-Tw6CqBndzQDtaQ}=;xV= zdnCKz`$ad9dcWSjWVB_bLH;$#+$L^ntH^OpJPyZ!)^=Jlp{|p60iMDw5nbnqN z#2C4NW@n#Hh%VXj;)E>>a&4*%Y;Tze+jDNtxQ|PJva@tDNq;Kl<})T!cb~S-UCO!Ps}fy&nuS zI~%J#?7$4xP*OP7A@%6bQK)IAV90jsg@jHC;4YIN8p#qE!C-dnDd9ff`?;56lqvJ? zd2cDVYUFJIs6m-GDn_XxM2Q1=&*)H9d1P;7U~jR(dr0SNwG5(iP)}<;Sgf?`*sX#pY(ppo_r`?^u6Az|H(*o-grke zBLhR5tPAVoe__C$so7g~L-nyAjO427zyN^H*#ZKyhw|nlwleh}6{bL_ZFl>5vi5;0 zlY&mQ^<$62qB`2$Uy^*wupzxtTMSz`dr#$xBVStA-g=b~cK`p?-j#<_nYMAx97~8+ zTSC;7F}Os+SQEz?TaG2s$W-=0DSNi0GWO{(mKa)W#}cw7r&XLLBnJ~&3dyk*4(8}M zbH8WnYySKG{jTr)d9L?)-sgIr=Y8(`{{8OX{fPbaOvgtg$f(&PqI5>j$uFv}Y=xH9 zOvl7kboqp6pI9s9t5QbKyP!0Rb10=GwDg$!oC=R%wSA*4|LZXAGwQ0ryZG}Bs13)ztyfvG)I7X2&vMEg+ zK$#WqnHFno8Skp9I2WM@BYdoT)4Cz=h(O%b6;%zDJ*1|i<@uZI#5HKoSEJq^Uki_` zsEQ0DM%AzL6f|7_ba1NT>UrJqh3hpB+|O{Flcz+m@H46E`ghY~Tr=)E@fFAs^yQ-& z4ciy$7*SS^{z{p8)bh7+{nm4L7G_&LMfMK{%_!@CFTr@fv9`E`=w4Gz`gysAtPvnb zXbqeT`}y_-YG%B3!k?W|J|6FY+RkLs*R|QYUG;Q_g&vH7W^Hh1;$Ta5S-vkB+hAij z?NsUEPas!3RJ|2znkRRps;GzA*hdV1QPtXjSAmGlATio)wYMv*!W;4s z16O*BvGX@lx`HY3-m=8?Uz$K1PPUwgYC8AGQ$hH?xTiJ6!G50hw)ERST+K0z#v^V&9L2m4*Mon>7c`>1JQa$YV$?>kFsO$1V8 z1&ibyvy1cp`e{k>gQ55ba)rfZOI+KV+egTgm2bv&{=mSmFT@X6ED@v2_Z#+6bMrq} zh7lMspH`=L0H57SbztyL)X!U;*MG{a@s2pXU@aao!IPI^D4z%$lBI>Ma(Yoa57lz= z18@9(6F#&eZ6d-CzkWMx&<4 zGQpgfR^2H(niwRJL<#@K&)1Xete; z468JHU2Bs&R2Fh_=)(jL1L}(=-*9@R@I;sFronQw}Gj z{89e>diU8;7Zj1_+v02=s9!L`_(%-tFbFM9{;&%KH5P5qv>hoIC19dUa)W7w=y?zgmRH(RQ4XF+$o>;D#V#W_V zC<6#+X@afp9Am-$8w%%3Zp_>BpKdD>6mXaeF22KR2A%hwXLkM+&m%0+N1Z*Wc zwn%g1b0!kQ{p`6)ZRX=QtifxiT)xEr_2{_=Jjc;wMqIHah}8bS9`=z&v`lhu(TB{N zRd36#K&sfoXkN^z4AQul4?Tnuy@4y@Y6gQh;P=!k;329bNWg0NGNt2{Q=P$RU^`&1 zh1*Nij@?+d^4E&jlJlmANDoNw<8UuGfUwk*#>8vIn}VF7x9kl%J<~(U38!*LNzhD+d2 zJ}X`Hg*$~Wp&St@ED}eP48tlB>ENXUN4Bver^BFN_R>rh^%HI~@|aI##?=0Hv#Lri zIv6W_U;KSpA(;Ak)J|0Q*%b@tZmD4nB$Jo93fzEwRe^*393OCMas>LT+8h)0X$RjqVyAUqpDtH({T^trr3ae=!RH!*=cBHr^Rm`1 z3jr-&7v4VQ%11t=^!KUx3}89m*8tOs2dUFyPW&}+g|73&B6>hp#L8vCQoB$auv54K zaZ7CHjOT)VK;GWEh!e{?h7tgb&cj=XE@$_!rr{I9w5cgt84d{nHkQuPUl!_|U|~S* zvvo3ud14;|mhsIwMWpH!d_dI*96GIN$w*O#TyzY=U2VW-dx+s$CUl?xX|YpCRLhgQn<)L)j?vY)|dz?AI76kIwQkg4X$iBCV!Vo&Qj7jTg8^= z{;$h++`8Q)DhHK{Y-5bbn0=}&fM327;D)i!!bU4U2<>)X&UlRN(rt+BUQ5f2(zTP> zII&ahy&y{P?q+!;$v}X80(^vNqVQd@`=p$fm7^BFb<)DQpTu8?z# znip(-=wyy_HZ2OPtox*ALWX+=C-FSmcLI&Ru&G^E&tgkYGj`(MNLGt^Zkg6vTB60K zs|RBbqq;+P1kzX>u+b)%eB;sd14Q)x2)I5axffSUS2|!fUmNg;C>&-A;-r zG{8tTuSwa8naQx>lGqezy3oOeWmZo+kpVH?DbqMaV@;|hS0bC`L|p`pf) zG>`N#)=uG~G#8PhyEFC8SH~?6iWl&G{uncH&biEn1V`b#jayV?SJ&aRG2(#%@fM_W ziVd<~A+HU)arARLr{od)aS(ey^5TlUSslav0^PFP7v1vzhs|8c|E<|3%`MpXYUMnc z4#^~CtlS@)+mgaHuC_{dyhED2j|Taf*w?3;G5^0S)VR@148K#$lOTGqeQ&PlNlrmx z!N05#mH6y{WgOVy*w8I!b|iIv(RbsoC*eaE3Lu1K?jyHzu@uGRKt$O+uff#PL!Ae6 zFI%PXT+E;U`W{Z&0#SkF=y4KGSY2$IfGuuoV5G^(JzzDvY8uNBXk7j%6ytPfk_UcR MxR|N(klV$709C^41ONa4 From bad6fdbbda7992b7bd5461ffbd6b2576eb33ce2b Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Wed, 24 Sep 2025 20:00:42 -0400 Subject: [PATCH 050/327] added comm protocol concept doc and updated event doc --- VERSION | 2 +- autodocs/concepts.rst | 43 ++++- docs/concepts/communication_protocol.md | 114 ++++++++++++ docs/concepts/events.md | 237 +++++++++++++----------- 4 files changed, 280 insertions(+), 116 deletions(-) create mode 100644 docs/concepts/communication_protocol.md diff --git a/VERSION b/VERSION index f19fbd1bf..ca471aaa9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.23T21.21.23.699Z.dfa95f90.master +0.1.0+2025.09.25T00.00.42.365Z.a3fa17c9.master diff --git a/autodocs/concepts.rst b/autodocs/concepts.rst index f6c06c98e..00aca9db6 100644 --- a/autodocs/concepts.rst +++ b/autodocs/concepts.rst @@ -2,17 +2,42 @@ Concepts ============= Explanations of key ideas, principles, and background knowledge. +Follow this recommended sequence to build context before diving into +implementation details: + +- :doc:`History ` - establishes the background and + problem space the project is addressing. +- :doc:`System Design ` - explains how the product + strategy and user needs translate into an overall system approach. +- :doc:`Architecture ` - outlines the concrete + architecture that implements the system design. +- :doc:`Technologies ` - surveys the primary tools + and platforms we rely on to realize the architecture. +- :doc:`Events ` - introduces the event model that drives + data flowing through the system. +- :doc:`Reducers ` - details how incoming events are + aggregated into the state our experiences depend on. +- :doc:`Communication Protocol ` - discusses how + the system queries data from reducers for dashboards. +- :doc:`Scaling ` - covers strategies for growing the + system once the fundamentals are in place. +- :doc:`Auth ` - describes authentication considerations + that secure access to the system. +- :doc:`Privacy ` - documents how we protect learner data + and comply with privacy expectations. .. toctree:: + :hidden: :maxdepth: 1 :titlesonly: - docs/concepts/architecture.md - docs/concepts/auth.md - docs/concepts/events.md - docs/concepts/history.md - docs/concepts/privacy.md - docs/concepts/reducers.md - docs/concepts/scaling.md - docs/concepts/system_design.md - docs/concepts/technologies.md + docs/concepts/history + docs/concepts/system_design + docs/concepts/architecture + docs/concepts/technologies + docs/concepts/events + docs/concepts/reducers + docs/concepts/communication_protocol + docs/concepts/scaling + docs/concepts/auth + docs/concepts/privacy diff --git a/docs/concepts/communication_protocol.md b/docs/concepts/communication_protocol.md new file mode 100644 index 000000000..c9ca1accf --- /dev/null +++ b/docs/concepts/communication_protocol.md @@ -0,0 +1,114 @@ +# Communication Protocol + +The communication protocol is Learning Observer's query and transport +layer. It allows dashboards, notebooks, and other clients to request +aggregated data from the key-value store and supporting services by +submitting a declarative *execution DAG* (directed acyclic graph). The +server evaluates the DAG node-by-node, resolves the required +parameters, executes reducers or helper functions, and returns the +assembled result. This document explains how that process fits +together, the core building blocks you can use in a query, and the +helper utilities that make it easier to integrate those queries into +applications. + +## Lifecycle of a Request + +1. **Query construction** - A client builds a nested query description + in Python (or another language) with the helpers in + `learning_observer.communication_protocol.query`. The helpers mirror + relational concepts such as parameters, joins, and projections and + produce JSON-serialisable dictionaries. (See: query.py L1-L123) +2. **Flattening** - Before execution, the DAG is normalised so every + node has a unique identifier and can reference other nodes via + `variable` pointers. The `flatten` utility rewrites nested + structures such as `select(keys(...))` into separate nodes to make + evaluation straightforward. (See: util.py L1-L59) +3. **Execution** - The executor walks the flattened DAG, dispatching + each node type to a registered handler. Nodes can call Python + functions, fetch keys from the key-value store, join intermediate + datasets, or map functions across collections. The executor + assembles the final payload and enforces error handling through the + `DAGExecutionException` type. (See: executor.py L1-L145, L147-L220) +4. **Exports** - Queries expose named *exports* that identify the DAG + nodes clients may request. The integration layer can bind those + exports to callables so dashboards or notebooks can invoke them as + regular async functions. (See: util.py L64-L104, integration.py L38-L102) + +This flow supports both server-defined queries and open-ended +exploration. Production deployments typically offer curated, predefined +queries while development tooling exposes the full language for +experimentation. (See: README.md L11-L36) + +## Core Node Types + +Every node in the execution DAG has a `dispatch` type that determines +how the executor evaluates it. The query helper functions generate the +correct shape for each node type. (See: query.py L19-L123) The most common nodes are: + +- **`parameter`** - Declares a runtime argument. Parameters can be + required or optional, and the executor substitutes provided values or + defaults before downstream nodes run. (See: query.py L33-L42, executor.py L114-L144) +- **`variable`** - References the output of another node in the DAG. + These indirections are automatically inserted during flattening but + can also be used explicitly when wiring complex queries. (See: query.py L45-L52, util.py L13-L61) +- **`call`** - Invokes a published Python function on the server. + Functions are registered with `publish_function`, which ensures every + callable has a unique name. Called functions may be synchronous or + asynchronous; the executor awaits results as needed. (See: query.py L55-L67, executor.py L61-L112, integration.py L21-L47) +- **`keys`** - Produces the key descriptions required to fetch reducer + outputs from the key-value store. Keys nodes typically wrap the + outputs of roster or metadata queries so downstream `select` nodes + can retrieve the associated reducer documents. (See: query.py L114-L123, util.py L72-L102) +- **`select`** - Retrieves documents from the key-value store for the + provided keys. You can request all fields or limit to specific + projections via `SelectFields` enumerations. (See: query.py L70-L83) +- **`join`** - Merges two lists of dictionaries on matching keys using + dotted-path lookups. Left rows are preserved even without a matching + right-hand record, making it straightforward to enrich reducer + outputs with roster data. (See: query.py L86-L96, executor.py L147-L220) +- **`map`** - Applies a published function to each value in a list, + optionally in parallel, returning the transformed collection. This is + useful for server-side post-processing or feature extraction before a + result is exported. (See: query.py L99-L111) + +## Building Queries Efficiently + +Writing DAGs by hand is verbose, so the protocol provides shorthands +for common access patterns. For example, +`generate_base_dag_for_student_reducer` returns an execution DAG that +retrieves the latest reducer output for every student in a course, +including roster metadata and a preconfigured export entry. Dashboards +use this helper to quickly expose reducer results without writing the +full DAG each time. (See: util.py L63-L101) + +The `integration` module can also bind exports directly to a module so +code can call `await module.student_event_counter_export(course_id=...)` +instead of manually constructing requests. This keeps the protocol's +flexibility while offering ergonomic entry points for UI +components. (See: integration.py L49-L102) + +## Tooling and Debugging + +Two exploratory tools live alongside the protocol implementation: + +- `debugger.py` - Provides an interface for submitting ad-hoc queries + and inspecting intermediate results. +- `explorer.py` - Lists predefined queries already published on the + server so you can execute them interactively. + +Because the protocol is evolving, these tools occasionally require +updates when the underlying schema changes. Keeping the communication +protocol documented and covered by tests makes it easier to spot and +fix those regressions quickly. (See: README.md L45-L72) + +## Security Considerations + +Production deployments default to predefined queries so clients can +only request vetted datasets. Open-query mode should be restricted to +trusted environments—such as local notebooks or read replicas—because +it allows arbitrary function calls and joins that may expose sensitive +information or stress backing stores. (See: README.md L11-L36) + +Understanding these concepts makes it easier to extend the protocol, +design new reducers, and reason about the performance characteristics +of dashboards built on Learning Observer. diff --git a/docs/concepts/events.md b/docs/concepts/events.md index 8eb8bfec7..e2f49301c 100644 --- a/docs/concepts/events.md +++ b/docs/concepts/events.md @@ -1,106 +1,131 @@ -Event Format Notes -================== - -Our event format is inspired in part by: - -* IMS Caliper -* xAPI/Tincan -* edX tracking log events - -None of these are _quite_ right for our application, but several are -close. They're pretty good standards! - -Limitations of industry formats -------------------------------- - -*Verbosity* Both Caliper and xAPI require a lot of cruft to be -appended to the events. For example, we have random ID GUIDs, URLs, -and all sorts of other redundancy on each event. Having things have -either *a little* bit of context (e.g. a header) or *a little* -rationale (e.g. IDs which point into a data store) is sometimes good, -but too much is a problem. With too much redundancy, events can get -massive: - -* Our speed in handling large data scales with data size. Megabytes - can be done instantly, gigabytes in minutes, and terabytes in - hours. Cutting data sizes makes working with data easier. -* Repeating oneself can lead to inconsistent data. Data formats where - data goes one place (or where redundancy is *intentional* and - *engineered* for data correction) is more robust and less bug-prone. - -*Envelopes* Caliper payloads are bundled in JSON envelopes. This is -a horrible format since: - -* It results in a lot of additional parsing... -* ... of very large JSON objects -* If there's an error or incompatibility anywhere, you can easily lose - a whole block of data -* You can't process events in realtime, for example, for formative - feedback - -Text files with one JSON event per line are more robust and more -scalable: - -* They can be processed as a stream, without loading the whole file -* Individual corrupt events don't break the entire pipeline -- you can - skip bad events -* They can be streamed over a network -* They can be preprocessed without decoding. For example, one can - filter a file for a particular type of event, student ID, or - otherwise with a plain text search. The primary goal of first-stage - preprocessing is simply to quickly cut down data size, so it doesn't - need to be reject 100% of irrelevant events. - -*Details* In many cases, the details of a format are inappropriate for -a given purpose. There are event types which are in neither -Tincan/xAPI nor Caliper, and don't fit neatly into their -frameworks. For example: - -* Formats specify timestamps with great precision, while coarse events - (such as a student graduating) don't maintain that precision. -* In one of our clients, events are generated without a user - identifier, which is then added by the server once the user is - authenticated. For these events, validation fails. -* Related to the above, fields are sometimes repeated (e.g. client-side - timestamp, server-side timestamp, and further timestamps as the event - is processed by downstream systems). Much of this fits into security; - downstream systems _should not_ trust data from upstream systems. For - example, a student shouldn't be able to fake submitting a homework - assignment earlier than they did, and a school should not be able to - backdate a state exam response. - -There are similar minor mismatches to e.g. group events, very frequent -events (such as typing), and other types of events not fully -anticipated when the standards were created. - -I'd like to emphasize that in contrast to most industry formats, these -are quite good. They're not fundamentally broken. - -How we'd like to leverage industry formats ------------------------------------------- - -Fortunately, we don't need 100% compatibility for pretty good -interoperability. Our experience is that event formats are almost -never interchangeable between systems; even with standardized formats, -the meaning changes based on the pedagogical design. This level of -compatibility is enough to give pretty interoperability, without being -constrained by details of these formats. - -Our goal is to be compatible where convenient. Pieces we'd like to -borrow: - -* Critically, the universe has converged on events as JSON lines. This - already allows for common data pipelines. -* We can borrow vocabulary -- verbs, nouns, and similar. -* We can borrow field formats, where sensible - -With this level of standardization, adapting to data differences is -typically already less work than adapting to differences in underlying -pedagogy. - -Where we are ------------- - -We have not yet done more careful engineering of our event -format. Aside from a JSON-event-per-line, the above level of -compatibility is mostly aspirational. \ No newline at end of file +# Event Format + +Our event format is inspired in part by IMS Caliper, xAPI/Tincan, and the edX +tracking log events. None of these standards are quite right for our +application, but several are close. They're pretty good standards! + +## Limitations of Industry Formats + +* **Verbosity.** Both Caliper and xAPI require a lot of cruft to be appended to + events. For example, we have random GUIDs, URLs, and other redundancy on each + event. Having a little bit of context (e.g. a header) or a little rationale + (e.g. IDs which point into a data store) is sometimes good, but too much is a + problem. With too much redundancy, events can get massive: + * Our speed in handling large data scales with data size. Megabytes can be + done instantly, gigabytes in minutes, and terabytes in hours. Cutting data + sizes makes working with data easier. + * Repeating oneself can lead to inconsistent data. Data formats where data + goes in one place (or where redundancy is intentional and engineered for + data correction) are more robust and less bug-prone. +* **Envelopes.** Caliper payloads are bundled in JSON envelopes. This is a + horrible format because: + * It results in a lot of additional parsing... + * ... of very large JSON objects. + * If there's an error or incompatibility anywhere, you can easily lose a + whole block of data. + * You can't process events in realtime, for example, for formative feedback. + +Text files with one JSON event per line are more robust and more scalable: + +* They can be processed as a stream, without loading the whole file. +* Individual corrupt events don't break the entire pipeline-you can skip bad + events. +* They can be streamed over a network. +* They can be preprocessed without decoding. For example, you can filter a file + for a particular type of event, student ID, or otherwise with a plain text + search. The primary goal of first-stage preprocessing is simply to quickly cut + down data size, so it doesn't need to reject 100% of irrelevant events. + +* **Details.** In many cases, the details of a format are inappropriate for a + given purpose. There are event types which are in neither Tincan/xAPI nor + Caliper, and don't fit neatly into their frameworks. For example: + * Formats specify timestamps with great precision, while coarse events (such + as a student graduating) don't maintain that precision. + * In one of our clients, events are generated without a user identifier, which + is then added by the server once the user is authenticated. For these + events, validation fails. + * Related to the above, fields are sometimes repeated (e.g. client-side + timestamp, server-side timestamp, and further timestamps as the event is + processed by downstream systems). Much of this fits into security; + downstream systems should not trust data from upstream systems. For example, + a student shouldn't be able to fake submitting a homework assignment earlier + than they did, and a school should not be able to backdate a state exam + response. + +There are similar minor mismatches for group events, very frequent events (such +as typing), and other types of events not fully anticipated when the standards +were created. + +I'd like to emphasize that, in contrast to most industry formats, these are +quite good. They're not fundamentally broken. + +## How We'd Like to Leverage Industry Formats + +Fortunately, we don't need 100% compatibility for pretty good interoperability. +Our experience is that event formats are almost never interchangeable between +systems; even with standardized formats, the meaning changes based on the +pedagogical design. This level of compatibility is enough to give interoperability +without being constrained by details of these formats. + +Our goal is to be compatible where convenient. Pieces we'd like to borrow: + +* Critically, the universe has converged on events as JSON lines. This already + allows for common data pipelines. +* We can borrow vocabulary-verbs, nouns, and similar. +* We can borrow field formats, where sensible. + +With this level of standardization, adapting to data differences is typically +already less work than adapting to differences in underlying pedagogy. + +## Where We Are + +We have not yet done more careful engineering of our event format. Aside from a +JSON-event-per-line, the above level of compatibility is mostly aspirational. + +## Incoming Event Flow + +Incoming events reach the Learning Observer through `/wsapi/in/`, which +establishes a long-lived websocket for each client session. The websocket stream +is processed through a series of generators that progressively enrich and +validate each message before it reaches reducers. + +1. **Initial decode and logging.** Every websocket frame is decoded by + `event_decoder_and_logger`, which writes the raw payloads to per-session log + files. When the Merkle feature flag is enabled, the same routine also commits + events to the Merkle store using the configured backend. This stage ensures + that we always have an immutable audit log of the stream. +2. **Lock fields and metadata.** Clients typically send a `lock_fields` event + first to declare metadata such as the `source`, `activity`, or other + immutable context. These fields are cached and injected into subsequent + events so downstream reducers receive consistent metadata. Server-side + metadata like IP and user agent is added separately via `compile_server_data` + and cannot be spoofed by the client. +3. **Authentication.** The pipeline buffers events until + `learning_observer.auth.events.authenticate` confirms the session. Successful + authentication attaches the derived `auth` context-containing identifiers + like the `user_id`-to each event before it continues. The websocket + acknowledges authentication so the client can react if credentials are + missing or invalid. +4. **Protection stages.** Events flow through guardrails that: + * stop processing on an explicit `terminate` event and close the associated + log files, + * block sources that appear on the runtime blacklist, notifying the client + when a block occurs, and + * handle optional blob storage interactions (`save_blob` and `fetch_blob`) + that reducers can request. +5. **Reducer preparation.** After authentication and metadata are in place we + call `handle_incoming_client_event`. This builds a pipeline from the declared + client `source`. Each source maps to a set of stream analytics modules that + expose coroutine reducers. Reducers are partially applied with metadata + (including the authenticated user) so they can maintain per-student state. +6. **Reducer execution.** Every canonicalized event passes through the prepared + reducers. Events are logged a second time-now with server metadata and + authentication context-and reducers update their internal state. If the + reducer definitions change during a session (e.g. due to a hot reload in + development) the pipeline is rebuilt on the next event. + +This staged processing allows us to maintain separate concerns for logging, +authentication, safety checks, and analytics while keeping the event format +itself lightweight. Clients only need to agree on the JSON structure of events, +while the server handles durability and routing responsibilities on their +behalf. From 1c72d9e151fcbc3c43bd44fd3cee0ce8a62de093 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Thu, 25 Sep 2025 12:23:50 -0400 Subject: [PATCH 051/327] more descriptive table of contents plus initial communication protocol documentation how to --- VERSION | 2 +- autodocs/how-to.rst | 11 +- autodocs/reference.rst | 11 +- autodocs/tutorials.rst | 6 +- docs/concepts/communication_protocol.md | 17 ++ docs/how-to/communication_protocol.md | 210 ++++++++++++++++++++++++ 6 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 docs/how-to/communication_protocol.md diff --git a/VERSION b/VERSION index ca471aaa9..08b27df3a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.25T00.00.42.365Z.a3fa17c9.master +0.1.0+2025.09.25T16.23.50.822Z.bad6fdbb.master diff --git a/autodocs/how-to.rst b/autodocs/how-to.rst index 534354882..deec45815 100644 --- a/autodocs/how-to.rst +++ b/autodocs/how-to.rst @@ -1,12 +1,21 @@ How-to ============= -Practical instructions to solve specific problems or achieve goals. +Practical instructions for achieving specific goals within Learning Observer. Use these guides when you know what outcome you need and want a proven recipe to follow: + +- :doc:`Communication Protocol ` - How to query data from reducers or system endpoints for dashboards. +- :doc:`Configure Learning Observer ` - Set up credentials, environment variables, and other configuration details required for a smooth deployment. +- :doc:`Build Dashboards ` - Walk through creating dashboards from reducer outputs, including layout choices and data wiring. +- :doc:`Run with Docker ` - Learn how to containerize the stack, manage images, and operate the project using Docker Compose. +- :doc:`Writing Observer Extension ` - Install, configure, and validate the Writing Observer browser extension for capturing events. +- :doc:`Interactive Environments ` - Connect Learning Observer to Jupyter and other live coding setups for iterative development. .. toctree:: + :hidden: :maxdepth: 1 :titlesonly: + docs/how-to/communication_protocol.md docs/how-to/config.md docs/how-to/dashboards.md docs/how-to/docker.md diff --git a/autodocs/reference.rst b/autodocs/reference.rst index 5df3f458d..dbc769734 100644 --- a/autodocs/reference.rst +++ b/autodocs/reference.rst @@ -1,9 +1,18 @@ Reference ============= -Detailed, structured information about APIs, configurations, and technical details. +Detailed, structured information about APIs, configurations, and technical details. Consult these resources when you need definitive answers about how the system behaves or how to integrate with it: + +- :doc:`Code Quality Standards ` - Understand our expectations for readability, style, and continuous improvement. +- :doc:`Documentation Conventions ` - Learn how we structure docs, what tools we use, and how to contribute updates. +- :doc:`Linting Rules ` - Review the automated checks that keep the codebase healthy and how to run them locally. +- :doc:`Testing Strategy ` - Explore the testing layers we rely on and guidelines for writing reliable tests. +- :doc:`Versioning and Releases ` - See how we tag releases, manage dependencies, and maintain backward compatibility. +- :doc:`Module Reference ` - Dive into the autogenerated API reference for Python modules within Learning Observer. +- :doc:`API Reference ` - Inspect the internal functionality of the system. .. toctree:: + :hidden: :maxdepth: 1 :titlesonly: diff --git a/autodocs/tutorials.rst b/autodocs/tutorials.rst index 580567507..0d6771b53 100644 --- a/autodocs/tutorials.rst +++ b/autodocs/tutorials.rst @@ -1,9 +1,13 @@ Tutorials ============= -Step-by-step guides to help you learn by doing. +Step-by-step guides that teach by doing. Follow these tutorials to get hands-on experience with core workflows: + +- :doc:`Install Learning Observer ` - Set up the development environment, install dependencies, and verify your deployment. +- :doc:`Create a Module with Cookiecutter ` - Generate a new module scaffold, customize it, and understand the key files produced by the template. .. toctree:: + :hidden: :maxdepth: 1 :titlesonly: diff --git a/docs/concepts/communication_protocol.md b/docs/concepts/communication_protocol.md index c9ca1accf..3738286a4 100644 --- a/docs/concepts/communication_protocol.md +++ b/docs/concepts/communication_protocol.md @@ -87,6 +87,23 @@ instead of manually constructing requests. This keeps the protocol's flexibility while offering ergonomic entry points for UI components. (See: integration.py L49-L102) +## WebSocket Endpoint + +Dashboards and other clients interact with the communication protocol +through a dedicated WebSocket endpoint exposed at +`/wsapi/communication_protocol`. The aiohttp application wires that path +to `websocket_dashboard_handler`, making the protocol available to +browser sessions and backend consumers alike. (See: learning_observer/routes.py L195-L213) + +When a client connects, the handler waits for a JSON payload describing +one or more queries. Each entry typically includes the flattened +`execution_dag`, a list of `target_exports` to stream, and optional +`kwargs` that provide runtime parameters. Whenever the client submits a +new payload, the server builds the requested DAG generators, executes +them, and schedules reruns based on the provided settings. Responses are +batched into arrays of `{op, path, value}` records so the client can +efficiently apply partial updates to its local state. (See: learning_observer/dashboard.py L331-L411) + ## Tooling and Debugging Two exploratory tools live alongside the protocol implementation: diff --git a/docs/how-to/communication_protocol.md b/docs/how-to/communication_protocol.md new file mode 100644 index 000000000..b72d02fb9 --- /dev/null +++ b/docs/how-to/communication_protocol.md @@ -0,0 +1,210 @@ +# How to Build and Run Communication Protocol Queries + +This guide explains the end-to-end workflow for turning a reporting idea into a runnable query on the Learning Observer communication protocol. Follow the steps in order—both humans and language models can use this as a checklist when creating or automating queries. + +## 1. Frame the Data Task + +1. Write a one-sentence description of the insight or dataset you need (e.g., *“Return the latest writing sample for each student in a course”*). +2. Identify the reducers, helper functions, or key-value store documents that expose the data. Concept docs provide summaries of the executor lifecycle, node types, and utilities for transforming reducer outputs. 【F:docs/concepts/communication_protocol.md†L1-L100】 +3. Check whether an existing helper (e.g., `generate_base_dag_for_student_reducer`) already provides most of the DAG structure. Reusing helpers keeps queries consistent and concise. 【F:docs/concepts/communication_protocol.md†L62-L87】 + +## 2. Confirm Your Goal and Required Data + +1. Identify the data source(s): + + * **Reducers** - Aggregated documents stored in the key-value store. + * **Helper functions** - Python callables published with `publish_function`. + * **Roster/metadata** - Collections that need to be joined with reducer data. +2. Decide which fields must appear in the output. Note whether you need the entire document or only specific fields. +3. List all runtime values (course ID, time range, student list, etc.). These become `parameter` nodes later. + +Document these choices (in comments or metadata) so you can refer to them in later steps. + +## 3. Declare Parameters and Defaults + +Each runtime input must be expressed as a `parameter` node. Parameters can be required or optional and may include default values: + +```python +course_id = query.parameter("course_id", required=True) +student_id = query.parameter("student_id", required=False, default=None) +``` + +For each parameter, document: + +* **Name** - Identifier passed to the DAG node. +* **Type** - String, UUID, ISO date, etc. +* **Required** - Boolean flag. +* **Default** - Optional fallback value. + +> Tip: Emit parameter declarations first so later steps can reuse variables like `course_id["variable"]` consistently. + +For fixed values (e.g., reducer names or field lists), define constants once near where they are used. + +## 4. Plan the Data Flow (DAG Skeleton) + +Translate the goal into a linear sequence of operations. A typical reducer query involves: + +1. Fetching roster metadata or other context. +2. Producing keys for each entity (`keys` nodes). +3. Retrieving reducer documents with `select`. +4. Joining reducer outputs with metadata. +5. (Optional) Post-processing with `map` or `call`. + +Example outline: + +``` +roster = call("get_course_roster", course_id) +reducer_keys = keys(reducer_name, roster.students) +reducer_docs = select(reducer_keys, fields=[...]) +enriched = join(reducer_docs, roster, left_on="student.id", right_on="id") +export enriched +``` + +Verify that every step depends only on earlier outputs, and adjust until the flow is acyclic. + +## 5. Construct Nodes with Query Helpers + +Use `query.py` helpers to implement the skeleton: + +```python +from learning_observer.communication_protocol import query + +roster = query.call("get_course_roster", args={"course_id": course_id}) +reducer_keys = query.keys( + reducer="reading_fluency", + entities=query.variable(roster, "students"), +) +reducer_docs = query.select( + keys=reducer_keys, + fields=query.SelectFields.SUMMARY, +) +enriched = query.join( + left=reducer_docs, + right=query.variable(roster), + left_on="student_id", + right_on="id", +) +``` + +Guidelines: + +* Use `query.variable(node, path=None)` for downstream access to prior outputs. +* Encapsulate repeated or complex logic in functions for reuse and testing. +* Use explicit names and keyword arguments—avoid positional arguments for clarity. + +## 6. Define Exports and Integrations + +Choose which nodes should be externally accessible: + +```python +exports = { + "reading_fluency": query.export("reading_fluency", enriched) +} +``` + +If integrating with the async helper layer, pass `exports` to `learning_observer.communication_protocol.integration.bind_exports`. + +Document required parameters and defaults with the export definitions. + +## 7. Flatten, Validate, and Serialise + +1. Convert the nested DAG into executor-ready form: + + ```python + from learning_observer.communication_protocol import util + dag = util.flatten(exports) + ``` + +2. Confirm all node IDs are unique and reference earlier nodes. Inspect the flattened DAG if generated automatically. + +3. Serialise to JSON (e.g., `json.dumps(dag)`) when sending over the wire. + +4. Add automated tests—at minimum a smoke test against a fixture store. + +## 8. Expose the DAG to Clients + +To make the DAG discoverable over the websocket interface: + +* Define `EXECUTION_DAG` in the module file and register it with the loader. +* On server start, the DAG will be advertised under the module’s namespace. + +Production deployments should prefer predefined DAGs for security. Open-query mode is optional and must be explicitly enabled. + +## 9. Execute the Query + +Submit the flattened DAG to the communication protocol endpoint with runtime parameters: + +```json +{ + "parameters": { + "course_id": "course-123", + "start_date": "2023-09-01" + }, + "exports": ["reading_fluency"], + "dag": { ... flattened nodes ... } +} +``` + +On success, the response includes export payloads keyed by export name. Inspect `DAGExecutionException` for error details. + +When using integration bindings, call the generated async function with the same parameters. + +## 10. Construct Websocket Requests + +Clients interact with `/wsapi/communication_protocol` via JSON messages. Each message contains: + +* `execution_dag` - Name of a predefined DAG or a full DAG object. +* `target_exports` - List of exports to run. +* `kwargs` - Runtime parameters. + +Example: + +```json +{ + "docs_request": { + "execution_dag": "writing_observer", + "target_exports": ["docs_with_roster"], + "kwargs": { "course_id": "COURSE-123" } + } +} +``` + +The server streams back updates in messages shaped like: + +```json +[ + { + "op": "update", + "path": "students.student-1", + "value": { "text": "...", "provenance": { ... } } + } +] +``` + +If `rerun_dag_delay` is set, the server automatically re-executes the DAG and pushes updates. + +## 11. Iterate and Maintain + +* Profile slow queries; large joins may need new helpers or precomputed reducers. +* Keep DAGs version-controlled. Update dependent queries when reducers or helpers change. +* Review security before exposing exports to untrusted clients. + +## 12. Test End-to-End + +* **Unit-test** reducers and helpers independently. +* **Reference** `learning_observer/learning_observer/communication_protocol/test_cases.py` for DAG tests. +* **Exercise websocket flows** manually or with automated integration tests. + +## 13. Document Parameters and Outputs + +Update module documentation with: + +* Export descriptions, parameter types, and return structures. +* Sample request payloads. +* Notes on authentication or runtime context. + +Good documentation ensures developers and tooling can invoke queries reliably. + +### Summary + +Following this workflow ensures queries are consistent, testable, and safe to expose across dashboards, notebooks, and automation tools. From d6047986b4ba0548038649c9e5699f5e56d1f16e Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 30 Sep 2025 11:53:18 -0400 Subject: [PATCH 052/327] updated documentation for modules --- VERSION | 2 +- autodocs/conf.py | 122 ++++++++++++++- autodocs/modules.rst | 2 +- docs/reference/documentation.md | 32 ++-- learning_observer/VERSION | 2 +- .../learning_observer/integrations/google.py | 4 +- modules/wo_bulk_essay_analysis/README.md | 71 +++++++++ modules/wo_bulk_essay_analysis/VERSION | 2 +- .../_images/bulk-essay-analysis-overview.png | Bin 0 -> 157818 bytes .../bulk-essay-analysis-student-tile.png | Bin 0 -> 125229 bytes .../wo_classroom_text_highlighter/README.md | 61 +++++++- modules/wo_classroom_text_highlighter/VERSION | 2 +- .../classroom-text-highlighter-options.png | Bin 0 -> 51037 bytes .../classroom-text-highlighter-overview.png | Bin 0 -> 153503 bytes .../classroom-text-highlighter-student.png | Bin 0 -> 72734 bytes modules/writing_observer/README.md | 141 +++++++++++++----- modules/writing_observer/VERSION | 2 +- 17 files changed, 371 insertions(+), 72 deletions(-) create mode 100644 modules/wo_bulk_essay_analysis/README.md create mode 100644 modules/wo_bulk_essay_analysis/_images/bulk-essay-analysis-overview.png create mode 100644 modules/wo_bulk_essay_analysis/_images/bulk-essay-analysis-student-tile.png create mode 100644 modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-options.png create mode 100644 modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-overview.png create mode 100644 modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-student.png diff --git a/VERSION b/VERSION index 08b27df3a..696424a49 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.25T16.23.50.822Z.bad6fdbb.master +0.1.0+2025.09.30T15.53.18.556Z.1c72d9e1.master diff --git a/autodocs/conf.py b/autodocs/conf.py index 55ec33798..3af5b92ef 100644 --- a/autodocs/conf.py +++ b/autodocs/conf.py @@ -1,8 +1,10 @@ import os import pathlib +import re import shutil import sphinx.util import sys +import unicodedata # Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: @@ -50,8 +52,110 @@ LOGGER = sphinx.util.logging.getLogger(__name__) +_MARKDOWN_IMAGE_PATTERN = re.compile(r'!\[[^\]]*\]\(([^)]+)\)') +_RST_IMAGE_PATTERNS = [ + re.compile(r'\.\.\s+image::\s+([^\s]+)'), + re.compile(r'\.\.\s+figure::\s+([^\s]+)'), +] + + +def _extract_local_assets(text): + """Return relative asset paths referenced in the provided README text.""" + + asset_paths = set() + for match in _MARKDOWN_IMAGE_PATTERN.findall(text): + asset_paths.add(match) + for pattern in _RST_IMAGE_PATTERNS: + asset_paths.update(pattern.findall(text)) + + filtered_assets = set() + for raw_path in asset_paths: + candidate = raw_path.strip() + if not candidate: + continue + # Remove optional titles ("path "optional title"") and URL fragments + candidate = candidate.split()[0] + candidate = candidate.split('#', maxsplit=1)[0] + candidate = candidate.split('?', maxsplit=1)[0] + + if candidate.startswith(('http://', 'https://', 'data:')): + continue + if candidate.startswith('#'): + continue + + filtered_assets.add(candidate) + + return sorted(filtered_assets) + + +def _copy_module_assets(readme_path, destination_dir): + """Copy image assets referenced by ``readme_path`` into ``destination_dir``.""" + + module_dir = readme_path.parent.resolve() + readme_text = readme_path.read_text(encoding='utf-8') + asset_paths = _extract_local_assets(readme_text) + for asset in asset_paths: + relative_posix_path = pathlib.PurePosixPath(asset) + if relative_posix_path.is_absolute(): + LOGGER.warning( + "Skipping absolute image path %s referenced in %s", asset, readme_path + ) + continue + + normalized_relative_path = pathlib.Path(*relative_posix_path.parts) + source_path = (module_dir / normalized_relative_path).resolve(strict=False) + + try: + source_path.relative_to(module_dir) + except ValueError: + LOGGER.warning( + "Skipping image outside module directory: %s referenced in %s", + asset, + readme_path, + ) + continue + + if not source_path.exists(): + LOGGER.warning( + "Referenced image %s in %s was not found", asset, readme_path + ) + continue + + destination_path = destination_dir / normalized_relative_path + destination_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(source_path, destination_path) + + +def _extract_readme_title(readme_path: pathlib.Path) -> str: + """Return the first Markdown heading in ``readme_path``. + + Defaults to the parent directory name if no heading can be found. + """ + + try: + for line in readme_path.read_text(encoding='utf-8').splitlines(): + stripped = line.strip() + if stripped.startswith('#'): + title = stripped.lstrip('#').strip() + if title: + return title + except OSError as exc: # pragma: no cover - filesystem error propagation + LOGGER.warning("unable to read %s: %s", readme_path, exc) + + return readme_path.parent.name + + +def _slugify(text: str) -> str: + """Convert ``text`` to a lowercase filename-safe slug.""" + + normalized = unicodedata.normalize('NFKD', text) + without_diacritics = ''.join(ch for ch in normalized if not unicodedata.combining(ch)) + slug = re.sub(r'[^a-z0-9]+', '-', without_diacritics.casefold()).strip('-') + return slug or 'module' + + def _copy_module_readmes(app): - """Populate ``module_readmes`` with module README files.""" + """Populate ``module_readmes`` with module README files and assets.""" docs_root = pathlib.Path(__file__).parent.resolve() modules_root = docs_root.parent / 'modules' @@ -65,11 +169,21 @@ def _copy_module_readmes(app): shutil.rmtree(destination_root) destination_root.mkdir(parents=True, exist_ok=True) - readme_paths = sorted(modules_root.glob('*/README.md')) - for readme_path in readme_paths: + readme_info = [] + for readme_path in modules_root.glob('*/README.md'): + title = _extract_readme_title(readme_path) + readme_info.append((title, readme_path)) + + readme_info.sort(key=lambda item: item[0].casefold()) + + for title, readme_path in readme_info: module_name = readme_path.parent.name - destination_path = destination_root / f"{module_name}.md" + slug = _slugify(title) + module_destination = destination_root / f'{slug}--{module_name}' + module_destination.mkdir(parents=True, exist_ok=True) + destination_path = module_destination / "README.md" shutil.copy2(readme_path, destination_path) + _copy_module_assets(readme_path, module_destination) def setup(app): diff --git a/autodocs/modules.rst b/autodocs/modules.rst index b267a6da9..a8395ea34 100644 --- a/autodocs/modules.rst +++ b/autodocs/modules.rst @@ -6,4 +6,4 @@ The module READMEs are collected automatically during the Sphinx build. :maxdepth: 1 :glob: - module_readmes/* + module_readmes/*/README diff --git a/docs/reference/documentation.md b/docs/reference/documentation.md index fd3188f15..52ce073de 100644 --- a/docs/reference/documentation.md +++ b/docs/reference/documentation.md @@ -8,36 +8,26 @@ On pushes or pull requests to the main branch, the documentation is auto-built a ## Including documentation -Since documentation is built from the code, you need to follow specific steps to include new documentation elements. +Since documentation is built from the code, every contribution should clearly state what component the documentation describes (for example a module, CLI tool, or feature page). After creating the content, make sure a reference to the source file lives in the appropriate subsection so that Sphinx can locate and render it. ### Markdown file -To include a new markdown file in the documentation, follow these steps: +To document a new page that lives in a standalone markdown file, follow these steps: -1. Place your markdown file in the `docs/` directory. Any images should be placed in `docs/_images`. -2. Add a reference to your markdown file in `autodocs/other_docs.rst`. The reference will look like this: +1. Place the markdown file under the appropriate section in `docs/`. For example, how-to guides live in `docs/how-to/` and reference material belongs in `docs/reference/`. Any images should be placed in `docs/_images`. +2. In the pull request description (and any related communication), specify which page the new file documents so reviewers understand the context. +3. Update the corresponding section index (`autodocs/how-to.rst`, `autodocs/reference.rst`, etc.) to include your new page in its `.. toctree::`. Each index file keeps its toctree organized by the section's subsections, so add a line that points to the new markdown file (for example, `docs/how-to/new_guide.md`). -```rst -.. include:: ../docs/your_markdown_file.md - :parser: myst_parser.sphinx_ -``` - -Replace `your_markdown_file.md` with the name of your markdown file. +This ensures the page is discoverable from the rendered documentation and is built automatically by Sphinx. ### Module -To include a newly added module in the documentation, follow these steps: - -1. Add a reference to the module in `autodocs/modules.rst`. The reference will look like this: - -```rst -.. autosummary:: - :recursive: - :toctree: generated/your_module_name +To document a Python package or module, follow these steps: - your_module_name -``` +1. In your change description, call out the module the documentation targets so the reviewer can verify coverage. +2. Add or update the module's `README.md` under `modules//README.md`. During the Sphinx build, `autodocs/conf.py` copies each module README into `autodocs/module_readmes/`, and `autodocs/modules.rst` automatically includes every file in that directory via a globbed toctree. +3. Make sure the module's docstrings are accurate. The `autodoc2_packages` setting in `autodocs/conf.py` lists the packages whose code documentation is generated automatically, so keeping docstrings up to date ensures the API reference stays correct. -Replace `your_module_name` with the name of your module. +Because the READMEs are gathered automatically, you only need to make sure the README exists alongside the module. The build will pick it up and render it in the Modules section. By following these steps, you can ensure that your new markdown files and modules are properly integrated into the documentation, which will then be automatically built and made available on Readthedocs. diff --git a/learning_observer/VERSION b/learning_observer/VERSION index 0fbb6683f..696424a49 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.09.23T15.55.02.340Z.fb5631b3.master +0.1.0+2025.09.30T15.53.18.556Z.1c72d9e1.master diff --git a/learning_observer/learning_observer/integrations/google.py b/learning_observer/learning_observer/integrations/google.py index de7f85c9a..95e09ff82 100644 --- a/learning_observer/learning_observer/integrations/google.py +++ b/learning_observer/learning_observer/integrations/google.py @@ -207,9 +207,9 @@ def extract_text_from_google_doc_json( length = j['body']['content'][-1]['endIndex'] elements = [a.get('paragraph', {}).get('elements', []) for a in j['body']['content']] flat = sum(elements, []) - text_chunks = [f['textRun']['content'] for f in flat] + text_chunks = [f.get('textRun', {}).get('content', '') for f in flat] if align: - lengths = [f['endIndex'] - f['startIndex'] for f in flat] + lengths = [f.get('endIndex', 0) - f.get('startIndex', 0) for f in flat] text_chunks = [_force_text_length(chunk, length) for chunk, length in zip(text_chunks, lengths)] text = ''.join(text_chunks) diff --git a/modules/wo_bulk_essay_analysis/README.md b/modules/wo_bulk_essay_analysis/README.md new file mode 100644 index 000000000..867001cdc --- /dev/null +++ b/modules/wo_bulk_essay_analysis/README.md @@ -0,0 +1,71 @@ +# Writing Observer - Classroom AI Feedback Assistant + +**Last updated:** September 30th, 2025 + +![Bulk Essay Analysis dashboard overview](_images/bulk-essay-analysis-overview.png) + +The Classroom AI Feedback Assistant dashboard helps teachers generate AI-driven feedback for an entire class of student essays in a single workspace. It combines Writing Observer's learning data with configurable prompts so you can rapidly review submissions, capture high-level trends, and craft targeted responses for each student. + +> **Who is this for?** Educators who need fast, consistent formative feedback across a large set of essays or narrative responses. + +## What you can do with this dashboard + +* **Queue AI feedback for the whole class.** Select a document source and instantly request AI-generated feedback for every student submission at once. +* **Customize prompts with placeholders.** Build prompts that reference student-specific context (e.g., `{student_text}` or custom placeholders you upload) so the AI response stays grounded in your classroom language. +* **Fine-tune the AI's voice.** Provide a system prompt that frames the tone, rubric, or learning goals you want the AI to follow. +* **Track prompt history.** Quickly re-run or iterate on past prompts without rebuilding them from scratch. +* **Monitor progress in real time.** A loading panel shows how many students have been processed so you know when the batch is complete. +* **Dive into individual students.** Expand any student tile to review their essay, the applied prompt, and the returned feedback side-by-side. +* **Adjust the layout to match your workflow.** Change tile height, students per row, and visibility of profile headers for small-group reviews or projector-friendly displays. + +## Getting started + +1. **Open the dashboard.** From the main dashboard, choose **Classroom AI Feedback Assistant** in your course navigation. The URL ends with `/wo_bulk_essay_analysis/dash/bulk-essay-analysis`. +2. **Connect to your class.** The dashboard automatically reads the course and assignment from the page URL. Use the profile sidebar to confirm you are logged in and connected. +3. **Pick a document source.** In **Settings → Document Source**, choose where essays should come from (e.g., most recent document, document accessed at specific time, etc). Adjust any source-specific options if prompted. +4. **Draft your prompts.** + * **System prompt:** Sets expectations for the AI (tone, rubric, grading stance). + * **Query prompt:** Explain what you want the AI to produce. Use placeholders such as `{student_text}` to insert student work. Add your own placeholders via the **Add** button - paste text or upload `.txt`, `.md`, `.pdf`, or `.docx` files to reference rubrics or exemplars. +5. **Review placeholder tags.** Click a placeholder pill to insert it into your query. The tag manager prevents duplicate labels and shows warnings if required content is missing. +6. **Submit the batch.** Click **Submit**. The dashboard disables the button while processing and displays a progress bar with status updates. + +## Reading the results + +![Student tile and feedback panel](_images/bulk-essay-analysis-student-tile.png) + +Each student tile shows: + +* **Profile header** (optional) with avatar, name. +* **Process tags** summarizing analytics such as time on task or current activity status. +* **Student text panel** rendered with Writing Observer's rich text component. +* **Feedback card** that fills in once the AI response returns. Loading spinners indicate students still in progress. Errors surface in a dismissible alert with debug details (visible in development mode). + +Use the expand icon on any tile to open the **Individual Student** drawer for focused review, longer scrolling feedback, or to copy responses into LMS comments. + +## Managing prompts and history + +The **Prompt History** panel (right side) stores every submitted prompt for this browser session. Selecting an entry previews the exact text that was sent. + +## Advanced configuration + +Open the **Advanced** panel to: + +* **Change layout density.** Set students-per-row and tile height for flexible layouts (e.g., 1-up for conferencing, 3-up for scanning). +* **Hide/show student profiles.** Toggle headers off when projecting or sharing anonymized work samples. +* **Switch document sources on the fly.** Quickly pivot between document sources. +* **Select information overlays.** Enable additional metrics from the Classroom Text Highlighter module (e.g., time on task) to contextualize feedback. + +## Tips for effective use + +* Start with the provided sample prompts and iterate. Short, specific requests (3-5 bullet points) generate the most actionable feedback. +* Use the tag manager to maintain a consistent rubric voice. Uploading a rubric once lets you reuse it across prompts without copy/paste. +* Watch the progress bar before closing the tab—students remaining in queue continue to update, and the bar helps you gauge completion. +* If no text is available for a student, the tile will note that explicitly so you can follow up with the student. + +## Troubleshooting + +* **Nothing happens when I click Submit.** Ensure the course URL includes `course_id` and `assignment_id`, and verify at least one placeholder (`{student_text}`) is present in your prompt. +* **The alert banner appears.** Hover to read the message. In development environments, open the error JSON to share with your technical support team. +* **PDF/DOCX uploads fail.** Confirm the file size is manageable and the content is mostly text (scanned images are not supported for extraction). + +Once configured, the Classroom AI Feedback Assistant becomes your hub for consistent, high-quality formative feedback at scale. diff --git a/modules/wo_bulk_essay_analysis/VERSION b/modules/wo_bulk_essay_analysis/VERSION index 4dd337e23..696424a49 100644 --- a/modules/wo_bulk_essay_analysis/VERSION +++ b/modules/wo_bulk_essay_analysis/VERSION @@ -1 +1 @@ -0.1.0+2025.04.17T11.52.09.536Z.37e99b72.berickson.202504.process.metrics +0.1.0+2025.09.30T15.53.18.556Z.1c72d9e1.master diff --git a/modules/wo_bulk_essay_analysis/_images/bulk-essay-analysis-overview.png b/modules/wo_bulk_essay_analysis/_images/bulk-essay-analysis-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..b7408566551d36db75cbab6ca7001995386d391a GIT binary patch literal 157818 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 d&84(mTsmef_~9U|*oA{|7a>rquud literal 0 HcmV?d00001 diff --git a/modules/wo_bulk_essay_analysis/_images/bulk-essay-analysis-student-tile.png b/modules/wo_bulk_essay_analysis/_images/bulk-essay-analysis-student-tile.png new file mode 100644 index 0000000000000000000000000000000000000000..13c6efca47e74882cb98c639f135174c7262450a GIT binary patch literal 125229 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 **Who is this for?** Teachers who want to explore student writing through highlights, time-on-task metrics, and reusable annotation presets. + +## What you can do with this dashboard + +* **Display student writing at a glance.** See every student's document in a responsive grid, with quick navigation between document sources. +* **Highlight key language features.** Turn on NLP indicators (parts of speech, sentence structures, tone, etc.) and instantly spot trends across the class. +* **Track writing behaviors.** Add process metrics such as time on task or status badges so you know who is still working versus finished. +* **Save and reuse presets.** Build highlight collections (e.g., "Argumentative Evidence" or "Narrative Voice") and recall them with one click. +* **Surface a legend for students.** Share the color key so learners understand what each highlight represents during conferences or gallery walks. +* **Zoom into individual students.** Expand any tile for a focused view, ideal for projecting on screen or printing annotated drafts. + +## Getting started + +1. **Open the dashboard.** From the primary dashboard, select **Classroom Text Highlighter**. The dashboard loads at `/wo_classroom_text_highlighter/dash`. +2. **Confirm the connection.** The WebSocket indicator in the toolbar should be green. If not, check your login status via the profile sidebar. +3. **Pick a document source.** In **Settings → Document Source**, choose where essays should come from (e.g., most recent document, document accessed at specific time, etc). Adjust any source-specific options if prompted. +4. **Select NLP options.** In the **Information Options** table, check the highlights and metrics you want to display. Group headers (e.g., *Text Information*, *Process Information*) expand to reveal individual features. +5. **Adjust the layout.** Use the view controls to set students per row, tile height, and whether student names appear. These settings make it easy to adapt the dashboard for stations, projector mode, or screen readers. + +## Working with highlights and presets + +![Highlight configuration panel](_images/classroom-text-highlighter-options.png) + +* **Legend button:** Shows the current highlight color key so you can share the meaning with students. +* **Presets panel:** Save combinations of options (e.g., "Sentence Structure") for future lessons. Name your preset, click **Add Preset**, and it stores the current configuration. Select a preset from the list to instantly apply it. +* **Deselect All preset:** Quickly clears every highlight and metric selection if you want to start fresh. +* **Custom colors:** Customize colors for each selected highlightable item. + +## Exploring student writing + +![Expanded student tile](_images/classroom-text-highlighter-student.png) + +* **Student tiles:** Each tile shows badges for selected metrics (time on task, status) followed by the highlighted text. Tiles resize automatically based on your layout settings. +* **Expand view:** Click the expand icon to open the **Individual Student** drawer. This view removes the grid so you can focus on one student, scroll without distractions, and discuss highlights during conferences. +* **Loading feedback:** A progress bar appears while new highlights are generated. The banner updates with counts so you know when all documents are ready. + +## Tips for classroom use + +* Begin mini-lessons by projecting the legend and a few anonymized tiles. Have students identify how the highlights connect to the day's learning target. +* Combine process metrics with highlights to spot students who spent little time on task but still produced strong structures—perfect for peer coaching pairs. +* Encourage student self-assessment by sharing individual tiles and asking learners to explain why certain phrases received highlights. + +## Troubleshooting + +* **No students appear.** Ensure the URL contains a `course_id` and that the selected document source has submissions. Try toggling the Options panel to refresh the selection. +* **Highlights don't change after I toggle options.** Wait for the loading banner to disappear; the dashboard batches NLP requests and updates tiles when processing finishes. +* **Colors are confusing.** Use the legend button to review the palette, or save a preset with fewer simultaneous highlights. +* **Error alert shows up.** Read the message for guidance. The dashboard records error details (visible to developers) that you can share with your support contact. + +With the Classroom Text Highlighter, you can transform raw student writing into an interactive, data-informed experience that keeps learners engaged and reflective. diff --git a/modules/wo_classroom_text_highlighter/VERSION b/modules/wo_classroom_text_highlighter/VERSION index daf8882e5..696424a49 100644 --- a/modules/wo_classroom_text_highlighter/VERSION +++ b/modules/wo_classroom_text_highlighter/VERSION @@ -1 +1 @@ -0.1.0+2025.04.16T16.38.16.396Z.ab096d59.berickson.202504.process.metrics +0.1.0+2025.09.30T15.53.18.556Z.1c72d9e1.master diff --git a/modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-options.png b/modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-options.png new file mode 100644 index 0000000000000000000000000000000000000000..0cce1f8cc3b5c7eb58cac61260ce2b89c7183e91 GIT binary patch literal 51037 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

5-|frn2p>cjEqvh3|^{)AFA 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 literal 0 HcmV?d00001 diff --git a/modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-overview.png b/modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..1a9380e3cca8171aee6cf22799c4456ec976ed5d GIT binary patch literal 153503 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 z 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 Xm1XQa&12)AGrm8H$%vK+>w5hU6|Z-g literal 0 HcmV?d00001 diff --git a/modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-student.png b/modules/wo_classroom_text_highlighter/_images/classroom-text-highlighter-student.png new file mode 100644 index 0000000000000000000000000000000000000000..b58d22cc9e2aea5e20058d43828f9dc871a0b523 GIT binary patch literal 72734 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 The module is designed so that any feature can be toggled on or off. This lets you reuse only the pieces that are available in your deployment environment. + +## Configuration (`creds.yaml`) + +Below is a representative configuration block. Any unspecified key falls back to the documented default value. ## Config (`creds.yaml`) ```yaml modules: - writing_observer: - use_nlp: false - use_google_documents: false - use_languagetool: false - languagetool_host: http://localhost - languagetool_port: 8081 - verbose: false - gpt_responders: - ollama: - model: llama2 - host: http://localhost:11434 - openai: - model: gpt-3.5-turbo-16k - api_key: your-secret-key + writing_observer: + use_nlp: false + use_google_documents: false + use_languagetool: false + languagetool_host: http://localhost + languagetool_port: 8081 + verbose: false + gpt_responders: + ollama: + model: llama2 + host: http://localhost:11434 + openai: + model: gpt-3.5-turbo-16k + api_key: your-secret-key ``` -- `use_nlp` (bool, default false): determines whether or not we should use the AWE libraries or not to compute NLP indicators. -- `use_google_documents` (bool, default false): determines if we should attempt to update the reconstruct reducer with the ground truth (Google docs API). -- `use_languagetool` (bool, default false): enable LanguageTool information to be processed. - - `languagetool_host` (str, default `localhost`): host that is running LanguageTool - - `languagetool_port` (int, default 8081): which port LanguageTool is running on -- `verbose` (bool, default false): print state whenever reducers update -- `gpt_responders` (obj, {}): how you wish to connect to GPTs. See dedicated section below for more details. +### Top-level flags + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `use_nlp` | bool | `false` | Enable AWE NLP indicators such as parts of speech, main idea detection, and academic language metrics. | +| `use_google_documents` | bool | `false` | Sync reconstructed reducer state with a Google Doc using the Google Docs API. | +| `use_languagetool` | bool | `false` | Run LanguageTool analysis on submitted text. | +| `verbose` | bool | `false` | Log reducer state whenever it updates (useful when debugging pipelines). | + +### LanguageTool options + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `languagetool_host` | str | `http://localhost` | Host URL for the LanguageTool server. | +| `languagetool_port` | int | `8081` | Port on which LanguageTool is available. | + +Set `use_languagetool` to `true` only when LanguageTool is reachable at the configured host and port. + +### GPT responders + +The `gpt_responders` object declares one or more providers. The system iterates over the responders in the order they appear and selects the first one that is correctly configured. This allows you to offer fallbacks (for example, try a local Ollama instance before hitting OpenAI). + +Currently supported responders: + +#### Ollama + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `model` | str | `llama2` | Model name served by the Ollama runtime. | +| `host` | str | `http://localhost:11434` | Base URL of the Ollama server. You can also supply this via the `OLLAMA_HOST` environment variable. | + +#### OpenAI + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `model` | str | `gpt-3.5-turbo-16k` | Chat completion model to call. | +| `api_key` | str | _(required)_ | Secret API key for your OpenAI account. You can also provide it through the `OPENAI_API_KEY` environment variable. | + +## Feature-by-feature guidance + +### NLP indicators (AWE) + +1. Set `use_nlp: true` in the configuration. +2. Ensure the AWE libraries are installed and accessible from the runtime environment. +3. Call the relevant reducers or service functions to compute indicators such as parts-of-speech counts or academic language percentages. + +These indicators are useful for automated writing evaluation and can be combined with LanguageTool or GPT feedback. + +### Google Docs synchronization + +Enable `use_google_documents` when you want the module to keep a Google Doc up to date with reconstructed reducer state. You must supply Google API credentials in the broader system configuration (outside the scope of this document). + +### LanguageTool error detection -## Available tools +1. Run or connect to a LanguageTool server. +2. Configure `languagetool_host` and `languagetool_port`. +3. Set `use_languagetool: true`. -There are 3 primary tools we have available to us. +The module will then enrich reducer output with spelling and usage error information, which can be displayed directly to writers or incorporated into other feedback flows. -1. NLP indicators to suppoprt automated writing evaulation. These indicators provide information about the text (parts of speech, main ideas, % of academic langauge, etc.). -2. LanguageTool to detect specific errors being made in text. These errors include spelling and incorrect word usage. -3. Ability to interface with LLMs. +### GPT-based feedback -## GPT Responders +1. Add one or more entries to `gpt_responders` (see tables above). +2. Provide any required credentials via configuration or environment variables. +3. Enable the module feature or reducer that consumes GPT responses (for instance, conversational feedback or revision suggestions). -We allow users to define different ways of interacting with GPTs. The system will iterate over each listed responder and return the first successfully configured one. The current supported responders are: +## Tips for integration -### Ollama +* Toggle features gradually during development to keep dependencies manageable. +* Use the `verbose` flag while integrating new reducers to observe state transitions and diagnose issues. +* Keep secrets (such as API keys) out of version control by relying on environment variables or secret management tooling. +* When deploying in containers, expose the LanguageTool and Ollama ports to the module runtime. -- `model` (str, default `llama2`): the model you wish to use. -- `host` (str, default `http://localhost:11434`): the host running Ollama. You may also set the `OLLAMA_HOST` environment variable. +## Further resources -### OpenAI +* [LanguageTool server documentation](https://dev.languagetool.org/http-server) +* [Ollama documentation](https://docs.ollama.ai/) +* [OpenAI API reference](https://platform.openai.com/docs/) -- `model` (str, default `gpt-3.5-turbo-16k`): the model you wish to use. -- `api_key` (str): your secret openai API key. You may also set this with the `OPENAI_API_KEY` environment variable. +These resources provide additional setup instructions and troubleshooting guides for the third-party services referenced above. diff --git a/modules/writing_observer/VERSION b/modules/writing_observer/VERSION index c98f3678a..696424a49 100644 --- a/modules/writing_observer/VERSION +++ b/modules/writing_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.08.07T19.58.28.937Z.ed90597d.berickson.202507.new.lti.updates +0.1.0+2025.09.30T15.53.18.556Z.1c72d9e1.master From 8b205d0c2750fa8bcaa2c0a4837b3f533b82f895 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Wed, 1 Oct 2025 13:50:57 -0400 Subject: [PATCH 053/327] updated system settings documentation --- VERSION | 2 +- autodocs/concepts.rst | 3 + autodocs/extension.rst | 6 - autodocs/reference.rst | 2 + docs/concepts/system_settings.md | 115 ++++++++ docs/how-to/config.md | 279 ------------------ docs/reference/system_settings.md | 152 ++++++++++ learning_observer/VERSION | 2 +- .../learning_observer/auth/auth.md | 2 +- 9 files changed, 275 insertions(+), 288 deletions(-) delete mode 100644 autodocs/extension.rst create mode 100644 docs/concepts/system_settings.md delete mode 100644 docs/how-to/config.md create mode 100644 docs/reference/system_settings.md diff --git a/VERSION b/VERSION index 696424a49..0aa6c860e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.09.30T15.53.18.556Z.1c72d9e1.master +0.1.0+2025.10.01T17.50.57.101Z.d6047986.master diff --git a/autodocs/concepts.rst b/autodocs/concepts.rst index 00aca9db6..58ec6c63c 100644 --- a/autodocs/concepts.rst +++ b/autodocs/concepts.rst @@ -13,6 +13,8 @@ implementation details: architecture that implements the system design. - :doc:`Technologies ` - surveys the primary tools and platforms we rely on to realize the architecture. +- :doc:`System Settings ` - describes how the + system loads global and cascading settings. - :doc:`Events ` - introduces the event model that drives data flowing through the system. - :doc:`Reducers ` - details how incoming events are @@ -35,6 +37,7 @@ implementation details: docs/concepts/system_design docs/concepts/architecture docs/concepts/technologies + docs/concepts/system_settings docs/concepts/events docs/concepts/reducers docs/concepts/communication_protocol diff --git a/autodocs/extension.rst b/autodocs/extension.rst deleted file mode 100644 index 8bc9e1ca3..000000000 --- a/autodocs/extension.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. _extension: - -Extension ---------- -.. include:: ../docs/extension.md - :parser: myst_parser.sphinx_ diff --git a/autodocs/reference.rst b/autodocs/reference.rst index dbc769734..ba358f17b 100644 --- a/autodocs/reference.rst +++ b/autodocs/reference.rst @@ -4,6 +4,7 @@ Reference Detailed, structured information about APIs, configurations, and technical details. Consult these resources when you need definitive answers about how the system behaves or how to integrate with it: - :doc:`Code Quality Standards ` - Understand our expectations for readability, style, and continuous improvement. +- :doc:`System Settings ` - Review what each system setting does and where it is used. - :doc:`Documentation Conventions ` - Learn how we structure docs, what tools we use, and how to contribute updates. - :doc:`Linting Rules ` - Review the automated checks that keep the codebase healthy and how to run them locally. - :doc:`Testing Strategy ` - Explore the testing layers we rely on and guidelines for writing reliable tests. @@ -17,6 +18,7 @@ Detailed, structured information about APIs, configurations, and technical detai :titlesonly: docs/reference/code_quality.md + docs/reference/system_settings.md docs/reference/documentation.md docs/reference/linting.md docs/reference/testing.md diff --git a/docs/concepts/system_settings.md b/docs/concepts/system_settings.md new file mode 100644 index 000000000..fc7d0ae93 --- /dev/null +++ b/docs/concepts/system_settings.md @@ -0,0 +1,115 @@ +# System settings + +Learning Observer depends on a single source of truth for everything from +server ports to which pieces of modules are enabled. We rely on the +[PMSS](https://github.com/ETS-Next-Gen/pmss) registry because it gives us a +predictable, type-checked way to describe those concerns once and reuse them +across the whole stack. This article explains why the settings layer exists, +how `creds.yaml` fits into the picture, and why we support cascading +``*.pmss`` files that behave a bit like CSS for configuration. + +To view all settings and what they do, checkout the [System Settings Reference](../reference/system_settings.md). + +## Why centralize configuration? + +* **Shared vocabulary.** Modules, reducers, and integrations all speak the same + language when they ask for `hostname`, `redis_connection.port`, or + `modules.writing_observer.use_nlp`. PMSS enforces the field definitions so we + can freely move code between services without wondering what the knobs are + called. +* **Type safety and validation.** Every field is registered with a type and + optional parser. PMSS refuses to start if a value is missing or malformed, + surfacing errors during boot instead of in the middle of a request. +* **Operational portability.** Teams deploy Learning Observer to wildly + different environments. A single registry allows a site to describe network + boundaries, third-party credentials, or feature flags in one place and keep + those choices under version control. + +## The role of `creds.yaml` + +Most installations load configuration from `creds.yaml`. When the process +starts, `learning_observer.settings` initializes PMSS with a +`YAMLFileRuleset`, parses that file, and registers the run mode and other core +fields. The YAML mirrors the namespace hierarchy, so options live exactly where +operators expect to see them: + +```yaml +server: + port: 5000 +modules: + writing_observer: + use_nlp: true +``` + +`creds.yaml` gives us a stable default: it travels with the deployment, can be +checked into private infrastructure repositories, and is easy to audit during +reviews. Even when we introduce additional sources, the YAML baseline remains +the anchor that documents the "intent" of the environment. + +## Cascading ``*.pmss`` overlays + +While one file covers global defaults, we often need tweaks that depend on +**who** is asking for data or **where** a request originates. PMSS supports +multiple rule sets, so we extend the base YAML with optional ``*.pmss`` +overlays. Each overlay is a small PMSS file whose contents look just like the +YAML fragment they augment, but they add selectors that encode *specificity*. + +Think of these selectors like CSS. We start with the low-specificity default +rule and then layer on increasingly precise matches: + +```pmss +roster_data { + source: all; +} + +roster_data[domain="learning-observer.org"] { + source: google; +} +``` + +When `learning_observer/learning_observer/rosters.py` asks for `roster_data` +it supplies attributes such as the caller's email domain or provider. PMSS +walks the rule set, finds the most specific block that matches the request, and +returns that value. In the example above a teacher from +`learning-observer.org` would receive the `google` roster source, while any +other user would keep the global `all` default. Additional selectors can layer +on top for providers, schools, or classrooms with each more specific rule +overriding the broader ones. + +At runtime we still assemble a deterministic cascade: + +1. Load the global `creds.yaml` defaults. +2. Apply any environment overlays (for example, a `district.pmss` file that + swaps OAuth credentials for that customer). +3. Resolve request-scoped overlays that match the supplied selectors, letting + the most specific rule win. + +PMSS tracks the provenance of each value so developers can inspect which file +supplied the final answer when troubleshooting. Because overlays reuse the +same registered fields, we retain all of the type checking that protects the +base configuration. + +## How code consumes the cascade + +Once the cascade is assembled, code does not care whether a value came from the +YAML baseline or an overlay. Components call +`learning_observer.settings.pmss_settings.()` (optionally via +`module_setting()` helpers) and PMSS resolves the field using the active rule +stack. That means a request handled for an instructor can pick up +instructor-specific defaults while a system job, using the same accessor, still +observes the site-wide configuration. + +## Extending the system settings surface + +Adding a new capability follows a consistent pattern: + +1. Register the field with PMSS, giving it a name, type, description, and + default if appropriate. +2. Update `creds.yaml` (or the reference documentation) to teach operators what + the new setting does. +3. Optionally create overlay files where the value should vary by tenant, user, + or integration partner. + +By keeping configuration declarative and cascading, we get the flexibility to +serve many partners without branching the codebase, all while preserving the +predictability administrators expect from a single system settings registry. diff --git a/docs/how-to/config.md b/docs/how-to/config.md deleted file mode 100644 index 84f9ea673..000000000 --- a/docs/how-to/config.md +++ /dev/null @@ -1,279 +0,0 @@ -# Config (creds.yaml) - -The Learning Observer project can be configured on a per-system basis using a configuration file. This configuration file is essential for setting various options such as the environment mode (development or production), authentication, and module-specific settings. - -## Settings - -The settings are loaded in via the `learning_observer/learning_observer/settings.py` file. You see them referred to in the code with - -```python -import learning_observer.settings -item = learning_observer.settings.settings['kvs'] -``` - -### Hostname and Protocol - -The `hostname` and `protocol` sections define the address and protocol used for accessing the Learning Observer application. - -- `hostname`: The address of the application server. -- `protocol`: The protocol used for communication (http or https). - -Example: - -```yaml -hostname: localhost:8888 -protocol: http -``` - -### XMPP - -The `xmpp` section defines the credentials and configurations for XMPP connections, including sinks, sources, and stream components. - -- `sink`: Configuration for XMPP sinks that receive messages. - - `jid`: The Jabber ID for the sink. - - `password`: The password for the sink. -- `source`: Configuration for XMPP sources that send messages. - - `jid`: The Jabber ID for the source. - - `password`: The password for the source. -- `stream`: Configuration for XMPP streams used for debugging. - - `jid`: The Jabber ID for the stream. - - `password`: The password for the stream. - -Example: - -```yaml -xmpp: - sink: - jid: sink@localhost - password: {xmpp-sink-password} - source: - jid: source@localhost - password: {xmpp-source-password} - stream: - jid: stream@localhost - password: {xmpp-stream-password} -``` - -### Authentication - -The `auth` section is responsible for configuring various authentication methods. - -- `google_oauth`: Configuration for Google OAuth authentication. - - `web`: A sub-configuration containing Google OAuth settings. - - `client_id`: The Google OAuth client ID. - - `project_id`: The Google OAuth project ID. - - `auth_uri`: The Google OAuth authorization URI. - - `token_uri`: The Google OAuth token URI. - - `auth_provider_x509_cert_url`: The Google OAuth provider x509 certificate URL. - - `client_secret`: The Google OAuth client secret. - - `javascript_origins`: The list of allowed JavaScript origins. -- `password_file`: The path to the password file used for authentication, created using the `lo_passwd.py` script. -- `http_basic_auth`: Configuration for HTTP basic authentication. - - `mode`: The mode of HTTP basic authentication, either 'nginx' or 'password-file'. - - `password_file`: The path to the password file used for authentication, or 'null' if authentication is done by nginx. - -Example: - -```yaml -auth: - google_oauth: - web: - client_id: {google-oauth-client-id} - project_id: {google-oauth-project-id} - auth_uri: https://accounts.google.com/o/oauth2/auth - token_uri: https://oauth2.googleapis.com/token - auth_provider_x509_cert_url: https://www.googleapis.com/oauth2/v1/certs - client_secret: {google-client-secret} - javascript_origins: ["{url}"] - password_file: passwd.lo - http_basic_auth: - mode: remove-this - password_file: passwd.lo -``` - -### PubSub - -The `pubsub` section configures the pubsub system type used for the application. - -- `type`: The type of pubsub system, either 'stub' for in-memory debugging or 'redis' for small-scale production. - -Example: - -```yaml -pubsub: - type: stub -``` - -### Redis Connection - -This determines how we should be connecting to Redis. If these are not -set, the connection will default to using `localhost:6389` without a -password. - -```yaml -redis_connection: - redis_host: localhost - redis_port: 6389 - redis_password: yoursupersecurepassword -``` - -### KVS - -The `kvs` section configures the key-value store used in the application. - -- `default`: The default configuration for the key-value store. - - `type`: The type of key-value store, such as 'stub', 'redis', or 'redis_ephemeral'. - - `expiry`: The expiry time for objects in the key-value store (in seconds). - -Example: - -```yaml -kvs: - default: - type: stub - expiry: 6000 -``` - -### Roster Data - -The `roster_data` section configures the source of roster data. - -- `source`: The source of roster data, such as 'filesystem', 'google_api', 'all', or 'test'. - -Example: - -```yaml -roster_data: - source: filesystem -``` - -### AIO - -The `aio` section configures user session settings. - -- `session_secret`: The unique secret key for your deployment. -- `session_max_age`: The maximum age of a session, in seconds. - -Example: - -```yaml -aio: - session_secret: {unique-aio-session-key} - session_max_age: 3600 -``` - -### Config - -The `config` section configures the run mode and debug settings. - -- `run_mode`: The run mode, either 'dev' or 'deploy'. -- `debug`: A list of debug options, such as "tracemalloc". - -Example: - -```yaml -config: - run_mode: dev - debug: [] -``` - -### Logging - -The `logging` section configures the logging settings. - -- `debug_log_level`: The log level, either 'NONE', 'SIMPLE', or 'EXTENDED'. -- `debug_log_destinations`: A list of log destinations, such as 'CONSOLE' and 'FILE'. - -Example: - -```yaml -logging: - debug_log_level: SIMPLE - debug_log_destinations: - - CONSOLE - - FILE -``` - -### Theme - -The `theme` section configures the appearance and messages of the application. - -- `server_name`: The name of the server. -- `front_page_pitch`: The message displayed on the front page. -- `logo_big`: The URL of the logo. - -Example: - -```yaml -theme: - server_name: Learning Observer - front_page_pitch: Learning Observer is an experimental dashboard. If you'd like to be part of the experiment, please contact us. If you're already part of the experiment, log in! - logo_big: /static/media/logo-clean.jpg -``` - -### Event Auth - -The `event_auth` section configures authentication settings for events. - -- `local_storage`: Configuration for local storage authentication. - - `userfile`: The file containing user information. - - `allow_guest`: A boolean indicating whether guest access is allowed. -- `chromebook`: (optional) Configuration for Chromebook authentication. - - `allow_guest`: A boolean indicating whether guest access is allowed on Chromebooks. - -Example: - -```yaml -event_auth: - local_storage: - userfile: students.yaml - allow_guest: true -``` - -### Feature Flags - -The `feature_flags` section allows you to enable or disable specific features in development. - A dictionary with the feature names as keys and boolean values to indicate whether the feature is enabled or disabled. - -Example: - -```yaml -feature_flags: {} -``` - -### Server - -The `server` section configures the server settings. - -- `port`: The port number on which the server will listen. - -Example: - -```yaml -server: - port: 8888 -``` - -### Modules - -The `modules` section configures the settings for each module installed on the system. Different systems may define different items depending on which modules they wish to have installed on their system. An error will be raised if an expected setting is missing from a given module. Here is an example for the `writing_observer` module. - -- `writing_observer`: Settings specific to the Writing Observer module. - - `use_nlp`: A boolean indicating whether to use natural language processing or a stub function. (default: `false`) - - `use_google_documents`: A boolean indicating whether to use Google Documents. (default: `false`) - - `languagetool_port`: The port the LanguageTool server is running on (default: `8081`) - - `languagetool_host`: The host the LanguageTool server is running on (default: `localhost`) - - `use_languagetool`: A boolean indicating whether to use LanguageTool or a stub function. (default: `false`) - -Example: - -```yaml -modules: - writing_observer: - use_nlp: true - use_google_documents: false - languagetool_port: 8081 - use_languagetool: true -``` - -Note: This is just an example of how to configure the settings for a specific module. Each module may have its own unique settings, and you should consult the module's documentation for information on which settings are required and how they should be configured. diff --git a/docs/reference/system_settings.md b/docs/reference/system_settings.md new file mode 100644 index 000000000..ce097d30e --- /dev/null +++ b/docs/reference/system_settings.md @@ -0,0 +1,152 @@ +# System Settings + +This page lists every field registered with PMSS for the **Learning Observer +base application**, grouped by the namespace you use in `creds.yaml`. Each +entry includes the YAML path, purpose, default (if any), and the code that +relies on it. Module-specific settings (such as the Writing Observer module) +should be documented alongside their module guides in the reference section. + +Refer back to the [system settings concept](../concepts/system_settings.md) +concept guide for details on how these values are loaded and consumed by the +runtime. + +## Global application keys + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `run_mode` | Selects `dev`, `deploy`, or `interactive` runtime profiles to control logging and startup behaviour. | required | [`learning_observer/learning_observer/settings.py`](../../learning_observer/learning_observer/settings.py), [`learning_observer/learning_observer/main.py`](../../learning_observer/learning_observer/main.py) | +| `hostname` | Public host name for OAuth callbacks and secure cookie scopes. Include the port when not using 80/443. | required | [`learning_observer/learning_observer/auth/social_sso.py`](../../learning_observer/learning_observer/auth/social_sso.py), [`learning_observer/learning_observer/webapp_helpers.py`](../../learning_observer/learning_observer/webapp_helpers.py) | +| `protocol` | Protocol (`http` or `https`) that governs cookie security and OAuth redirect URLs. | required | [`learning_observer/learning_observer/auth/social_sso.py`](../../learning_observer/learning_observer/auth/social_sso.py), [`learning_observer/learning_observer/webapp_helpers.py`](../../learning_observer/learning_observer/webapp_helpers.py) | +| `clone_module_git_repos` | Controls whether module git repositories are cloned automatically (`y`), skipped (`n`), or prompted (`prompt`). | `prompt` | [`learning_observer/learning_observer/module_loader.py`](../../learning_observer/learning_observer/module_loader.py) | +| `dangerously_allow_insecure_dags` | Enables uploading arbitrary dashboard DAG definitions for development experiments. Leave disabled in production. | `false` | [`learning_observer/learning_observer/dashboard.py`](../../learning_observer/learning_observer/dashboard.py) | +| `fetch_additional_info_from_teacher_on_login` | Starts a background job after Google login to fetch extra teacher documents immediately. | `false` | [`learning_observer/learning_observer/auth/social_sso.py`](../../learning_observer/learning_observer/auth/social_sso.py) | + +### `config` namespace + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `config.run_mode` | Mirror of the root `run_mode` so runtime helpers can resolve the value within the `config` namespace. | required | [`learning_observer/learning_observer/main.py`](../../learning_observer/learning_observer/main.py) | +| `config.debug` | List of diagnostic toggles (for example `"tracemalloc"`) that enable extra debugging helpers during development. | `[]` | [`learning_observer/learning_observer/routes.py`](../../learning_observer/learning_observer/routes.py) | + +### `server` namespace + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `server.port` | Port that the aiohttp web server binds to. Falling back to an open port in development remains TODO. | `8888` | [`learning_observer/learning_observer/main.py`](../../learning_observer/learning_observer/main.py) | + +### Session management (`aio` namespace) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `aio.session_secret` | Secret used to encrypt and sign aiohttp session cookies. Generate a unique value per deployment. | required | [`learning_observer/learning_observer/webapp_helpers.py`](../../learning_observer/learning_observer/webapp_helpers.py) | +| `aio.session_max_age` | Session lifetime in seconds. | required | [`learning_observer/learning_observer/webapp_helpers.py`](../../learning_observer/learning_observer/webapp_helpers.py) | + +### Redis connection (`redis_connection` namespace) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `redis_connection.redis_host` | Hostname for Redis. | `localhost` | [`learning_observer/learning_observer/redis_connection.py`](../../learning_observer/learning_observer/redis_connection.py) | +| `redis_connection.redis_port` | Port for Redis. | `6379` | [`learning_observer/learning_observer/redis_connection.py`](../../learning_observer/learning_observer/redis_connection.py) | +| `redis_connection.redis_password` | Password for Redis (set to `null` when unused). | `null` | [`learning_observer/learning_observer/redis_connection.py`](../../learning_observer/learning_observer/redis_connection.py) | + +### Logging (`logging` namespace) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `logging.debug_log_level` | Chooses how verbose diagnostic logging should be (`NONE`, `SIMPLE`, or `EXTENDED`). | inherits environment default | [`learning_observer/learning_observer/log_event.py`](../../learning_observer/learning_observer/log_event.py) | +| `logging.debug_log_destinations` | Ordered list of destinations that should receive debug logs (`CONSOLE`, `FILE`). | `['CONSOLE', 'FILE']` in development | [`learning_observer/learning_observer/log_event.py`](../../learning_observer/learning_observer/log_event.py) | + +### Key-value stores (`kvs` namespace) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `kvs.default.type` | Backend used for the default key-value store (`stub`, `redis`, `redis_ephemeral`, or `filesystem`). | required | [`learning_observer/learning_observer/kvs.py`](../../learning_observer/learning_observer/kvs.py) | +| `kvs.default.expiry` | Expiration (seconds) required when `type` is `redis_ephemeral`. | required for `redis_ephemeral` | [`learning_observer/learning_observer/kvs.py`](../../learning_observer/learning_observer/kvs.py) | +| `kvs.default.path` | Filesystem directory for persisted values when `type` is `filesystem`; supports optional `subdirs`. | required for `filesystem` | [`learning_observer/learning_observer/kvs.py`](../../learning_observer/learning_observer/kvs.py) | +| `kvs..type` | Additional named KVS pools that modules can request by name. Same accepted values as `kvs.default.type`. | optional | [`learning_observer/learning_observer/kvs.py`](../../learning_observer/learning_observer/kvs.py) | +| `kvs..expiry` | Per-store expiration when the named pool uses the `redis_ephemeral` backend. | required for `redis_ephemeral` pools | [`learning_observer/learning_observer/kvs.py`](../../learning_observer/learning_observer/kvs.py) | +| `kvs..path` | Filesystem location (and optional `subdirs`) for the named store when using the `filesystem` backend. | required for `filesystem` pools | [`learning_observer/learning_observer/kvs.py`](../../learning_observer/learning_observer/kvs.py) | + +### Roster ingestion (`roster_data` namespace) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `roster_data.source` | Selects the roster provider: `filesystem`, `google`, `schoology`, `x-canvas`, `all`, or `test`. | required | [`learning_observer/learning_observer/rosters.py`](../../learning_observer/learning_observer/rosters.py) | + +### Core authentication flags (`auth`) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `auth.password_file` | Enables password authentication using the specified credentials file (generated with `lo_passwd.py`). | disabled | [`learning_observer/learning_observer/routes.py`](../../learning_observer/learning_observer/routes.py) | +| `auth.test_case_insecure` | When `true` or configured with overrides, short-circuits authentication for automated tests. | `false` | [`learning_observer/learning_observer/auth/handlers.py`](../../learning_observer/learning_observer/auth/handlers.py) | +| `auth.demo_insecure` | Demo mode that fabricates user sessions for walkthroughs; may be a boolean or a mapping with a fixed `name`. | `false` | [`learning_observer/learning_observer/auth/handlers.py`](../../learning_observer/learning_observer/auth/handlers.py) | + +#### Google OAuth (`auth.google_oauth.web`) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `auth.google_oauth.web.client_id` | Google OAuth client ID. | required | [`learning_observer/learning_observer/auth/social_sso.py`](../../learning_observer/learning_observer/auth/social_sso.py) | +| `auth.google_oauth.web.client_secret` | Google OAuth client secret. | required | [`learning_observer/learning_observer/auth/social_sso.py`](../../learning_observer/learning_observer/auth/social_sso.py) | + +#### LTI providers (`auth.lti.`) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `auth.lti..auth_uri` | LMS endpoint that initiates the OIDC login flow. | required | [`learning_observer/learning_observer/auth/lti_sso.py`](../../learning_observer/learning_observer/auth/lti_sso.py) | +| `auth.lti..jwks_uri` | JWKS endpoint used to validate LMS ID tokens. | required | [`learning_observer/learning_observer/auth/lti_sso.py`](../../learning_observer/learning_observer/auth/lti_sso.py) | +| `auth.lti..token_uri` | OAuth token endpoint for the LMS. | required | [`learning_observer/learning_observer/auth/lti_sso.py`](../../learning_observer/learning_observer/auth/lti_sso.py) | +| `auth.lti..redirect_uri` | Callback URL inside Learning Observer. | required | [`learning_observer/learning_observer/auth/lti_sso.py`](../../learning_observer/learning_observer/auth/lti_sso.py) | +| `auth.lti..private_key_path` | Location of the private key used to sign LTI messages. | required | [`learning_observer/learning_observer/auth/lti_sso.py`](../../learning_observer/learning_observer/auth/lti_sso.py) | +| `auth.lti..api_domain` | Base Canvas API domain for roster and assignment cleaners (Canvas-specific). | required | [`learning_observer/learning_observer/integrations/canvas.py`](../../learning_observer/learning_observer/integrations/canvas.py) | + +#### HTTP Basic authentication (`auth.http_basic`) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `auth.http_basic.password_file` | Credential store used when Learning Observer verifies HTTP basic logins directly. Set to `null` when nginx handles auth. | required when present | [`learning_observer/learning_observer/routes.py`](../../learning_observer/learning_observer/routes.py), [`learning_observer/learning_observer/auth/http_basic.py`](../../learning_observer/learning_observer/auth/http_basic.py) | +| `auth.http_basic.login_page_enabled` | Enables the built-in login endpoint that proxies browser-provided credentials into a session. | `false` | [`learning_observer/learning_observer/auth/http_basic.py`](../../learning_observer/learning_observer/auth/http_basic.py) | +| `auth.http_basic.full_site_auth` | Marks that nginx protects every route so middleware should expect auth headers on each request. | `false` | [`learning_observer/learning_observer/auth/http_basic.py`](../../learning_observer/learning_observer/auth/http_basic.py) | +| `auth.http_basic.delegate_nginx_auth` | Indicates that nginx performs the credential check; Learning Observer only trusts forwarded headers. | `false` | [`learning_observer/learning_observer/auth/http_basic.py`](../../learning_observer/learning_observer/auth/http_basic.py) | + +### Background services and feature flags + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `feature_flags.*` | Optional feature toggles (`uvloop`, `watchdog`, `canvas_routes`, etc.). `True` enables a flag and allows nested configuration. | varies | [`learning_observer/learning_observer/settings.py`](../../learning_observer/learning_observer/settings.py) | + +### Event stream authentication (`event_auth` namespace) + +| YAML path | Description | Default | Used in | +| --- | --- | --- | --- | +| `event_auth.local_storage.userfile` | Path (under the data directory) listing device tokens that should be treated as authenticated. | required for `local_storage` | [`learning_observer/learning_observer/auth/events.py`](../../learning_observer/learning_observer/auth/events.py) | +| `event_auth.local_storage.allow_guest` | Permits unauthenticated fallbacks when the Chromebook or extension token is unknown. | `false` | [`learning_observer/learning_observer/auth/events.py`](../../learning_observer/learning_observer/auth/events.py) | +| `event_auth.http_basic` | Presence enables nginx-backed HTTP basic auth for event streams. No additional keys are required. | disabled | [`learning_observer/learning_observer/auth/events.py`](../../learning_observer/learning_observer/auth/events.py) | +| `event_auth.guest` | Enables guest sessions that mint random IDs for browsers without credentials. | disabled | [`learning_observer/learning_observer/auth/events.py`](../../learning_observer/learning_observer/auth/events.py) | +| `event_auth.hash_identify` | Enables hash-based identity hints (e.g., `/page#user=alice`) for one-off experiments. | disabled | [`learning_observer/learning_observer/auth/events.py`](../../learning_observer/learning_observer/auth/events.py) | +| `event_auth.testcase_auth` | Allows automated tests to tag events with deterministic user IDs. | disabled | [`learning_observer/learning_observer/auth/events.py`](../../learning_observer/learning_observer/auth/events.py) | + +## Modules + +Modules can define their own PMSS namespaces under `modules.`. +Consult each module's reference guide for those settings - for example, the +Writing Observer module documents its configuration alongside the rest of its +module documentation. + +## Example snippet + +```yaml +run_mode: dev +hostname: localhost:8888 +protocol: http +config: + run_mode: dev +server: + port: 8888 +aio: + session_secret: "replace-me" + session_max_age: 3600 +redis_connection: + redis_host: localhost + redis_port: 6379 + redis_password: null +``` diff --git a/learning_observer/VERSION b/learning_observer/VERSION index 696424a49..0aa6c860e 100644 --- a/learning_observer/VERSION +++ b/learning_observer/VERSION @@ -1 +1 @@ -0.1.0+2025.09.30T15.53.18.556Z.1c72d9e1.master +0.1.0+2025.10.01T17.50.57.101Z.d6047986.master diff --git a/learning_observer/learning_observer/auth/auth.md b/learning_observer/learning_observer/auth/auth.md index f38fd6889..c62b4818a 120000 --- a/learning_observer/learning_observer/auth/auth.md +++ b/learning_observer/learning_observer/auth/auth.md @@ -1 +1 @@ -../../../docs/auth.md \ No newline at end of file +../../../docs/concepts/auth.md \ No newline at end of file From f12616b4c95ee5224360da9ace49d99f0483a089 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Wed, 1 Oct 2025 17:16:15 -0400 Subject: [PATCH 054/327] added documentation for serving as lti --- VERSION | 2 +- autodocs/concepts.rst | 3 + autodocs/how-to.rst | 2 + docs/concepts/student_identity_mapping.md | 36 ++++++++++ docs/how-to/lti.md | 87 +++++++++++++++++++++++ 5 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 docs/concepts/student_identity_mapping.md create mode 100644 docs/how-to/lti.md diff --git a/VERSION b/VERSION index 0aa6c860e..39acef61a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+2025.10.01T17.50.57.101Z.d6047986.master +0.1.0+2025.10.01T21.16.15.146Z.8b205d0c.master diff --git a/autodocs/concepts.rst b/autodocs/concepts.rst index 58ec6c63c..8c0002830 100644 --- a/autodocs/concepts.rst +++ b/autodocs/concepts.rst @@ -21,6 +21,8 @@ implementation details: aggregated into the state our experiences depend on. - :doc:`Communication Protocol ` - discusses how the system queries data from reducers for dashboards. +- :doc:`Student Identity Mapping ` - explain + how learners information is mapped across integrations. - :doc:`Scaling ` - covers strategies for growing the system once the fundamentals are in place. - :doc:`Auth ` - describes authentication considerations @@ -41,6 +43,7 @@ implementation details: docs/concepts/events docs/concepts/reducers docs/concepts/communication_protocol + docs/concepts/student_identity_mapping docs/concepts/scaling docs/concepts/auth docs/concepts/privacy diff --git a/autodocs/how-to.rst b/autodocs/how-to.rst index deec45815..7bf21ad7d 100644 --- a/autodocs/how-to.rst +++ b/autodocs/how-to.rst @@ -6,6 +6,7 @@ Practical instructions for achieving specific goals within Learning Observer. Us - :doc:`Communication Protocol ` - How to query data from reducers or system endpoints for dashboards. - :doc:`Configure Learning Observer ` - Set up credentials, environment variables, and other configuration details required for a smooth deployment. - :doc:`Build Dashboards ` - Walk through creating dashboards from reducer outputs, including layout choices and data wiring. +- :doc:`LTI ` - Cover how to install Learning Observer as an LTI application. - :doc:`Run with Docker ` - Learn how to containerize the stack, manage images, and operate the project using Docker Compose. - :doc:`Writing Observer Extension ` - Install, configure, and validate the Writing Observer browser extension for capturing events. - :doc:`Interactive Environments ` - Connect Learning Observer to Jupyter and other live coding setups for iterative development. @@ -18,6 +19,7 @@ Practical instructions for achieving specific goals within Learning Observer. Us docs/how-to/communication_protocol.md docs/how-to/config.md docs/how-to/dashboards.md + docs/how-to/lti.md docs/how-to/docker.md docs/how-to/extension.md docs/how-to/interactive_environments.md diff --git a/docs/concepts/student_identity_mapping.md b/docs/concepts/student_identity_mapping.md new file mode 100644 index 000000000..e902c6a2d --- /dev/null +++ b/docs/concepts/student_identity_mapping.md @@ -0,0 +1,36 @@ +# Student Identity Mapping + +This document describes the current approach for reconciling a student's identity across the Google Workspace context used by Writing Observer and external platforms that only surface an email address (for example when the application is launched as an LTI tool). + +## Why the mapping exists + +When Writing Observer runs inside Google Workspace we naturally have access to the Google user identifier that shows up in event payloads. However, when the product is embedded as an LTI application we receive the learner's email address but do not receive the Google identifier. Many downstream reducers and dashboards expect to look students up by the Google identifier that is emitted by Google Docs events. Without an explicit bridge between those two identifiers we would be unable to join activity data with roster or profile information for LTI launches. + +## Data sources involved + +Two pieces of infrastructure cooperate to keep an email-to-Google-ID lookup table available: + +1. **`student_profile` reducer** – The `student_profile` KVS pipeline in `writing_analysis.py` stores the latest email address and Google identifier (`safe_user_id`) observed for each student. The reducer only updates its state when either value changes. The resulting records live in the reducer's internal key-value namespace and therefore need to be copied to a place where other services can access them. 【F:modules/writing_observer/writing_observer/writing_analysis.py†L233-L253】 +2. **`map_emails_to_ids_in_kvs.py` script** – This maintenance script scans the reducer's internal keys, extracts any records that contain both `email` and `google_id`, and writes a dedicated `email-studentID-mapping:{email}` entry to the key-value store. The explicit mapping gives any service that only knows the email address a way to recover the Google identifier. 【F:scripts/map_emails_to_ids_in_kvs.py†L1-L29】 + +This flow is intentionally simple: the reducer captures whatever the client reports, and the script copies the data to keys that other components already know how to query. + +## Operating the script + +The email mapping script is normally run in the same environment as other KVS maintenance tasks. It requires access to the same credentials file that reducers use. A manual run looks like this: + +```bash +python scripts/map_emails_to_ids_in_kvs.py +``` + +The script performs a full scan every time it runs, so it is safe to execute multiple times or to schedule as a recurring job. + +## Limitations and future direction + +The current reducer-plus-script approach fills an immediate gap but remains a stopgap solution: + +* **Tight coupling to Google identity** – The reducer only records the Google identifier surfaced by Google Docs. If we ingest events from another platform, there is no canonical place to persist its identifiers. +* **No user object abstraction** – Each consumer must know which KVS keys to query. A shared user object (or identity service) would allow the system to attach multiple external identifiers, roles, and profile attributes to a learner and to expose them through a stable API. +* **Operational overhead** – Because the mapping lives in the KVS, we must remember to run the maintenance script anywhere we expect the lookup table to be fresh. + +In the future we plan to introduce a formal user object that encapsulates identifiers, roles, and cross-system metadata. That abstraction would make this lookup process unnecessary by giving every component a single source of truth for student identity. Until then, this document serves as a reference for the current mapping workflow. diff --git a/docs/how-to/lti.md b/docs/how-to/lti.md new file mode 100644 index 000000000..b87ea3661 --- /dev/null +++ b/docs/how-to/lti.md @@ -0,0 +1,87 @@ +# Serve Learning Observer as an LTI 1.3 tool + +Learning Observer ships with an IMS LTI 1.3 implementation that relies on the platform's OpenID Connect (OIDC) handshake to authenticate users and obtain scoped API access tokens from the learning management system (LMS). Use this guide to register the tool in an LMS and connect it to a course shell. + +## Prerequisites + +* A deployment of Learning Observer reachable by the LMS (typically via HTTPS). +* An LMS that supports LTI 1.3 with dynamic registration or manual developer keys (e.g., Canvas or Schoology). +* Administrative access in that LMS to create a developer key / external tool. + +## 1. Generate and share a signing key + +Learning Observer signs client assertions with an RSA private key when it exchanges OIDC launch data for an LMS access token. Generate a keypair, store the private key somewhere on the application host, and upload the public key to the LMS when you create the developer key. + +```bash +# create a 4096-bit RSA keypair +openssl genrsa -out secrets/lti-tool-private.pem 4096 +openssl rsa -in secrets/lti-tool-private.pem -pubout > secrets/lti-tool-public.pem +``` + +Record the filesystem path to the private key; you'll reference it in the application configuration in the next step. + +## 2. Configure `creds.yaml` + +Enable the LTI provider in `learning_observer/creds.yaml` by adding an entry under `auth.lti.`. Each provider requires the LMS endpoints, the Learning Observer redirect URL, and the private key location. A Canvas example looks like this: + +```yaml +auth: + lti: + sample-canvas: + client_id: "10000000000000" + auth_uri: "https://canvas.example.edu/api/lti/authorize_redirect" + jwks_uri: "https://canvas.example.edu/api/lti/security/jwks" + token_uri: "https://canvas.example.edu/login/oauth2/token" + redirect_uri: "https://lo.example.edu/lti/sample-canvas/launch" + private_key_path: "secrets/lti-tool-private.pem" + api_domain: "https://canvas.example.edu" # Canvas-specific +``` + +Set `redirect_uri` to the public URL that will receive the POST launch request (`/lti//launch`). The login initiation URL for the LMS is the matching `/lti//login` route. + +Restart the application after updating configuration so the new provider registration is loaded. + +## 3. Enable LMS API routes + +Learning Observer only exposes the IMS Names & Roles (NRPS) and Assignment & Grade Service (AGS) proxy routes when the matching feature flag is turned on. Add the appropriate flag to `creds.yaml` so the application registers the routes during startup: + +```yaml +feature_flags: + canvas_routes: true # Canvas NRPS/AGS proxy endpoints + # schoology_routes: true # Schoology NRPS/AGS proxy endpoints +``` + +## 4. Map the roster source with PMSS + +LTI launches identify the LMS provider in the session so roster lookups can decide which backend to call. Create a PMSS overlay that maps the provider to the correct roster source (see [System settings](../concepts/system_settings.md) for more on PMSS). For Canvas, create a file such as `config/roster_source.pmss` alongside `creds.yaml` with the following contents: + +```pmss +roster_data[provider="sample-canvas"] { + source: sample-canvas; +} +``` + +If you support multiple LMS tenants, add additional selector blocks for their email domains or provider names and point them at `schoology`, `filesystem`, or any other supported roster backend. + +## 5. Register the tool in the LMS + +When you create the LTI developer key/external tool inside the LMS: + +1. Supply the **OIDC login initiation URL** as `https:///lti//login`. +2. Supply the **redirect/launch URL** as `https:///lti//launch`. +3. Paste the **public key** generated earlier so the LMS can validate the signed client assertions. +4. Copy the LMS-issued **client ID** and the platform endpoints (authorize, JWKS, token) into `creds.yaml` if you have not done so already. + +Publish the developer key and install the tool in the desired course/context. The LMS will send the context identifiers in the launch claims so Learning Observer can associate sessions with the right course. + +## 6. Verify the launch + +* Add the external tool link to a module or assignment inside the LMS course. +* Launch the tool from within the LMS. Learning Observer should redirect the browser to the LMS's authorize endpoint, validate the launch state and nonce, and then create a session for the user when the LMS returns. +* Successful launches land on the root of the application with LMS-specific authorization headers stored in the session for follow-up roster and grade sync operations. + +If the launch fails, inspect the Learning Observer logs for messages beginning with `LTI Launch`—they include detailed context whenever state validation, token exchange, or JWT verification fails. Once the LMS recognizes the tool, you can remove or hide other authentication methods; Learning Observer will automatically expose the LTI login routes whenever `auth.lti` providers are configured. + +## 7. Plan student identity mapping + +LTI launch data only includes the learner's email address, while Writing Observer's Google Workspace integrations emit a Google-specific user identifier. To keep downstream reducers and dashboards working for LTI cohorts, plan to run the maintenance workflow that maps emails to Google IDs. Refer to the [Student Identity Mapping guide](../concepts/student_identity_mapping.md) for an overview of how the reducer and maintenance script cooperate and how to operate the sync in production. From 10bdbfdf9ef16ad0878d2961b75173d2ca4e11ef Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:31:41 -0500 Subject: [PATCH 055/327] Updating documentation with additional local note files which will be updated as we deploy. --- docs/ncsu_setup.md | 297 +++++++++++++++++++++++++++++++++++++++++++++ docs/usagenotes.md | 8 ++ 2 files changed, 305 insertions(+) create mode 100644 docs/ncsu_setup.md create mode 100644 docs/usagenotes.md diff --git a/docs/ncsu_setup.md b/docs/ncsu_setup.md new file mode 100644 index 000000000..edf8e71c8 --- /dev/null +++ b/docs/ncsu_setup.md @@ -0,0 +1,297 @@ +# NCSU system setup guide +# ================================================== + +Currently the system is set for use with RHEL 8 on the NCSU systems. We are running with Python 3.9 and connected to the AWEWorkbench code. This assumes that we are also installing it into a vm with those tools installed as packages. An installation script has been added to the servermanagement directory. + + + + +# Older RHEL 7 Notes. +# ================================================== + + +The following is a guide to help with the installation of Learning Observer (LO) on NCSU systems. + +This guide assumes you are using an RHEL system. +Additionally, depending on where on the system you place the repository, you may need to run all commands as a sudo user. + +## Requirements + +LO is confirmed to work on `Python 3.8`. +Along with the base install of Python, LO requires the Python developer tools. +These can be installed with the following commands: + +```bash +sudo yum install rh-python38 # base python +sudo yum install python38-devel # developer tools for python 3.8 +``` + +On RHEL 7, the `python38-devel` is no longer recognized as a package. +To properly fetch the developer tools, use the following: + +```bash +sudo subscription-manager repos --enable rhel-7-server-optional-rpms --enable rhel-server-rhscl-7-rpms +sudo yum install rh-python38-python-devel.x86_64 +``` + +The Python installation should be located at `/opt/rh/rh-python38`. +Note this location for future sections. + +There is a chance you'll encounter an issue when installing the requirements, specifically `py-bcrypt`. +The developer tools do not show up in the exact proper place, so we need to create a soft symbolic link between the correct location and where they are located. +To create this link, use the following: + +```bash +cd /opt/rh/rh-python38/root +sudo ln -s usr/include/ . # check that Python.h exists in usr/include/python3.8/Python.h +``` + +Note, we are creating a link between the subdirectory `/opt/rh/rh-python38/root/usr/include` and `/opt/rh/rh-python38/root`. +Using `/usr/include` will result in the incorrect link. + +## Install + +### Virtual Environment + +To make sure we are using the proper installation of Python, we will use a virtual environment. +To do this, run the following command: + +```bash +/path/to/python3.8/ -m venv /path/of/desired/virtual/environment +``` + +Again, keep note of where the virtual environment is located for future steps. + +### Config files + +For each system, you'll need to create a new `creds.yaml` file within the `/path/to/repo/learning_observer` directory. +This file defines what type of connections are allowed to be made to the system. +Luckily, there is an example file you can copy located in the `/path/to/repo/learning_observer/learning_observer` directory. +When attempting to run the system later on in this setup guide, if you have any misconfigured here, then the system will tell you what's wrong. + +Some of the main changes that need to be made are: + +1. types of `auth` allowed, for simple setup, just remove the `google` child and all its subchildren +1. `aio` session secret and max age +1. `event_auth` to allow access from various locations (like Chromebooks) +1. `server` for reconfiguring the port information +1. `config:logging` for determining the `max_size` (in bytes) of each log file and total `backups` to keep around before rotating. + +More configurables are expected to be included in this config file in the future. + +### Package installation + +Before we get started installing packages, we must ensure that the `pip` in our virtual environment is up to date. +Some of the packages located in the `requirements.txt` file require `wheel` to be installed first. +After the base requirements are installed, we will also need to install the local packages (the Writing Observer module and the Learning Observer module). +To handle all the installs, use the following: + +```bash +cd writing_observer # cd into the top level of the repository +/path/to/venv/bin/pip install --upgrade pip # upgrade pip +/path/to/venv/bin/pip install wheel # install wheel +/path/to/venv/bin/pip install -r requirements.txt # install package requirements +/path/to/venv/bin/pip install -e learning_observer/ # install learning observer module +/path/to/venv/bin/pip install -e modules/writing_observer/ # install writing observer module +``` + +### Needed directories + +When installing Learning Observer for the first time, we need to create a few directories. +Use the following commands: + +```bash +mkdir /path/to/repo/learning_observer/learning_observer/static_data/course_lists +mkdir /path/to/repo/learning_observer/learning_observer/static_data/course_rosters +mkdir /path/to/repo/learning_observer/learning_observer/logs +mkdir /path/to/repo/learning_observer/learning_observer/logs/startup +``` + +### Proxy server + +By default, LO runs on port 8888. +Configure nginx, or another proxy server, for LO's port. + +### Executable files + +If this is the first time you are running the server on your system, you might need to make the shell scripts in the `servermanagement` directory executable. +To do this, use the following commands + +```bash +chmod +x /path/to/repo/servermanagement/RunLearningObserver.sh +chmod +x /path/to/repo/servermanagement/BackupWebSocketLogs.sh +``` + +## System specific changes + +There are various lines of code that point to specific servers. +For each setup, we need to make sure these are pointing to the proper place. + +### Server + +#### Auth information + +On the server, we need to point the redirect uri to the server we are working with. +Depending on how the credentials files was handled, this change may not be necessary to get the system running. +The redirect uri is used with the Google login. +If that is not used, then this step is not needed. +This is located in `/path/to/repo/learning_observer/learning_observer/auth/social_sso.py`. + +#### Server management + +Additionally, we need to set up the server management files in the `/path/to/repo/servermanagement` direcotry. + +In the `RunLearningObserver.sh` file, you'll want to set the system variables to match the current system. + +```bash +VIRTUALENV_PYTHON="/full/path/to/venv/bin/pip" +LEARNING_OBSERVER_LOC="/full/path/to/repo/learning_observer" +LOGFILE_DEST="/path/to/log/storage" +``` + +In the `BackupWebsocketLogs.sh` file, you'll want to set log directory to the same place as you set in `RunLearningObserver.sh` and set where the logs should be backed up. + +```bash +LOGFILE_SRC="/path/to/log/storage" +LOGFILE_DEST="/path/to/log/backups" +``` + +### Client + +On the clientside, we need to add the correct server to the `websocket_logger()` method in the `/path/to/repo/extension/extension/background.js` file. +If the server has SSL enabled, then the address we add should start with `wss://`. +If SSL is not enabled, then the address should start with `ws://`. +If a proxy server is not setup yet, make sure to include the port number (default 8888) on the end of the address. +An example of each instance is shown below: + +```js +websocket_logger("wss://writing.csc.ncsu.edu/wsapi/in/") // SSL enabled, nginx set +websocket_logger("ws://writing.csc.ncsu.edu:8888/wsapi/in/") // SSL not enabled, nginx not setup +``` + +## Running the server + +There are 2 different ways we can run the system. +One is better for debugging, whereas the other is best for when you want to run the server and leave it up. +We suggest completely testing the installation with the debugging steps first. + +### For debugging + +To run the system for debugging, we will just run the Learning Observer module. +This will output all the log information to the console. +To do this, use the following command: + +```bash +/path/to/venv/bin/python /learning_observer/learning_observer/ # run the learning observer module from within the learning observer directory +``` + +You should see any errors printed directly to the console. + +### As a server + +To run the system as a server, we will run the `RunLearningObserver.sh` script. +This fetches the virtual environment, runs the server, and pipes files into the proper log location we setup during the **System specific changes** section. +Run the following commands: + +```bash +./servermanagement/RunLearningObserver.sh +``` + +Check the logs for any errors. + +## Connecting the client + +The client is run through a Google Chrome extension. +To properly use the client, you must sign into Chrome and use the same account to access to Google Docs. + +From there, navigate to the extension manage located in settings. +Turn on Developer Mode (top right), then click the `Load Unpacked` button. +This opens a file explorer, where you should locate the repository. +More specifically, select the `writing_observer/extension/extension` directory. +This will unpack the extension and make it available for use in Google Chrome. + +To make sure it is working, click on the `background page` link on extension card from within the extension manager. +This opens an inspect window. +On this window, select the `Console` tab. +Next, open a Google doc and start typing. +You should see events within the console. +Ensure there are no logs sprinkled in. + +## Backing up logs + +Whenever a websocket is made, the server creates a new log file for that connection on top of the primary logs files. +We need to backup both the generic log files as well as all the websocket specific logs. + +### General logs + +The main logger for events is located in `event_logger.json`. +This is automatically backed up via the built-in Python logging module. +The settings for this file are handling via the `creds.yaml` file that you previously setup. +Simply changing the values and restarting the server will update the logging procress. + +### Websocket logs + +The websocket logs take a little more setting up. +We will set up a daily `cron` job to run a backup script, `/path/to/repo/servermanagement/BackupWebsocketLogs.sh`. +The backup script will search the log directory for any logs that match the websocket pattern and were last modified in the last **60 minutes**. +Next, the backup script will remove any files that match the pattern and were modifed in the last **120 minutes**. + +To set up the cron job, we first enter the crontab utility then add a line for the backup script. + +```bash +crontab -e # open the cron job menu + +0 1 * * * /usr/bin/sh /full/path/to/repo/servermanagement/BackupWebsocketLogs.sh # line to add to the cronjob +# Run it at the 0th minute every hour, every day, every month, and so on +``` + + + + +# Usage Notes +# ================================================================= +# Instructions for Configuring Writing Observer on RHEL Installations +### Install Global Dependencies +1. sudo yum install redis +2. sudo yum install git +3. sudo yum install nginx + +## Install Required RH Python 3.8 +4. sudo subscription-manager repos --enable rhel-7-server-optional-rpms \ + --enable rhel-server-rhscl-7-rpms +5. sudo yum -y install @development +6. sudo yum -y install rh-python38 + +* rh-pyhon38 dev tools are also required + +## Setup RH Python 38 and Virtual Envs +7. scl enable rh-python38 bash +8. python --version +* The output should indicate that python 3.8 is active +9. sudo pip install virtualenvwrapper +10. sudo source `/opt/rh/rh-python38/root/usr/local/bin/virtualenvwrapper.sh` + +## Install Local Dependencies +11. sudo git clone `https://github.com/ArgLab/writing_observer` +12. cd writing_observer +13. make install +14. sudo mkvirtualenv learning_observer +15. pip install -r requirements.txt +16. cd learning_observer +17. python setup.py develop +18. python learning_observer + +* At this point, follow the system's further instructions until the process runs on port 8888 by default + +## Server Setup +19. Populate creds.yaml with required Google Cloud Parameters +20. Configure nginx on `port 80` as a proxy for Learning Observer on `port 8888` +21. Replace all instances of `writing.csc.ncsu.edu` with custom server address in all files in directory `~/writing_observer/learning_observer/learning_observer/auth` + +## Client/Extension Setup +22. Replace all instances of `writing.csc.ncsu.edu` with custom server address in `~/writing_observer/extension/background.js` +* If SSL is not enabled for the server, all websocket protocols should begin with `ws://` as opposed to `wss://` +23. Open Chrome and navigate to `chrome://extensions` +24. Click on "Load Unpacked". Select `~/writing_observer/extensions` and ensure that it is enabled +25. Select `background page` on the extension section and ensure no errors are present +26. Open a Google Docs document while signed into Chrome and ensure websocket communication between client and server is active \ No newline at end of file diff --git a/docs/usagenotes.md b/docs/usagenotes.md new file mode 100644 index 000000000..fe1d8305b --- /dev/null +++ b/docs/usagenotes.md @@ -0,0 +1,8 @@ +## Usage Notes. + +For the moment this doc will act as some shared working knowledge for the use of the system with students. + + +# Extension Security. + +NOTE: The current working version of the chrome extension requires that the user is logged into both a Google account (which is registered to the classroom) *and* Chrome. This requirement stems from the security model used by the extension. On Chromebook devices this is the default behavior. In future work other devices will require a change. \ No newline at end of file From d0a8d2c135a92cd7b1a17a611a9c219f9d226191 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 056/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- docs/kafka_notes.md | 55 ++++++++++++++++++++ servermanagement/BackupWebSocketLogs.sh | 17 ++++++ servermanagement/RunLearningObserver.sh | 37 +++++++++++++ servermanagement/learning_observer_logrotate | 22 ++++++++ testcode/TestRedis.py | 22 ++++++++ testcode/WebSocketTest.py | 22 ++++++++ 6 files changed, 175 insertions(+) create mode 100644 docs/kafka_notes.md create mode 100644 servermanagement/BackupWebSocketLogs.sh create mode 100755 servermanagement/RunLearningObserver.sh create mode 100644 servermanagement/learning_observer_logrotate create mode 100644 testcode/TestRedis.py create mode 100644 testcode/WebSocketTest.py diff --git a/docs/kafka_notes.md b/docs/kafka_notes.md new file mode 100644 index 000000000..db01e179e --- /dev/null +++ b/docs/kafka_notes.md @@ -0,0 +1,55 @@ +# Structure notes + +Table for students + +student | sessions | hashes +---|---|--- +example@email.com | \[kafka_topic_id_00, kafka_topic_id_23\] | \[hash_of_kafka_topic_id_00\] + +Create session + +* Create Kafka stream +* Add student to student table with session name (REDIS or KAFKA) + +Closing behavior + +* Socket gets closed + * Times out? + * Could we determine when the document is closed? +* Message sent to data server + * The number of requests between servers will be dramatically fewer than messages between client and WO + * Could use a simple REST API +* Data server will: + * Compute the Hash + * Read data from Kafka stream + * Compute `hash = hash(data)` from our own hash function + * SHA 256 with some salt + * Create a Merkle tree where each leaf is a log event from the session. We use the root hash instead + * Append `hash` to a student's `hashes` + * Backup data + * Determine file location, `f = str(hash[:2]/hash[2:])` or some other way of hashing + * Create file at `f` + * There is some note that says Linux handles a lot of directories better than a lot of files in WYAG + * Write data to `f` + +Things TODO: + +* Turn on Kafka +* Write some of our data to Kafka stream + * Make the naming scheme easier to understand, for testing + * Just run it localy and collect the data through yourself +* Create simple REST API + * Post command to student + * Compute the hash, pull data, and store it + +How do we create the Merkle tree? + +* What is the purpose of the Merkle Tree? + * Where does it fit in? + * How will it be used? + * What is the purpose of the DAG portion? + +* Is it autostored in a merkle tree? i.e. the directory structure of our store is a merkle tree +* How are Merkle tree being used here? + * Do we store each log event as a Merkle Tree? Why? + * Do we store each log file as a Merkle Tree? Why? diff --git a/servermanagement/BackupWebSocketLogs.sh b/servermanagement/BackupWebSocketLogs.sh new file mode 100644 index 000000000..c3dbd59a7 --- /dev/null +++ b/servermanagement/BackupWebSocketLogs.sh @@ -0,0 +1,17 @@ +# System Variables +# -------------------------------------- +LOGFILE_SRC="/usr/local/share/Projects/WritingObserver/Repo-Fork/writing_observer/learning_observer/learning_observer/logs" +LOGFILE_DEST="/usr/local/share/Projects/WritingObserver/Repo-Fork/writing_observer/learning_observer/learning_observer/logs" + +# Make the backup name +# --------------------------------------- +LOG_DATE=$(date "+%m-%d-%Y--%H-%M-%S") +BACKUP_NAME="$LOGFILE_DEST/learning_observer_backup_$LOG_DATE.tar.gz" +echo $BACKUP_NAME; + +# Create the backup +# --------------------------------------- +echo "Backing up web socket logs" +find $LOGFILE_SRC -name "????-??-??T*.log" -mmin +60 -print0 | tar -czvf $BACKUP_NAME --null -T - +echo "Removing backed up web sockets logs" +find $LOGFILE_SRC -name "????-??-??T*.log" -mmin +120 -delete diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh new file mode 100755 index 000000000..4ce116949 --- /dev/null +++ b/servermanagement/RunLearningObserver.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# =============================== +# RunLearningObserver.sh +# Collin F. Lynch +# +# This bash script provides a simple wrapper to run the +# learning observer service and pipe the data to a logfile +# over time this should be integrated into the systemd +# service process. This uses static variables to specify +# the location of the virtualenv and the command and +# specifies the location for the running logfile. + +# System Variables +# -------------------------------------- +VIRTUALENV_PYTHON="/usr/local/share/Projects/WritingObserver/VirtualENVs/learning_observer/bin/python3.8" +LEARNING_OBSERVER_LOC="/usr/local/share/Projects/WritingObserver/Repo-Fork/writing_observer/learning_observer" +LOGFILE_DEST="/usr/local/share/Projects/WritingObserver/Repo-Fork/writing_observer/learning_observer/learning_observer/logs" + +# Make the logfile name +# --------------------------------------- +LOG_DATE=$(date "+%m-%d-%Y--%H-%M-%S") +LOGFILE_NAME="$LOGFILE_DEST/learning_observer_service_$LOG_DATE.log" +echo $LOG_NAME; + + +# Now run the thing. +# -------------------------------------- +echo "Running Learning Observer Service..." +cd $LEARNING_OBSERVER_LOC +#$($VIRTUALENV_PYTHON $LEARNING_OBSERVER_LOC > $LOG_NAME 2>&1) +nohup $VIRTUALENV_PYTHON learning_observer > $LOGFILE_NAME 2>&1 & +PROCESS_ID=$! +echo $PROCESS_ID > $LOGFILE_DEST/run.pid + + +# Set the number of allowed open files to something large 8192 +prlimit --pid $PROCESS_ID --nofile=8192 diff --git a/servermanagement/learning_observer_logrotate b/servermanagement/learning_observer_logrotate new file mode 100644 index 000000000..d3dc6bef5 --- /dev/null +++ b/servermanagement/learning_observer_logrotate @@ -0,0 +1,22 @@ +/path/to/repo/learning_observer/learning_observer/logs/*.pid +{ + daily + rotate 2 + olddir /path/to/backup + compress + missingok + notifempty +} + +/path/to/repo/learning_observer/learning_observer/logs/*.json +/path/to/repo/learning_observer/learning_observer/logs/learning_observer_service*.log +/path/to/repo/learning_observer/learning_observer/logs/debug.log +/path/to/repo/learning_observer/learning_observer/logs/incoming_websocket.log +{ + daily + rotate 5 + olddir /path/to/backup + compress + missingok + notifempty +} diff --git a/testcode/TestRedis.py b/testcode/TestRedis.py new file mode 100644 index 000000000..ca7cb42e8 --- /dev/null +++ b/testcode/TestRedis.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# Simple Asyncio redis test. + + +import asyncio +import asyncio_redis + + +async def example(): + # Create Redis connection + connection = await asyncio_redis.Connection.create(host='localhost', port=6379) + + # Set a key + await connection.set('my_key', 'my_value') + + # When finished, close the connection. + connection.close() + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(example()) diff --git a/testcode/WebSocketTest.py b/testcode/WebSocketTest.py new file mode 100644 index 000000000..0ad026e0c --- /dev/null +++ b/testcode/WebSocketTest.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# ================================== +# WebSocketTest.py +# Collin F. Lynch. +# +# This is a simple piece of code that I put together to +# ping the websockets API of the server just to confirm +# that it is running. +# +# Just gets a reject at the moment which is fine. + + +import asyncio +import websockets + +def test_url(url, data=""): + async def inner(): + async with websockets.connect(url) as websocket: + await websocket.send(data) + return asyncio.get_event_loop().run_until_complete(inner()) + +test_url("wss://writing.csc.ncsu.edu/wsapi/in") From 9dbb1ee6b9e8124f0e1216e7a9894278348fdfd8 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sat, 3 Dec 2022 13:32:15 -0500 Subject: [PATCH 057/327] Updating documentation on installation scripts. --- docs/ncsu_setup.md | 7 +++++++ servermanagement/SetupVENV.sh | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100755 servermanagement/SetupVENV.sh diff --git a/docs/ncsu_setup.md b/docs/ncsu_setup.md index edf8e71c8..79725bccd 100644 --- a/docs/ncsu_setup.md +++ b/docs/ncsu_setup.md @@ -4,6 +4,13 @@ Currently the system is set for use with RHEL 8 on the NCSU systems. We are running with Python 3.9 and connected to the AWEWorkbench code. This assumes that we are also installing it into a vm with those tools installed as packages. An installation script has been added to the servermanagement directory. +Ihnstallation on RHEL 8 requires: + +- python 3.9 or 3.10 (39 still default). +- redis.x86_64 5.0.3-5.module+el8.4.0+12927+b9845322 @rhel-8-for-x86_64-appstream-rpms +- redis-devel.x86_64 5.0.3-5.module+el8.4.0+12927+b9845322 @rhel-8-for-x86_64-appstream-rpms + + # Older RHEL 7 Notes. diff --git a/servermanagement/SetupVENV.sh b/servermanagement/SetupVENV.sh new file mode 100755 index 000000000..d18bcfdde --- /dev/null +++ b/servermanagement/SetupVENV.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# +# SetupVENV.sh +# Collin F. Lynch + +# This script performs the basic VENV setup necessary for our LO +# server. When called it takes as an argument the path for the +# VENV storage and a name. It then generates the VENV and upgrades +# the local pip install. It does *not* install the workbench or +# LO code. That part must be done with separate scripts that +# are located in this folder and in the AWE_Workbench code. + + +# Parameters +# ----------------------------------------------- +# Change these params + +PYTHON_CMD="python3.9" +PIP_CMD="pip" + + +# Argument Parsing +# ----------------------------------------------- + +VIRTUAL_ENV_LOC=$2 +VIRTUAL_ENV_NAME=$1 + +# Execution +# --------------------------------------------------------- +echo "1) Generating VENV" +"$PYTHON_CMD" -m venv "$VIRTUAL_ENV_LOC/$VIRTUAL_ENV_NAME" + +# Initialize +echo "2) Starting $VIRTUAL_ENV_NAME" +source "$VIRTUAL_ENV_LOC/$VIRTUAL_ENV_NAME/bin/activate" + +# Update the Pip Version. +echo "3) Updgrading Pip" +"$PIP_CMD" install --upgrade pip From 8d2b081f18bc6113cdd056ea6ed225b358b8d53f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:28:57 -0500 Subject: [PATCH 058/327] Adding initialization scripts. --- servermanagement/AddWOtoVENV.sh | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 servermanagement/AddWOtoVENV.sh diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh new file mode 100644 index 000000000..7058001b2 --- /dev/null +++ b/servermanagement/AddWOtoVENV.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# Add AWOtoVENV +# Collin F. Lynch + +# This script takes as argument a specified VENV. It +# then adds the Learning Observer, Writing Observer, and +# the dashboard. Construction of the VENV can be done +# using the SetupVENV script located in this directory. + + +# Parameters: +# --------------------------------------------- +PYTHON_CMD="python" +PIP_CMD="pip" + +CODE_REPOS_LOC="../../" + + +# Argument +# -------------------------------------------- +VIRTUAL_ENV="$1" +echo "USING VENV: $VIRTUAL_ENV" + + +# Activate VENV +# --------------------------------------------------------- +source "$VIRTUAL_ENV/bin/activate" + + +# Installation +# ---------------------------------------------------------- + +# Install basic requirements. +echo -e "\n=== Installing Requirements.txt ===" +cd .. +"$PIP_CMD" install -r requirements.txt + +echo -e "\n=== Installing Learning Observer ===" +cd learning_observer +"$PYTHON_CMD" setup.py develop + + +echo -e "\n=== Installing Writing Observer ===" +cd ../modules/writing_observer +"$PYTHON_CMD" setup.py develop + + +echo -e "\n=== Installing Brad's Dashboard ===" +cd ../../learning_observer/prototypes/dash_wo_teacher_dashboard +"$PYTHON_CMD" setup.py develop + From a8e1ea6b8738041562ef6dc7f7f76f97031a8fc2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 059/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 3c94386b023ca3481c103c7efaef4d664f8719d3 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 060/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 00ee86f7b..e054cf75a 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json From 49aaac604639b1676b72e20fa1f603f472540095 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 061/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- 4 files changed, 12 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index e054cf75a..8a8a3c5b4 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json From 73dc537ebb0152aef8f90f432cd32f8da1df974d Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 23 Dec 2022 11:24:37 -0500 Subject: [PATCH 062/327] Add settings to dropdown menu --- .../wo_highlight_dashboard/dashboard/students.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index 0aa405fce..fa798188c 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,6 +120,7 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ + settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn From 5bf62b7d9f8034a0de7dd94e8b27c11f53efea0a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 063/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 8 ++ 2 files changed, 96 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 7ebe5dd15..5a5603674 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -357,6 +358,13 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = writing_observer.event_wrapper.get_doc_id(event) + + print(">>> last_doc_call docid: ", document_id) + if document_id is not None: state = {"document_id": document_id} return state, state From 6cf71ea49df257d7eac26861127180a37431b593 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 064/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- .../writing_observer/writing_analysis.py | 9 +++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 5a5603674..9c131c872 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -358,12 +358,11 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - print(">>> last_doc_call: ", event) - - #document_id = event.get('client', {}).get('doc_id', None) + # Initially this code looked only for cases where the document + # id was specified by a doc_id field. This fix uses the event + # wrapper methods to support access of IDs located in the + # doc_id field or in the 'object' field. document_id = writing_observer.event_wrapper.get_doc_id(event) - - print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From 0170eb6f180bfea5ef93cc86ade3c0120b37d3e0 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:07 -0500 Subject: [PATCH 065/327] Removing some unnecessary info. --- .../incoming_student_event.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/learning_observer/learning_observer/incoming_student_event.py b/learning_observer/learning_observer/incoming_student_event.py index 53479bbd6..e2149867a 100644 --- a/learning_observer/learning_observer/incoming_student_event.py +++ b/learning_observer/learning_observer/incoming_student_event.py @@ -383,6 +383,7 @@ async def update_event_handler(event): if not authenticated: return False +<<<<<<< HEAD nonlocal event_handler, reducers_last_updated if 'source' in lock_fields: debug_log('Updating the event_handler()') @@ -398,6 +399,33 @@ async def handle_auth_events(events): '''This method checks a single method for auth and updates our `lock_fields`. If we are unauthenticated, an error will be thrown and we ignore it. +======= + # We're now ready to make the pipeline. + hostname = socket.gethostname() + decoder_and_logger = event_decoder_and_logger( + request, + headers=header_events, + metadata={ + 'ip': request.remote, + 'host': request.headers.get('Host', ''), + 'user_agent': request.headers.get('User-Agent', ''), + 'x_real_ip': request.headers.get('X-Real-IP', ''), + 'timestamp': datetime.datetime.utcnow().isoformat(), + 'session_count': COUNT, + 'pid': os.getpid(), + 'hostname': hostname, + 'hostip': socket.gethostbyname(hostname), + 'referer': request.headers.get('Referer', ''), + 'host': request.headers.get('Host', ''), + 'x-forwarded-for': request.headers.get('X-Forwarded-For', ''), + 'x-forwarded-host': request.headers.get('X-Forwarded-Host', '') + }, + session={ + 'student': event_metadata['auth']['safe_user_id'], + 'source': event_metadata['source'] + } + ) +>>>>>>> f72c6224 (Removing some unnecessary info.) HACK The auth method expects a list of events to find specific auth events. Since we are yielding event by From b96e16235e064990a5793c333d3ace5badc7b603 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 066/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 6c92f75ec0d7cc5ad8643e528c64b06f4f9803d0 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:39:13 -0500 Subject: [PATCH 067/327] Updating writing analysis to better deal with event types. --- .../writing_observer/writing_analysis.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 9c131c872..dafa32bea 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -358,11 +358,12 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - # Initially this code looked only for cases where the document - # id was specified by a doc_id field. This fix uses the event - # wrapper methods to support access of IDs located in the - # doc_id field or in the 'object' field. - document_id = writing_observer.event_wrapper.get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = get_doc_id_wrapper(event) + + print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From aa3f0b077f9067757e60c77077b079fece3b328d Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 068/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 0e2c676ab68f1c959fe3293b543d9313980c42da Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:52 -0500 Subject: [PATCH 069/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index dafa32bea..9e0bd31f5 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -360,7 +360,6 @@ async def last_document(event, internal_state): print(">>> last_doc_call: ", event) - #document_id = event.get('client', {}).get('doc_id', None) document_id = get_doc_id_wrapper(event) print(">>> last_doc_call docid: ", document_id) From b513891ebf982de4a5dd02e89d7a51d1a2ec2555 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 070/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 4ce116949..8e6f780eb 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh @@ -12,9 +13,10 @@ # System Variables # -------------------------------------- -VIRTUALENV_PYTHON="/usr/local/share/Projects/WritingObserver/VirtualENVs/learning_observer/bin/python3.8" -LEARNING_OBSERVER_LOC="/usr/local/share/Projects/WritingObserver/Repo-Fork/writing_observer/learning_observer" -LOGFILE_DEST="/usr/local/share/Projects/WritingObserver/Repo-Fork/writing_observer/learning_observer/learning_observer/logs" +VIRTUALENV_PATH="/usr/local/share/projects/WritingObserver/VirtualENVs/WOvenv" +#VIRTUALENV_PYTHON="/usr/local/share/Projects/WritingObserver/VirtualENVs/learning_observer/bin/python3.9" +LEARNING_OBSERVER_LOC="/usr/local/share/projects/WritingObserver/Repositories/ArgLab_writing_observer/learning_observer" +LOGFILE_DEST="/usr/local/share/projects/WritingObserver/Repositories/ArgLab_writing_observer/learning_observer/learning_observer/logs" # Make the logfile name # --------------------------------------- @@ -27,8 +29,9 @@ echo $LOG_NAME; # -------------------------------------- echo "Running Learning Observer Service..." cd $LEARNING_OBSERVER_LOC +source $VIRTUALENV_PATH/bin/activate #$($VIRTUALENV_PYTHON $LEARNING_OBSERVER_LOC > $LOG_NAME 2>&1) -nohup $VIRTUALENV_PYTHON learning_observer > $LOGFILE_NAME 2>&1 & +nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid From 2797d828e8fe8ca1e2981e8177421877f47aea60 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 071/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 9e0bd31f5..e8a0a884a 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 660985cc82fc1e3cd129f950aee884764a95d082 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 9 Feb 2023 13:25:26 -0500 Subject: [PATCH 072/327] Updating with comments. --- servermanagement/AddWOtoVENV.sh | 18 ++++++++++++------ servermanagement/SetupVENV.sh | 20 +++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 7058001b2..41115b78d 100644 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -9,20 +9,26 @@ # using the SetupVENV script located in this directory. +# Argument +# -------------------------------------------- +# This takes a single argument that should point +# to the directory of the VENV. You can then +# use this to make any necessary changes. +VIRTUAL_ENV="$1" +echo "USING VENV: $VIRTUAL_ENV" + + + # Parameters: # --------------------------------------------- +# Change these if you need to use a different +# python or pip. Otherwise leave them as-is. PYTHON_CMD="python" PIP_CMD="pip" CODE_REPOS_LOC="../../" -# Argument -# -------------------------------------------- -VIRTUAL_ENV="$1" -echo "USING VENV: $VIRTUAL_ENV" - - # Activate VENV # --------------------------------------------------------- source "$VIRTUAL_ENV/bin/activate" diff --git a/servermanagement/SetupVENV.sh b/servermanagement/SetupVENV.sh index d18bcfdde..14e9c8b51 100755 --- a/servermanagement/SetupVENV.sh +++ b/servermanagement/SetupVENV.sh @@ -11,19 +11,25 @@ # are located in this folder and in the AWE_Workbench code. -# Parameters +# Argument Parsing # ----------------------------------------------- -# Change these params +# The first argument to the script will specify the name of +# the virtual environment. Use something simple like WOVenv +VIRTUAL_ENV_NAME=$1 -PYTHON_CMD="python3.9" -PIP_CMD="pip" +# The second should be a path to your working directory (above the +# repositories) where you will actually run the code. +VIRTUAL_ENV_LOC=$2 -# Argument Parsing +# Parameters # ----------------------------------------------- +# Change these params if you need to shift python +# or pip versions. Otherwise leave them as-is. + +PYTHON_CMD="python3.9" +PIP_CMD="pip" -VIRTUAL_ENV_LOC=$2 -VIRTUAL_ENV_NAME=$1 # Execution # --------------------------------------------------------- From 44a87952e7f3a8505b19b42d0b3f8f3b8c0aa528 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 073/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 8e6f780eb..c255f7544 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From d5e3e1ec3b937ae3c43791398f52fbaae9a3c909 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sat, 3 Dec 2022 13:32:15 -0500 Subject: [PATCH 074/327] Updating documentation on installation scripts. --- servermanagement/SetupVENV.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/servermanagement/SetupVENV.sh b/servermanagement/SetupVENV.sh index 14e9c8b51..1da923645 100755 --- a/servermanagement/SetupVENV.sh +++ b/servermanagement/SetupVENV.sh @@ -31,6 +31,12 @@ PYTHON_CMD="python3.9" PIP_CMD="pip" +# Argument Parsing +# ----------------------------------------------- + +VIRTUAL_ENV_LOC=$2 +VIRTUAL_ENV_NAME=$1 + # Execution # --------------------------------------------------------- echo "1) Generating VENV" From 26df7492c4dd39d6e845338724a747cffa65e1be Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 075/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/dashboard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From ebbacd7c6b2a3ef87923c1f0ba79e4cfc92b2f6c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 076/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/dashboard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 0f0eb84d6c3b0198999c12975e04048180d34895 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 22 Dec 2022 00:18:23 -0500 Subject: [PATCH 077/327] Updating doc branch. --- .../incoming_student_event.py | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/learning_observer/learning_observer/incoming_student_event.py b/learning_observer/learning_observer/incoming_student_event.py index e2149867a..53479bbd6 100644 --- a/learning_observer/learning_observer/incoming_student_event.py +++ b/learning_observer/learning_observer/incoming_student_event.py @@ -383,7 +383,6 @@ async def update_event_handler(event): if not authenticated: return False -<<<<<<< HEAD nonlocal event_handler, reducers_last_updated if 'source' in lock_fields: debug_log('Updating the event_handler()') @@ -399,33 +398,6 @@ async def handle_auth_events(events): '''This method checks a single method for auth and updates our `lock_fields`. If we are unauthenticated, an error will be thrown and we ignore it. -======= - # We're now ready to make the pipeline. - hostname = socket.gethostname() - decoder_and_logger = event_decoder_and_logger( - request, - headers=header_events, - metadata={ - 'ip': request.remote, - 'host': request.headers.get('Host', ''), - 'user_agent': request.headers.get('User-Agent', ''), - 'x_real_ip': request.headers.get('X-Real-IP', ''), - 'timestamp': datetime.datetime.utcnow().isoformat(), - 'session_count': COUNT, - 'pid': os.getpid(), - 'hostname': hostname, - 'hostip': socket.gethostbyname(hostname), - 'referer': request.headers.get('Referer', ''), - 'host': request.headers.get('Host', ''), - 'x-forwarded-for': request.headers.get('X-Forwarded-For', ''), - 'x-forwarded-host': request.headers.get('X-Forwarded-Host', '') - }, - session={ - 'student': event_metadata['auth']['safe_user_id'], - 'source': event_metadata['source'] - } - ) ->>>>>>> f72c6224 (Removing some unnecessary info.) HACK The auth method expects a list of events to find specific auth events. Since we are yielding event by From 4ae1d8c8607b5b9680674f97930ed30876146095 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 078/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index e8a0a884a..9e0bd31f5 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 864c0c73489ccecfe4c4b6b71485e3a0481476f5 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 079/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From 94b61ea25a758d40c5c8f352963ae6badaca1b7e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 080/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 5d728a1e03d41c2c54fc1be763ed38fcefe78b6e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 081/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 2c37e0ab44b3fb4185d7a425df5ef8eb06ce798e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 082/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index c255f7544..8e6f780eb 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 8410f9e5c52bea3308e7d7343b9bee8d77c79d0e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 083/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 9e0bd31f5..e8a0a884a 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 8eda692aaccf78d38cb4e22b738ab9a5b74170db Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 9 Feb 2023 13:25:26 -0500 Subject: [PATCH 084/327] Updating with comments. --- servermanagement/SetupVENV.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/servermanagement/SetupVENV.sh b/servermanagement/SetupVENV.sh index 1da923645..14e9c8b51 100755 --- a/servermanagement/SetupVENV.sh +++ b/servermanagement/SetupVENV.sh @@ -31,12 +31,6 @@ PYTHON_CMD="python3.9" PIP_CMD="pip" -# Argument Parsing -# ----------------------------------------------- - -VIRTUAL_ENV_LOC=$2 -VIRTUAL_ENV_NAME=$1 - # Execution # --------------------------------------------------------- echo "1) Generating VENV" From 38b9fd4c7a4e92a950a2a89d0cc1a4cfa70ea4af Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 00:15:11 -0500 Subject: [PATCH 085/327] Minor cleaning. --- .../writing_observer/writing_analysis.py | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index e8a0a884a..3c4cdb431 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -350,19 +350,14 @@ async def last_document(event, internal_state): Small bit of data -- the last document accessed. This can be extracted from `document_list`, but we don't need that level of complexity for the 1.0 dashboard. - This code accesses the code below which provides some hackish support functions for the analysis. Over time these may age off with a better model. ''' document_id = get_doc_id(event) - print(">>> last_doc_call: ", event) - document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call docid: ", document_id) - if document_id is not None: state = {"document_id": document_id} return state, state @@ -370,6 +365,46 @@ async def last_document(event, internal_state): return False, False +# Basic class tests and extraction. +# ------------------------------- +# A big part of this project is wrapping up google doc events. +# In doing that we are reverse-engineering some of the elements +# particularly the event types. This code provides some basic +# wrappers for event types to simplify extraction of key elements +# and to simplify event recognition. +# +# Over time this will likely expand and will need to adapt to keep +# up with any changes in the event structure. For now it is just +# a thin abstraction layer on a few of the pieces. + +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return (Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return (Event_Type == 'keystroke') + + # Simple hack to match URLs. This should probably be moved as well # but for now it works. # From 6956a5ca7701cbdfc519bbd8e4568cde81f706e3 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 086/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 8a8a3c5b4..00ee86f7b 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 34cbe91105b6a955459a9cd5e1d650a8984b60c9 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 13:28:40 -0500 Subject: [PATCH 087/327] Adding exec. --- servermanagement/AddWOtoVENV.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 servermanagement/AddWOtoVENV.sh diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh old mode 100644 new mode 100755 From 1f77305f1e201c82f2c556a2b30e99b5e7728fbc Mon Sep 17 00:00:00 2001 From: DrLynch Date: Tue, 7 Mar 2023 14:44:02 -0500 Subject: [PATCH 088/327] Fixing load error on google.py startup to ablate unneeded code. --- learning_observer/learning_observer/google.py | 433 ++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 learning_observer/learning_observer/google.py diff --git a/learning_observer/learning_observer/google.py b/learning_observer/learning_observer/google.py new file mode 100644 index 000000000..6d9ecded0 --- /dev/null +++ b/learning_observer/learning_observer/google.py @@ -0,0 +1,433 @@ +''' +We will gradually move all of the Google-specific code into here. + +Our design goals: +- Easily call into Google APIs (Classroom, Drive, Docs, etc.) +- Be able to preprocess the data into standard formats + +On a high level, for each Google request, we plan to have a 4x4 grid: +- Web request and function call +- Cleaned versus raw data + +The Google APIs are well-designed (if poorly-documented, and with occasional +bugs), but usually return more data than we need, so we have cleaner functions. + +For a given call, we might have several cleaners. For example, for a Google Doc, +Google returns a massive JSON object containing everything. For most purposes, +we don't need all of that, and it's more convenient to work with a plain +text representation, and for downstream code to not need to understand this +JSON. However, for some algorithms, we might need additonal data of different +sorts. It's still more convenient to hand this back in something simplified for +analysis. +''' + +import collections +import itertools +import json +import recordclass +import string +import re + +import aiohttp +import aiohttp.web + +import learning_observer.settings as settings +import learning_observer.log_event +import learning_observer.util +import learning_observer.auth +import learning_observer.runtime + + +cache = None + + +GOOGLE_FIELDS = [ + 'alternateLink', 'calculationType', 'calendarId', 'courseGroupEmail', + 'courseId', 'courseState', 'creationTime', 'descriptionHeading', + 'displaySetting', 'emailAddress', 'enrollmentCode', 'familyName', + 'fullName', 'givenName', 'gradebookSettings', 'guardiansEnabled', + 'ownerId', 'photoUrl', 'teacherFolder', 'teacherGroupEmail', 'updateTime', + 'userId' +] + +# On in-take, we want to convert Google's CamelCase to LO's snake_case. This +# dictionary contains the conversions. +camel_to_snake = re.compile(r'(?>> ("hello {hi} my {bye}")] + ['hi', 'bye'] + ''' + # The parse returns a lot of context, which we discard. In particular, the + # last item is often about the suffix after the last parameter and may be + # `None` + return [f[1] for f in string.Formatter().parse(format_string) if f[1] is not None] + + +async def raw_google_ajax(runtime, target_url, **kwargs): + ''' + Make an AJAX call to Google, managing auth + auth. + + * runtime is a Runtime class containing request information. + * default_url is typically grabbed from ENDPOINTS + * ... and we pass the named parameters + ''' + request = runtime.get_request() + url = target_url.format(**kwargs) + cache_key = "raw_google/" + learning_observer.util.url_pathname(url) + if settings.feature_flag('use_google_ajax') is not None: + value = await cache[cache_key] + if value is not None: + return learning_observer.util.translate_json_keys( + json.loads(value), + GOOGLE_TO_SNAKE + ) + async with aiohttp.ClientSession(loop=request.app.loop) as client: + if 'auth_headers' not in request: + raise aiohttp.web.HTTPUnauthorized(text="Please log in") # TODO: Consistent way to flag this + async with client.get(url, headers=request["auth_headers"]) as resp: + response = await resp.json() + learning_observer.log_event.log_ajax(target_url, response, request) + if settings.feature_flag('use_google_ajax') is not None: + await cache.set(cache_key, json.dumps(response, indent=2)) + return learning_observer.util.translate_json_keys( + response, + GOOGLE_TO_SNAKE + ) + + +def raw_access_partial(remote_url, name=None): + ''' + This is a helper which allows us to create a function which calls specific + Google APIs. + + To test this, try: + + print(await raw_document(request, documentId="some_google_doc_id")) + ''' + async def caller(request, **kwargs): + ''' + Make an AJAX request to Google + ''' + return await raw_google_ajax(request, remote_url, **kwargs) + setattr(caller, "__qualname__", name) + + return caller + + +def initialize_and_register_routes(app): + ''' + This is a big 'ol function which might be broken into smaller ones at some + point. We: + + - Created debug routes to pass through AJAX requests to Google + - Created production APIs to have access to cleaned versions of said data + - Create local function calls to call from other pieces of code + within process + + We probably don't need all of this in production, but a lot of this is + very important for debugging. Having APIs is more useful than it looks, since + making use of Google APIs requires a lot of infrastructure (registering + apps, auth/auth, etc.) which we already have in place on dev / debug servers. + ''' + # # For now, all of this is behind one big feature flag. In the future, + # # we'll want seperate ones for the debugging tools and the production + # # staff + # if 'google_routes' not in settings.settings['feature_flags']: + # return + + for key in ['save_google_ajax', 'use_google_ajax', 'save_clean_ajax', 'use_clean_ajax']: + if key in settings.settings['feature_flags']: + global cache + cache = learning_observer.kvs.FilesystemKVS(path=learning_observer.paths.data('google'), subdirs=True) + + # Provide documentation on what we're doing + app.add_routes([ + aiohttp.web.get("/google", api_docs_handler) + ]) + + def make_ajax_raw_handler(remote_url): + ''' + This creates a handler to forward Google requests to the client. It's used + for debugging right now. We should think through APIs before relying on this. + ''' + async def ajax_passthrough(request): + ''' + And the actual handler.... + ''' + response = await raw_google_ajax( + request, + remote_url, + **request.match_info + ) + + return aiohttp.web.json_response(response) + return ajax_passthrough + + def make_cleaner_handler(raw_function, cleaner_function, name=None): + async def cleaner_handler(request): + ''' + ''' + response = cleaner_function( + await raw_function(request, **request.match_info) + ) + if isinstance(response, dict) or isinstance(response, list): + return aiohttp.web.json_response( + response + ) + elif isinstance(response, str): + return aiohttp.web.Response( + text=response + ) + else: + raise AttributeError(f"Invalid response type: {type(response)}") + if name is not None: + setattr(cleaner_handler, "__qualname__", name + "_handler") + + return cleaner_handler + + def make_cleaner_function(raw_function, cleaner_function, name=None): + async def cleaner_local(request, **kwargs): + google_response = await raw_function(request, **kwargs) + clean = cleaner_function(google_response) + return clean + if name is not None: + setattr(cleaner_local, "__qualname__", name) + return cleaner_local + + for e in ENDPOINTS: + function_name = f"raw_{e.name}" + raw_function = raw_access_partial(remote_url=e.remote_url, name=e.name) + globals()[function_name] = raw_function + cleaners = e._cleaners() + for c in cleaners: + app.add_routes([ + aiohttp.web.get( + cleaners[c]['local_url'], + make_cleaner_handler( + raw_function, + cleaners[c]['function'], + name=cleaners[c]['name'] + ) + ) + ]) + globals()[cleaners[c]['name']] = make_cleaner_function( + raw_function, + cleaners[c]['function'], + name=cleaners[c]['name'] + ) + app.add_routes([ + aiohttp.web.get( + e._local_url(), + make_ajax_raw_handler(e.remote_url) + ) + ]) + + +def api_docs_handler(request): + ''' + Return a list of available endpoints. + + Eventually, we should also document available function calls + ''' + response = "URL Endpoints:\n\n" + for endpoint in ENDPOINTS: + response += f"{endpoint._local_url()}\n" + cleaners = endpoint._cleaners() + for c in cleaners: + response += f" {cleaners[c]['local_url']}\n" + response += "\n\n Globals:" + if False: + response += str(globals()) + return aiohttp.web.Response(text=response) + + +def register_cleaner(data_source, cleaner_name): + ''' + This will register a cleaner function, for export both as a web service + and as a local function call. + ''' + def decorator(f): + found = False + for endpoint in ENDPOINTS: + if endpoint.name == data_source: + found = True + endpoint._add_cleaner( + cleaner_name, + { + 'function': f, + 'local_url': f'{endpoint._local_url()}/{cleaner_name}', + 'name': cleaner_name + } + ) + + if not found: + raise AttributeError(f"Data source {data_source} invalid; not found in endpoints.") + return f + + return decorator + + +# Rosters +@register_cleaner("course_roster", "roster") +def clean_course_roster(google_json): + ''' + Retrieve the roster for a course, alphabetically + ''' + students = google_json.get('students', []) + students.sort( + key=lambda x: x.get('name', {}).get('fullName', 'ZZ'), + ) + # Convert Google IDs to internal ideas (which are the same, but with a gc- prefix) + for student_json in students: + google_id = student_json['profile']['id'] + local_id = learning_observer.auth.google_id_to_user_id(google_id) + student_json['user_id'] = local_id + del student_json['profile']['id'] + + # For the present there is only one external id so we will add that directly. + if 'external_ids' not in student_json['profile']: + student_json['profile']['external_ids'] = [] + student_json['profile']['external_ids'].append({"source": "google", "id": google_id}) + return students + + +@register_cleaner("course_list", "courses") +def clean_course_list(google_json): + ''' + Google's course list is one object deeper than we'd like, and alphabetic + sort order is nicer. This will clean it up a bit + ''' + courses = google_json.get('courses', []) + courses.sort( + key=lambda x: x.get('name', 'ZZ'), + ) + return courses + + +# Google Docs +def _force_text_length(text, length): + ''' + Force text to a given length, either concatenating or padding + + >>> force_text_length("Hello", 3) + >>> 'Hel' + + >>> force_text_length("Hello", 13) + >>> 'Hello ' + ''' + return text[:length] + " " * (length - len(text)) + + +def get_error_details(error): + messages = { + 403: 'Student working on private document.', + 404: 'Unable to fetch document.' + } + code = error['code'] + message = messages.get(code, 'Unknown error.') + return {'error': {'code': code, 'message': message}} + + +@register_cleaner("document", "doctext") +def extract_text_from_google_doc_json( + j, align=True, + EXTRACT_DEBUG_CHECKS=False): + ''' + Extract text from a Google Docs JSON object, ignoring formatting. + + There is an alignment issue between Google's and Python's handling + of Unicode. We can either: + * extract text faithfully (align=False) + * extract text with aligned indexes by cutting text / adding + spaces (align=True) + + This issue came up in text with a Russian flag unicode symbol + (referencing the current conflict). I tried various encodings, + and none quite matched Google 100%. + + Note that align=True doesn't necessarily give perfect local alignment + within text chunks, since we do have different lengths for something like + this flag. It does work okay globally. + ''' + # return error message for text + if 'error' in j: + return get_error_details(j['error']) + length = j['body']['content'][-1]['endIndex'] + elements = [a.get('paragraph', {}).get('elements', []) for a in j['body']['content']] + flat = sum(elements, []) + text_chunks = [f['textRun']['content'] for f in flat] + if align: + lengths = [f['endIndex'] - f['startIndex'] for f in flat] + text_chunks = [_force_text_length(chunk, length) for chunk, length in zip(text_chunks, lengths)] + text = ''.join(text_chunks) + + if EXTRACT_DEBUG_CHECKS: + print("Text length versus Google length:") + print(len(text), length) + print("We expect these to be off by one, since Google seems to starts at 1 (and Python at 0)") + if align: + print + print("Offsets (these should match):") + print(list(zip(itertools.accumulate(map(len, text_chunks)), itertools.accumulate(lengths)))) + + return {'text': text} + + +if __name__ == '__main__': + import json + import sys + j = json.load(open(sys.argv[1])) + extract_text_from_google_doc_json(j, align=False, EXTRACT_DEBUG_CHECKS=True) + extract_text_from_google_doc_json(j, align=True, EXTRACT_DEBUG_CHECKS=True) From cac7a8ae5be8c8b6f6985ab76a0138d22fd69d97 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Tue, 7 Mar 2023 15:36:24 -0500 Subject: [PATCH 089/327] Fixing basic error in aggregator. --- modules/writing_observer/writing_observer/aggregator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 85b3809c5..9e7294eeb 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -410,6 +410,9 @@ async def latest_data(runtime, student_data, options=None): writing_data = await merge_with_student_data(writing_data, student_data) writing_data = await processor(writing_data, options) + writing_data = await merge_with_student_data(writing_data, student_data) + writing_data = await processor(writing_data, options) + return {'latest_writing_data': writing_data} From 2d3fbfd30e1616f4c98058f1a9f672722a6ed41c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Tue, 7 Mar 2023 15:36:59 -0500 Subject: [PATCH 090/327] Fixing new dashboard structure. --- servermanagement/AddWOtoVENV.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 41115b78d..9428da35c 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -53,6 +53,6 @@ cd ../modules/writing_observer echo -e "\n=== Installing Brad's Dashboard ===" -cd ../../learning_observer/prototypes/dash_wo_teacher_dashboard +cd ../wo_highlight_dashboard "$PYTHON_CMD" setup.py develop From e38867643fcf7dcb87b7a67e5bbb51573fc28aef Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 12:33:45 -0400 Subject: [PATCH 091/327] Minor tweak to service startup. --- servermanagement/RunLearningObserver.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 8e6f780eb..5fba8041d 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -34,7 +34,5 @@ source $VIRTUALENV_PATH/bin/activate nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid - - # Set the number of allowed open files to something large 8192 prlimit --pid $PROCESS_ID --nofile=8192 From de8f063c1c3f58f30e1de280f9eeb2f089e1b266 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 14:01:45 -0400 Subject: [PATCH 092/327] Making minor fix in module loading for new libraries. --- .../wo_highlight_dashboard/module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index cbf8b1f8e..4a4008990 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,6 +23,18 @@ } ] +# Third party module tests with helpful messages. +Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' +if (dbc.themes.MINTY != Minty_URL): + print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) + print("You will need to update dash bootstrap components hash value.\n") + +FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" +if (dbc.icons.FONT_AWESOME != FontAwesome_URL): + print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) + print("You will need to update the FontAwesome bootstrap components hash value.\n") + + THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From 6266fb6b62aa267a1036ee42b320621908615785 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 23:21:59 -0400 Subject: [PATCH 093/327] Adding explicit cuda call. --- servermanagement/AddWOtoVENV.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 9428da35c..eddaecc62 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -42,6 +42,15 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt +# If we plan to use a GPU then this line must also +# be run. Comment out the code below if you do +# not want cuda installed or edit it for your +# library version. +echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" +echo -e "\n Using CUDA v. 117" +cd .. +"$PIP_CMD" install spacy[cuda117] + echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From e0d38fae2186b26cad68a7a278dec1e7b1b9cbed Mon Sep 17 00:00:00 2001 From: "Collin F. Lynch" Date: Fri, 17 Mar 2023 01:27:59 -0400 Subject: [PATCH 094/327] Updating Add script to deal with 12x bug on spacy install. --- servermanagement/AddWOtoVENV.sh | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index eddaecc62..2755ed69e 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -36,21 +36,34 @@ source "$VIRTUAL_ENV/bin/activate" # Installation # ---------------------------------------------------------- - -# Install basic requirements. -echo -e "\n=== Installing Requirements.txt ===" -cd .. -"$PIP_CMD" install -r requirements.txt - # If we plan to use a GPU then this line must also # be run. Comment out the code below if you do # not want cuda installed or edit it for your # library version. +# +# Note that by default we seem to be unable to rely +# on spacy to pull the right cuda on its own echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" echo -e "\n Using CUDA v. 117" -cd .. "$PIP_CMD" install spacy[cuda117] +# If you are using cuda 12.1 as we are on some +# systems then spacy's passthrough install will +# not work. Therefore you will need a two-step +# process. +#echo -e "\n Using CUDA v. 12.x" +#"$PIP_CMD" install cupy-cuda12x +#"$PIP_CMD" install spacy[cuda12x] + + +# Install basic requirements. +echo -e "\n=== Installing Requirements.txt ===" +cd .. +"$PIP_CMD" install -r requirements.txt + + + + echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From 160df286ae0216cd72aad077d2fbadfdea859ae9 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 24 May 2023 12:31:58 -0400 Subject: [PATCH 095/327] Rebasing from master and adding module updates. --- .../wo_highlight_dashboard/module.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index 4a4008990..cbf8b1f8e 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,18 +23,6 @@ } ] -# Third party module tests with helpful messages. -Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' -if (dbc.themes.MINTY != Minty_URL): - print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) - print("You will need to update dash bootstrap components hash value.\n") - -FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" -if (dbc.icons.FONT_AWESOME != FontAwesome_URL): - print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) - print("You will need to update the FontAwesome bootstrap components hash value.\n") - - THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From 61212b4b9fdb6fbee4b01117634b4b60a4a66dd4 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 096/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 5fba8041d..a3d0c5d1f 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh @@ -30,9 +29,10 @@ echo $LOG_NAME; echo "Running Learning Observer Service..." cd $LEARNING_OBSERVER_LOC source $VIRTUALENV_PATH/bin/activate -#$($VIRTUALENV_PYTHON $LEARNING_OBSERVER_LOC > $LOG_NAME 2>&1) + nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid + # Set the number of allowed open files to something large 8192 prlimit --pid $PROCESS_ID --nofile=8192 From 0f4262e07db0bf68547394a2e550d30d49ac9a4e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:28:57 -0500 Subject: [PATCH 097/327] Adding initialization scripts. --- servermanagement/AddWOtoVENV.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 2755ed69e..bf37b3034 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -61,9 +61,6 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt - - - echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From 961d9ac03d5a7b7930b2421bf100c2d6b628e734 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 098/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 185739208df7db509f114378104b728e664d5691 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:09:42 -0500 Subject: [PATCH 099/327] Adding in error catch for cases where student has no last document which can arise when they have not logged in or data may have been purged. --- modules/writing_observer/writing_observer/aggregator.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 9e7294eeb..8e2e950ce 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -190,6 +190,8 @@ async def get_latest_student_documents(student_data): kvs_data = await kvs.multiget(keys=document_keys) + #print(">> WRITING DATA", writing_data) + # Return blank entries if no data, rather than None. This makes it possible # to use item.get with defaults sanely. For the sake of later alignment # we also zip up the items with the keys and users that they come from @@ -407,9 +409,6 @@ async def latest_data(runtime, student_data, options=None): # if annotated_text != "Error": # single_doc.update(annotated_text) - writing_data = await merge_with_student_data(writing_data, student_data) - writing_data = await processor(writing_data, options) - writing_data = await merge_with_student_data(writing_data, student_data) writing_data = await processor(writing_data, options) From 40639e8dc72378a4b54311b299eb61e76216e495 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 100/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- modules/writing_observer/writing_observer/aggregator.py | 2 +- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 00ee86f7b..e054cf75a 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 8e2e950ce..ba3f5c8b5 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -190,7 +190,7 @@ async def get_latest_student_documents(student_data): kvs_data = await kvs.multiget(keys=document_keys) - #print(">> WRITING DATA", writing_data) + print(">> WRITING DATA", writing_data) # Return blank entries if no data, rather than None. This makes it possible # to use item.get with defaults sanely. For the sake of later alignment From f273a8c868e89236d22be1e8102acd83144596f0 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 18 Dec 2022 22:12:19 -0500 Subject: [PATCH 101/327] Adding updates to deal with data alignment problem. --- modules/writing_observer/writing_observer/aggregator.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index ba3f5c8b5..c3317ce6e 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -176,7 +176,6 @@ async def get_latest_student_documents(student_data): # Compile a list of the active students. active_students = [s for s in student_data if 'writing_observer.writing_analysis.last_document' in s] - # Now collect documents for all of the active students. document_keys = ([ learning_observer.stream_analytics.helpers.make_key( @@ -190,7 +189,7 @@ async def get_latest_student_documents(student_data): kvs_data = await kvs.multiget(keys=document_keys) - print(">> WRITING DATA", writing_data) + print(">> WRITING DATA: KVS Data", kvs_data) # Return blank entries if no data, rather than None. This makes it possible # to use item.get with defaults sanely. For the sake of later alignment @@ -379,6 +378,8 @@ async def latest_data(runtime, student_data, options=None): # single_doc.update(annotated_text) :return: The latest writing data. ''' + print(">>>> PRINT WRITE DATA: Incoming Student") + print(student_data) # HACK we have a cache downstream that relies on redis_ephemeral being setup # when that is resolved, we can remove the feature flag From 4b5a6d00d78dc5873cbdf65c8a1e1a8c545d6f9c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 102/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- modules/writing_observer/writing_observer/aggregator.py | 1 - 5 files changed, 13 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index e054cf75a..8a8a3c5b4 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index c3317ce6e..d364070c1 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -189,7 +189,6 @@ async def get_latest_student_documents(student_data): kvs_data = await kvs.multiget(keys=document_keys) - print(">> WRITING DATA: KVS Data", kvs_data) # Return blank entries if no data, rather than None. This makes it possible # to use item.get with defaults sanely. For the sake of later alignment From 3facc7bd3e02ccce49904b6b0505cdca20d435a3 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 103/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 8 ++ 2 files changed, 96 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 3c4cdb431..a31753665 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -358,6 +359,13 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = writing_observer.event_wrapper.get_doc_id(event) + + print(">>> last_doc_call docid: ", document_id) + if document_id is not None: state = {"document_id": document_id} return state, state From 032911503ff1a1f6f035d0d25c1098bb857088b4 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 104/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- .../writing_observer/writing_analysis.py | 9 +++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index a31753665..27a7afa5d 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -359,12 +359,11 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call: ", event) - - #document_id = event.get('client', {}).get('doc_id', None) + # Initially this code looked only for cases where the document + # id was specified by a doc_id field. This fix uses the event + # wrapper methods to support access of IDs located in the + # doc_id field or in the 'object' field. document_id = writing_observer.event_wrapper.get_doc_id(event) - - print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From aa2bfce9b317f7e2eec29dfc501c62d8417132d9 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:07 -0500 Subject: [PATCH 105/327] Removing some unnecessary info. --- .../incoming_student_event.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/learning_observer/learning_observer/incoming_student_event.py b/learning_observer/learning_observer/incoming_student_event.py index 53479bbd6..f2393e899 100644 --- a/learning_observer/learning_observer/incoming_student_event.py +++ b/learning_observer/learning_observer/incoming_student_event.py @@ -383,6 +383,7 @@ async def update_event_handler(event): if not authenticated: return False +<<<<<<< HEAD nonlocal event_handler, reducers_last_updated if 'source' in lock_fields: debug_log('Updating the event_handler()') @@ -398,6 +399,33 @@ async def handle_auth_events(events): '''This method checks a single method for auth and updates our `lock_fields`. If we are unauthenticated, an error will be thrown and we ignore it. +======= + # We're now ready to make the pipeline. + hostname = socket.gethostname() + decoder_and_logger = event_decoder_and_logger( + request, + headers=header_events, + metadata={ + 'ip': request.remote, + 'host': request.headers.get('Host', ''), + 'user_agent': request.headers.get('User-Agent', ''), + 'x_real_ip': request.headers.get('X-Real-IP', ''), + 'timestamp': datetime.datetime.utcnow().isoformat(), + 'session_count': COUNT, + 'pid': os.getpid(), + 'hostname': hostname, + 'hostip': socket.gethostbyname(hostname), + 'referer': request.headers.get('Referer', ''), + 'host': request.headers.get('Host', ''), + 'x-forwarded-for': request.headers.get('X-Forwarded-For', ''), + 'x-forwarded-host': request.headers.get('X-Forwarded-Host', '') + }, + session={ + 'student': event_metadata['auth']['safe_user_id'], + 'source': event_metadata['source'] + } + ) +>>>>>>> 20bc1b61 (Removing some unnecessary info.) HACK The auth method expects a list of events to find specific auth events. Since we are yielding event by From 98c3c452d1653ddb4414c9d2f793477eb1a40631 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 106/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From d503dde627cf39dbfa187bf3dc3831aabdc8d255 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:39:13 -0500 Subject: [PATCH 107/327] Updating writing analysis to better deal with event types. --- .../writing_observer/writing_analysis.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 27a7afa5d..8a069b815 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -359,11 +359,12 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) - # Initially this code looked only for cases where the document - # id was specified by a doc_id field. This fix uses the event - # wrapper methods to support access of IDs located in the - # doc_id field or in the 'object' field. - document_id = writing_observer.event_wrapper.get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = get_doc_id_wrapper(event) + + print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From b51dd661870c64acab0cb6cdea638ac70ca964ca Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 108/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From d2060c8fe287c1a07dcd53d9d2e86c5900a678f2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:52 -0500 Subject: [PATCH 109/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 8a069b815..83f4ddf5d 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -361,7 +361,6 @@ async def last_document(event, internal_state): print(">>> last_doc_call: ", event) - #document_id = event.get('client', {}).get('doc_id', None) document_id = get_doc_id_wrapper(event) print(">>> last_doc_call docid: ", document_id) From 61895578e025a4105975f2a58d7ac27fb9415888 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 110/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index a3d0c5d1f..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh @@ -29,7 +30,6 @@ echo $LOG_NAME; echo "Running Learning Observer Service..." cd $LEARNING_OBSERVER_LOC source $VIRTUALENV_PATH/bin/activate - nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid From 379bb73c9dc52c686f20266d187748fff7fd181b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 111/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 83f4ddf5d..bc8cd6fc2 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 4766c2201cc9e795fe96e9d4115ec38a99c5e91b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:31:41 -0500 Subject: [PATCH 112/327] Updating documentation with additional local note files which will be updated as we deploy. --- docs/ncsu_setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ncsu_setup.md b/docs/ncsu_setup.md index 79725bccd..c97fd5bf9 100644 --- a/docs/ncsu_setup.md +++ b/docs/ncsu_setup.md @@ -4,7 +4,7 @@ Currently the system is set for use with RHEL 8 on the NCSU systems. We are running with Python 3.9 and connected to the AWEWorkbench code. This assumes that we are also installing it into a vm with those tools installed as packages. An installation script has been added to the servermanagement directory. -Ihnstallation on RHEL 8 requires: +Installation on RHEL 8 requires: - python 3.9 or 3.10 (39 still default). - redis.x86_64 5.0.3-5.module+el8.4.0+12927+b9845322 @rhel-8-for-x86_64-appstream-rpms From 9022e96209ce4fad21237495f8d54b08e3c91a34 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 113/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 20c59665a3e6be581e4da51a4ea49b90baf96aa5 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 114/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/dashboard.py | 2 ++ learning_observer/learning_observer/rosters.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 8a8a3c5b4..3456de378 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -171,7 +171,6 @@ def adjust_external_gc_ids(resp_json): # Pull the actual profile data. student_profile = student_json['profile'] - # Calculate the new ID to use for our student. google_id = auth.google_id_to_user_id(student_profile['id']) From 65aeef466182c956db2be1f5b08c3e60a89ee033 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 115/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/dashboard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 359fb4f67386b3d9d323fa48b208cc76e57a7e5e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 22 Dec 2022 00:18:23 -0500 Subject: [PATCH 116/327] Updating doc branch. --- .../incoming_student_event.py | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/learning_observer/learning_observer/incoming_student_event.py b/learning_observer/learning_observer/incoming_student_event.py index f2393e899..53479bbd6 100644 --- a/learning_observer/learning_observer/incoming_student_event.py +++ b/learning_observer/learning_observer/incoming_student_event.py @@ -383,7 +383,6 @@ async def update_event_handler(event): if not authenticated: return False -<<<<<<< HEAD nonlocal event_handler, reducers_last_updated if 'source' in lock_fields: debug_log('Updating the event_handler()') @@ -399,33 +398,6 @@ async def handle_auth_events(events): '''This method checks a single method for auth and updates our `lock_fields`. If we are unauthenticated, an error will be thrown and we ignore it. -======= - # We're now ready to make the pipeline. - hostname = socket.gethostname() - decoder_and_logger = event_decoder_and_logger( - request, - headers=header_events, - metadata={ - 'ip': request.remote, - 'host': request.headers.get('Host', ''), - 'user_agent': request.headers.get('User-Agent', ''), - 'x_real_ip': request.headers.get('X-Real-IP', ''), - 'timestamp': datetime.datetime.utcnow().isoformat(), - 'session_count': COUNT, - 'pid': os.getpid(), - 'hostname': hostname, - 'hostip': socket.gethostbyname(hostname), - 'referer': request.headers.get('Referer', ''), - 'host': request.headers.get('Host', ''), - 'x-forwarded-for': request.headers.get('X-Forwarded-For', ''), - 'x-forwarded-host': request.headers.get('X-Forwarded-Host', '') - }, - session={ - 'student': event_metadata['auth']['safe_user_id'], - 'source': event_metadata['source'] - } - ) ->>>>>>> 20bc1b61 (Removing some unnecessary info.) HACK The auth method expects a list of events to find specific auth events. Since we are yielding event by From 17edb0578496d77b96474c6b5f61900b56114f3f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 117/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index bc8cd6fc2..83f4ddf5d 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 6fc9660a0d3c45c5e636bd83e6216641723e543c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 118/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From d290dc32daf44570cc34598b1c3988f06fffd05c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 119/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From fe3402359b7c559eb5a8cd9dd45cb06995f78abd Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 120/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 61390bd2209ccde71085b700ab6d714cb880d762 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 121/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 3778d9cd24f1e331ea2f29564db46a59576701ca Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 122/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 83f4ddf5d..bc8cd6fc2 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 68c52d9b93314200135c5542cd897a0ecb0b165f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 00:15:11 -0500 Subject: [PATCH 123/327] Minor cleaning. --- modules/writing_observer/writing_observer/writing_analysis.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index bc8cd6fc2..08cd31018 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -358,12 +358,8 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call: ", event) - document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call docid: ", document_id) - if document_id is not None: state = {"document_id": document_id} return state, state From bc792f89c6ad64aa47e7ceaa1a6a318ed60285d3 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 124/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 3456de378..ff13909f9 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 9f995928866d5986a0e13ee822bd83b9dae3e54a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 14:01:45 -0400 Subject: [PATCH 125/327] Making minor fix in module loading for new libraries. --- .../wo_highlight_dashboard/module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index cbf8b1f8e..4a4008990 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,6 +23,18 @@ } ] +# Third party module tests with helpful messages. +Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' +if (dbc.themes.MINTY != Minty_URL): + print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) + print("You will need to update dash bootstrap components hash value.\n") + +FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" +if (dbc.icons.FONT_AWESOME != FontAwesome_URL): + print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) + print("You will need to update the FontAwesome bootstrap components hash value.\n") + + THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From c0107fbd9601896eef0298de4bbfdf8cd96a1e4e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 23:21:59 -0400 Subject: [PATCH 126/327] Adding explicit cuda call. --- servermanagement/AddWOtoVENV.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index bf37b3034..32de12080 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -61,6 +61,15 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt +# If we plan to use a GPU then this line must also +# be run. Comment out the code below if you do +# not want cuda installed or edit it for your +# library version. +echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" +echo -e "\n Using CUDA v. 117" +cd .. +"$PIP_CMD" install spacy[cuda117] + echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From 53cb30dc6fb65e74bc7d196cc060d85397a08b4e Mon Sep 17 00:00:00 2001 From: "Collin F. Lynch" Date: Fri, 17 Mar 2023 01:27:59 -0400 Subject: [PATCH 127/327] Updating Add script to deal with 12x bug on spacy install. --- servermanagement/AddWOtoVENV.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 32de12080..2755ed69e 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -61,14 +61,8 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt -# If we plan to use a GPU then this line must also -# be run. Comment out the code below if you do -# not want cuda installed or edit it for your -# library version. -echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" -echo -e "\n Using CUDA v. 117" -cd .. -"$PIP_CMD" install spacy[cuda117] + + echo -e "\n=== Installing Learning Observer ===" cd learning_observer From ea11dd7f8ca9098c109978281797e2c27f28bb1d Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 25 May 2023 22:56:21 -0400 Subject: [PATCH 128/327] Cleaning up minor differences after rebase. --- .../wo_highlight_dashboard/dashboard/students.py | 1 - modules/writing_observer/writing_observer/aggregator.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index fa798188c..0aa405fce 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,7 +120,6 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ - settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index d364070c1..01ef71769 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -15,7 +15,6 @@ import learning_observer.settings from learning_observer.stream_analytics.fields import KeyField, KeyStateType, EventField import learning_observer.stream_analytics.helpers -# import traceback import learning_observer.util pmss.register_field( @@ -411,7 +410,6 @@ async def latest_data(runtime, student_data, options=None): writing_data = await merge_with_student_data(writing_data, student_data) writing_data = await processor(writing_data, options) - return {'latest_writing_data': writing_data} From 24e8956b70e472892978f5f6e19c45fd1e32a868 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 129/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 6859e0f8d164de278b8592b938c7d5cd9ca6bdee Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sat, 3 Dec 2022 13:32:15 -0500 Subject: [PATCH 130/327] Updating documentation on installation scripts. --- docs/ncsu_setup.md | 4 ++++ servermanagement/SetupVENV.sh | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/ncsu_setup.md b/docs/ncsu_setup.md index c97fd5bf9..35f892478 100644 --- a/docs/ncsu_setup.md +++ b/docs/ncsu_setup.md @@ -4,7 +4,11 @@ Currently the system is set for use with RHEL 8 on the NCSU systems. We are running with Python 3.9 and connected to the AWEWorkbench code. This assumes that we are also installing it into a vm with those tools installed as packages. An installation script has been added to the servermanagement directory. +<<<<<<< HEAD Installation on RHEL 8 requires: +======= +Ihnstallation on RHEL 8 requires: +>>>>>>> 292f3ef (Updating documentation on installation scripts.) - python 3.9 or 3.10 (39 still default). - redis.x86_64 5.0.3-5.module+el8.4.0+12927+b9845322 @rhel-8-for-x86_64-appstream-rpms diff --git a/servermanagement/SetupVENV.sh b/servermanagement/SetupVENV.sh index 14e9c8b51..0483b0c1d 100755 --- a/servermanagement/SetupVENV.sh +++ b/servermanagement/SetupVENV.sh @@ -30,7 +30,6 @@ VIRTUAL_ENV_LOC=$2 PYTHON_CMD="python3.9" PIP_CMD="pip" - # Execution # --------------------------------------------------------- echo "1) Generating VENV" From 381bd2a223f488e928e427856fbf04d140ae1b6c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:28:57 -0500 Subject: [PATCH 131/327] Adding initialization scripts. --- servermanagement/AddWOtoVENV.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 2755ed69e..4f81e274e 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -28,7 +28,6 @@ PIP_CMD="pip" CODE_REPOS_LOC="../../" - # Activate VENV # --------------------------------------------------------- source "$VIRTUAL_ENV/bin/activate" @@ -61,9 +60,6 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt - - - echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop @@ -75,6 +71,6 @@ cd ../modules/writing_observer echo -e "\n=== Installing Brad's Dashboard ===" -cd ../wo_highlight_dashboard +cd ../../learning_observer/prototypes/dash_wo_teacher_dashboard "$PYTHON_CMD" setup.py develop From 2f92d3c99bbc4145e248f8bcc3025c14dcfe144a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 132/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From d15f3258eb5fa01594551915ad05f4d2b8656416 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:09:42 -0500 Subject: [PATCH 133/327] Adding in error catch for cases where student has no last document which can arise when they have not logged in or data may have been purged. --- .../writing_observer/aggregator.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 01ef71769..19e480df2 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -409,7 +409,25 @@ async def latest_data(runtime, student_data, options=None): # single_doc.update(annotated_text) writing_data = await merge_with_student_data(writing_data, student_data) - writing_data = await processor(writing_data, options) + + #print(">>>> PRINT WRITE DATA.") + #print(writing_data) + + just_the_text = [w.get("text", "") for w in writing_data] + + #print(">>>> PRINT just.") + #print(just_the_text) + + annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) + + #print(">>>> PRINT ANN TXT.") + #print(annotated_texts) + + + for annotated_text, single_doc in zip(annotated_texts, writing_data): + if annotated_text != "Error": + single_doc.update(annotated_text) + # Call Paul's code to add stuff to it return {'latest_writing_data': writing_data} From b5cc02e13f0bfa1bf33ed88fbadb87a5c712e65a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 134/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- .../learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- .../writing_observer/writing_observer/aggregator.py | 12 ++++++------ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index ff13909f9..9df77d60e 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 19e480df2..bafd78a79 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -410,18 +410,18 @@ async def latest_data(runtime, student_data, options=None): writing_data = await merge_with_student_data(writing_data, student_data) - #print(">>>> PRINT WRITE DATA.") - #print(writing_data) + print(">>>> PRINT WRITE DATA: Merge") + print(writing_data) just_the_text = [w.get("text", "") for w in writing_data] - #print(">>>> PRINT just.") - #print(just_the_text) + print(">>>> PRINT just.") + print(just_the_text) annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) - #print(">>>> PRINT ANN TXT.") - #print(annotated_texts) + print(">>>> PRINT ANN TXT.") + print(annotated_texts) for annotated_text, single_doc in zip(annotated_texts, writing_data): From b2e6e7736ff505b88c0370ec5b83970bb3702d29 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 18 Dec 2022 22:12:19 -0500 Subject: [PATCH 135/327] Adding updates to deal with data alignment problem. --- modules/writing_observer/writing_observer/aggregator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index bafd78a79..675fddf89 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -410,8 +410,8 @@ async def latest_data(runtime, student_data, options=None): writing_data = await merge_with_student_data(writing_data, student_data) - print(">>>> PRINT WRITE DATA: Merge") - print(writing_data) + #print(">>>> PRINT WRITE DATA: Merge") + #print(writing_data) just_the_text = [w.get("text", "") for w in writing_data] @@ -422,12 +422,12 @@ async def latest_data(runtime, student_data, options=None): print(">>>> PRINT ANN TXT.") print(annotated_texts) - for annotated_text, single_doc in zip(annotated_texts, writing_data): if annotated_text != "Error": single_doc.update(annotated_text) # Call Paul's code to add stuff to it + print(">>>>> Final Data: ", writing_data) return {'latest_writing_data': writing_data} From 730679d0e77083916954c3df9a93787510287f59 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 136/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- modules/writing_observer/writing_observer/aggregator.py | 8 +------- 5 files changed, 1 insertion(+), 19 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 9df77d60e..3456de378 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 675fddf89..203507350 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -415,19 +415,13 @@ async def latest_data(runtime, student_data, options=None): just_the_text = [w.get("text", "") for w in writing_data] - print(">>>> PRINT just.") - print(just_the_text) - annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) - print(">>>> PRINT ANN TXT.") - print(annotated_texts) - for annotated_text, single_doc in zip(annotated_texts, writing_data): if annotated_text != "Error": single_doc.update(annotated_text) # Call Paul's code to add stuff to it - print(">>>>> Final Data: ", writing_data) + return {'latest_writing_data': writing_data} From 22540423eac5ff8bdfbe01a059f4671c4a50015e Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 23 Dec 2022 11:24:37 -0500 Subject: [PATCH 137/327] Add settings to dropdown menu --- .../wo_highlight_dashboard/dashboard/students.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index 0aa405fce..fa798188c 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,6 +120,7 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ + settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn From d7e897b4c3db6c3082020b7796b7e7dd69e5824c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 138/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 5 +- 2 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 08cd31018..2dfd16f7f 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -356,10 +357,6 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - document_id = get_doc_id_wrapper(event) - - document_id = get_doc_id_wrapper(event) - if document_id is not None: state = {"document_id": document_id} return state, state From f3ff569b2f3df0ac7c49f39570e65452725ff365 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 139/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From aacb04701bb3f164f513029e148c795ee997c64e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 140/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 07fe53021dbdf3ac8a99d3dfac41056f1a146ca3 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 141/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 5af92af76ac7b7568973dd0e80b589b3a739838e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 142/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From ceb3957c1eecd12ff9dffdf4e85607f20d6edcd0 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 143/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 2dfd16f7f..67735bd04 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 32c4acd79fb31e4f70419bb2e3262f9e3b2c538d Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 144/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From ec2039a2594b9f9002e3120472509b0221e0b81f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 145/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/dashboard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 90e030bcba32d11f00a792707d87be31b4dda807 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 146/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/dashboard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 2075b4e5d84804494f41d1e9808227494a738b2b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 147/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 67735bd04..2dfd16f7f 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 17770032ebcd7a5401032d426c5720f94c2aaefa Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 148/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From 1559c94c6cbdea2006053b5026a0df108f8c0cf5 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 149/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From f1277251949df0e17e8b11fc4b0384460d09c689 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 150/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From fe75022f78822a614ec7cffbf2c7ecf7f565d9cd Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 151/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 4391a9a049065109db140c02d6de6d0c20ff4e88 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 152/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 2dfd16f7f..67735bd04 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From e1e99d6af0b7a1a939ed9b92c3cd685191c78625 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 153/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 3456de378..ff13909f9 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From f98dce219eb74a674085c17ac0122b2849882161 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Tue, 7 Mar 2023 15:36:24 -0500 Subject: [PATCH 154/327] Fixing basic error in aggregator. --- .../writing_observer/writing_observer/aggregator.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 203507350..24158149a 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -410,18 +410,22 @@ async def latest_data(runtime, student_data, options=None): writing_data = await merge_with_student_data(writing_data, student_data) - #print(">>>> PRINT WRITE DATA: Merge") - #print(writing_data) + + # #print(">>>> PRINT WRITE DATA: Merge") + # #print(writing_data) - just_the_text = [w.get("text", "") for w in writing_data] + # just_the_text = [w.get("text", "") for w in writing_data] - annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) + # annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) for annotated_text, single_doc in zip(annotated_texts, writing_data): if annotated_text != "Error": single_doc.update(annotated_text) # Call Paul's code to add stuff to it + writing_data = await merge_with_student_data(writing_data, student_data) + writing_data = await processor(writing_data, options) + return {'latest_writing_data': writing_data} From 52ad6cda296233cab2e35b4b95759ff8165e7d14 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Tue, 7 Mar 2023 15:36:59 -0500 Subject: [PATCH 155/327] Fixing new dashboard structure. --- servermanagement/AddWOtoVENV.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 4f81e274e..2556b2a84 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -71,6 +71,6 @@ cd ../modules/writing_observer echo -e "\n=== Installing Brad's Dashboard ===" -cd ../../learning_observer/prototypes/dash_wo_teacher_dashboard +cd ../wo_highlight_dashboard "$PYTHON_CMD" setup.py develop From b0665fb029850d138fe577cc95a626c4ca2cd3f2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 23:21:59 -0400 Subject: [PATCH 156/327] Adding explicit cuda call. --- servermanagement/AddWOtoVENV.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 2556b2a84..222ce708a 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,6 +60,15 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt +# If we plan to use a GPU then this line must also +# be run. Comment out the code below if you do +# not want cuda installed or edit it for your +# library version. +echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" +echo -e "\n Using CUDA v. 117" +cd .. +"$PIP_CMD" install spacy[cuda117] + echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From a0190f571ebf99986e84033987ef30356e930d9f Mon Sep 17 00:00:00 2001 From: "Collin F. Lynch" Date: Fri, 17 Mar 2023 01:27:59 -0400 Subject: [PATCH 157/327] Updating Add script to deal with 12x bug on spacy install. --- servermanagement/AddWOtoVENV.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 222ce708a..a99cc4ac0 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,14 +60,8 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt -# If we plan to use a GPU then this line must also -# be run. Comment out the code below if you do -# not want cuda installed or edit it for your -# library version. -echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" -echo -e "\n Using CUDA v. 117" -cd .. -"$PIP_CMD" install spacy[cuda117] + + echo -e "\n=== Installing Learning Observer ===" cd learning_observer From f3daae598a122c3f9afb2b870b3b0d3164b0044f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 24 May 2023 12:31:58 -0400 Subject: [PATCH 158/327] Rebasing from master and adding module updates. --- .../wo_highlight_dashboard/module.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index 4a4008990..cbf8b1f8e 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,18 +23,6 @@ } ] -# Third party module tests with helpful messages. -Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' -if (dbc.themes.MINTY != Minty_URL): - print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) - print("You will need to update dash bootstrap components hash value.\n") - -FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" -if (dbc.icons.FONT_AWESOME != FontAwesome_URL): - print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) - print("You will need to update the FontAwesome bootstrap components hash value.\n") - - THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From f3b9506008f477814032b13e915b01cc2d8ba611 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:31:41 -0500 Subject: [PATCH 159/327] Updating documentation with additional local note files which will be updated as we deploy. --- docs/ncsu_setup.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/ncsu_setup.md b/docs/ncsu_setup.md index 35f892478..c97fd5bf9 100644 --- a/docs/ncsu_setup.md +++ b/docs/ncsu_setup.md @@ -4,11 +4,7 @@ Currently the system is set for use with RHEL 8 on the NCSU systems. We are running with Python 3.9 and connected to the AWEWorkbench code. This assumes that we are also installing it into a vm with those tools installed as packages. An installation script has been added to the servermanagement directory. -<<<<<<< HEAD Installation on RHEL 8 requires: -======= -Ihnstallation on RHEL 8 requires: ->>>>>>> 292f3ef (Updating documentation on installation scripts.) - python 3.9 or 3.10 (39 still default). - redis.x86_64 5.0.3-5.module+el8.4.0+12927+b9845322 @rhel-8-for-x86_64-appstream-rpms From 7f7e26fdc86c2fe89caa9b65d16f69579e75269a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 160/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 145560442730840cbb7368c77991b6179ea59c0e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:28:57 -0500 Subject: [PATCH 161/327] Adding initialization scripts. --- servermanagement/AddWOtoVENV.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index a99cc4ac0..2556b2a84 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,9 +60,6 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt - - - echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From d2db996d519fd617c998b010f388c2e0f3263fd8 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 162/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From b1fb73c18ae1a2bf82bf03fcc8aa61bca4f9b407 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 163/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- modules/writing_observer/writing_observer/aggregator.py | 6 ++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index ff13909f9..9df77d60e 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 24158149a..50e57a66c 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -208,6 +208,9 @@ async def get_latest_student_documents(student_data): doc['student'] = student writing_data.append(doc) + print("WRITING DATA >>>>") + print(writing_data) + return writing_data @@ -227,6 +230,9 @@ async def merge_with_student_data(writing_data, student_data): Add the student metadata to each text ''' + print("!!!! WRITE: ", writing_data) + print("!!!! STUDENT: ", student_data) + for item, student in zip(writing_data, student_data): if 'edit_metadata' in item: del item['edit_metadata'] From 06f8a632585364feae151d049f2d924301c4f126 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 18 Dec 2022 22:12:19 -0500 Subject: [PATCH 164/327] Adding updates to deal with data alignment problem. --- modules/writing_observer/writing_observer/aggregator.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 50e57a66c..5d582e2ee 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -208,7 +208,11 @@ async def get_latest_student_documents(student_data): doc['student'] = student writing_data.append(doc) - print("WRITING DATA >>>>") + # Now insert the student data and pass it along. + doc['student'] = student + writing_data.append(doc) + + print(">>>> Writing Data: LATEST STUDENT DOCS") print(writing_data) return writing_data From 8cec8d24bae4a0d56c8978984a4399761aac92e3 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 165/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- modules/writing_observer/writing_observer/aggregator.py | 4 ---- 5 files changed, 16 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 9df77d60e..3456de378 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 5d582e2ee..7c406e6b2 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -212,7 +212,6 @@ async def get_latest_student_documents(student_data): doc['student'] = student writing_data.append(doc) - print(">>>> Writing Data: LATEST STUDENT DOCS") print(writing_data) return writing_data @@ -234,9 +233,6 @@ async def merge_with_student_data(writing_data, student_data): Add the student metadata to each text ''' - print("!!!! WRITE: ", writing_data) - print("!!!! STUDENT: ", student_data) - for item, student in zip(writing_data, student_data): if 'edit_metadata' in item: del item['edit_metadata'] From fecea6cba54b12260e03e062f9e3477eb609e434 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 166/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 8 ++ 2 files changed, 96 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 67735bd04..584108ae4 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -356,6 +357,13 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = writing_observer.event_wrapper.get_doc_id(event) + + print(">>> last_doc_call docid: ", document_id) + if document_id is not None: state = {"document_id": document_id} return state, state From 926ad16a7a00dd784f110827d549b0445c4589ae Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 167/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- .../writing_observer/writing_analysis.py | 9 +++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 584108ae4..d98dfe67e 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -357,12 +357,11 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - print(">>> last_doc_call: ", event) - - #document_id = event.get('client', {}).get('doc_id', None) + # Initially this code looked only for cases where the document + # id was specified by a doc_id field. This fix uses the event + # wrapper methods to support access of IDs located in the + # doc_id field or in the 'object' field. document_id = writing_observer.event_wrapper.get_doc_id(event) - - print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From afb9f406fc87c0302caf8e1f2ebf8757366091d0 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 168/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From c3f28ec94f45954e55bd6787cce31f0db27537a7 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:39:13 -0500 Subject: [PATCH 169/327] Updating writing analysis to better deal with event types. --- .../writing_observer/writing_analysis.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index d98dfe67e..d03d1712b 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -357,11 +357,12 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - # Initially this code looked only for cases where the document - # id was specified by a doc_id field. This fix uses the event - # wrapper methods to support access of IDs located in the - # doc_id field or in the 'object' field. - document_id = writing_observer.event_wrapper.get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = get_doc_id_wrapper(event) + + print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From a28943fdd03e91c2d44aa07535c9b3d38db7dfe1 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 170/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From c10ae3593af332c5e72bc8307ec0d264bbd74f95 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:52 -0500 Subject: [PATCH 171/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index d03d1712b..7b4d2868e 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -359,7 +359,6 @@ async def last_document(event, internal_state): print(">>> last_doc_call: ", event) - #document_id = event.get('client', {}).get('doc_id', None) document_id = get_doc_id_wrapper(event) print(">>> last_doc_call docid: ", document_id) From 5a4b1811d34724fabc46738e461ebf79920b2d2b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 172/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 093e5236a7ebd81189d6e66a87a57e6131c69453 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 173/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 7b4d2868e..41bd104c6 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From e52b1091a897776bcbcf0076ab0d8a99f4c9ca45 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 27 Jan 2023 10:06:06 -0500 Subject: [PATCH 174/327] Migrate extension from v2 to v3 --- extension/extension/inject.js | 13 +++++++++++++ extension/extension/service_worker.js | 8 ++++++++ extension/writing-process/src/writing.js | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 extension/extension/inject.js create mode 100644 extension/extension/service_worker.js diff --git a/extension/extension/inject.js b/extension/extension/inject.js new file mode 100644 index 000000000..a22971361 --- /dev/null +++ b/extension/extension/inject.js @@ -0,0 +1,13 @@ +let script = document.createElement('script') +script.id = 'tmpScript' + +const code = "_docs_flag_initialData.info_params.token" +script.textContent = 'document.getElementById("tmpScript").textContent = JSON.stringify(' + code + ')' + +document.documentElement.appendChild(script) + +let result = script.textContent + +window.postMessage({ from: 'inject.js', data: result }) + +script.remove() \ No newline at end of file diff --git a/extension/extension/service_worker.js b/extension/extension/service_worker.js new file mode 100644 index 000000000..2a1c90341 --- /dev/null +++ b/extension/extension/service_worker.js @@ -0,0 +1,8 @@ +// Combining the two background scripts into one to serve +// as a single service worker script + +try { + importScripts( "./writing_common.js", "./background.js"); +} catch (e) { + console.log(e); +} \ No newline at end of file diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index 1e63f9df1..e55021508 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix-page")[0].innerText; + return document.getElementsByClassName("kix")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From f3bc04d6b93d2efcc9f8344ac6f47afe36fe333a Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 10 Feb 2023 09:37:41 -0500 Subject: [PATCH 175/327] Add more code comments/documentation --- extension/extension/inject.js | 9 ++++++++- extension/extension/service_worker.js | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/extension/extension/inject.js b/extension/extension/inject.js index a22971361..4581c03a3 100644 --- a/extension/extension/inject.js +++ b/extension/extension/inject.js @@ -1,3 +1,10 @@ +/* + Inject script. This is a web_accessible_resources used to pass the id + of the document as a globally accessible variable to the extension. + It is called by the injectScript function in writing.js to make the result + accessible using an event listener +*/ + let script = document.createElement('script') script.id = 'tmpScript' @@ -10,4 +17,4 @@ let result = script.textContent window.postMessage({ from: 'inject.js', data: result }) -script.remove() \ No newline at end of file +script.remove() diff --git a/extension/extension/service_worker.js b/extension/extension/service_worker.js index 2a1c90341..1231108dc 100644 --- a/extension/extension/service_worker.js +++ b/extension/extension/service_worker.js @@ -5,4 +5,4 @@ try { importScripts( "./writing_common.js", "./background.js"); } catch (e) { console.log(e); -} \ No newline at end of file +} From 4ad2fec9cce20b00824d050f922a45b04b50ca75 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 176/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From b47843890fdd55339e1f6f2af5802ec242cec7ca Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 177/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/dashboard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 26dc7a7465149781042ccf87a21b3aee0de47abc Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 178/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/dashboard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 4a165315c598d9d504b42cf3b29d3da3c457bb2e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 179/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 41bd104c6..7b4d2868e 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 576ef6a11cd65a8b13cefabc3e60e15e7c13603c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 180/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From 4119b6acab5f3e9d8bc0ad4ba28119e409f69904 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 181/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 746a15621755d7cdd2e5e5afc395d9b3a0aa18a1 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 182/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From cc75cefcca771bee8a20b5fc237db16b53fd08f4 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 183/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From f8845907f9299d2457d5a472c5a73b27c2f89904 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 184/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 7b4d2868e..41bd104c6 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From e58091e4de05863e01555dbb3f41220d0885eab5 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 00:15:11 -0500 Subject: [PATCH 185/327] Minor cleaning. --- modules/writing_observer/writing_observer/writing_analysis.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 41bd104c6..3c4cdb431 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -356,12 +356,8 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - print(">>> last_doc_call: ", event) - document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call docid: ", document_id) - if document_id is not None: state = {"document_id": document_id} return state, state From a4f39e6ce91e97c2531efe845c1ce140362db6cc Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 186/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 3456de378..ff13909f9 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 63c8f23e56aeba0d93532522fad5524046ea6591 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 15 Mar 2023 23:39:41 -0400 Subject: [PATCH 187/327] Minor spacing cleanup. --- extension/extension/service_worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/extension/service_worker.js b/extension/extension/service_worker.js index 1231108dc..138ba9421 100644 --- a/extension/extension/service_worker.js +++ b/extension/extension/service_worker.js @@ -2,7 +2,7 @@ // as a single service worker script try { - importScripts( "./writing_common.js", "./background.js"); + importScripts("./writing_common.js", "./background.js"); } catch (e) { console.log(e); } From 76669dd5c1f9c786bffccb418bac8f3ad621fe5c Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 3 Mar 2023 08:43:46 -0500 Subject: [PATCH 188/327] Fix content script unload/reload --- extension/writing-process/src/writing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index e55021508..1e63f9df1 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix")[0].innerText; + return document.getElementsByClassName("kix-page")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 8e2b087032e2907a2a332313df8061d9dea19c29 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 14:01:45 -0400 Subject: [PATCH 189/327] Making minor fix in module loading for new libraries. --- .../wo_highlight_dashboard/module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index cbf8b1f8e..4a4008990 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,6 +23,18 @@ } ] +# Third party module tests with helpful messages. +Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' +if (dbc.themes.MINTY != Minty_URL): + print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) + print("You will need to update dash bootstrap components hash value.\n") + +FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" +if (dbc.icons.FONT_AWESOME != FontAwesome_URL): + print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) + print("You will need to update the FontAwesome bootstrap components hash value.\n") + + THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From b3424c3c93745b8edc4e4395ea2d31c4d49e25e6 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 23:21:59 -0400 Subject: [PATCH 190/327] Adding explicit cuda call. --- servermanagement/AddWOtoVENV.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 2556b2a84..222ce708a 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,6 +60,15 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt +# If we plan to use a GPU then this line must also +# be run. Comment out the code below if you do +# not want cuda installed or edit it for your +# library version. +echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" +echo -e "\n Using CUDA v. 117" +cd .. +"$PIP_CMD" install spacy[cuda117] + echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From c09ee4d18a26472bd36eddb7e53acb1274cff39f Mon Sep 17 00:00:00 2001 From: "Collin F. Lynch" Date: Fri, 17 Mar 2023 01:27:59 -0400 Subject: [PATCH 191/327] Updating Add script to deal with 12x bug on spacy install. --- servermanagement/AddWOtoVENV.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 222ce708a..a99cc4ac0 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,14 +60,8 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt -# If we plan to use a GPU then this line must also -# be run. Comment out the code below if you do -# not want cuda installed or edit it for your -# library version. -echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" -echo -e "\n Using CUDA v. 117" -cd .. -"$PIP_CMD" install spacy[cuda117] + + echo -e "\n=== Installing Learning Observer ===" cd learning_observer From 21e64aa48806cd93bf6765f0bd954cd7076da48f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 25 May 2023 22:56:21 -0400 Subject: [PATCH 192/327] Cleaning up minor differences after rebase. --- .../dashboard/students.py | 1 - .../writing_observer/aggregator.py | 34 ------------------- 2 files changed, 35 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index fa798188c..0aa405fce 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,7 +120,6 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ - settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 7c406e6b2..5e06519f8 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -396,42 +396,8 @@ async def latest_data(runtime, student_data, options=None): # Strip out the unnecessary extra data. writing_data = await remove_extra_data(writing_data) - - # print(">>> WRITE DATA-premerge: {}".format(writing_data)) - - # This is the error. Skipping now. - writing_data_merge = await merge_with_student_data(writing_data, student_data) - # print(">>> WRITE DATA-postmerge: {}".format(writing_data_merge)) - - # #print(">>>> PRINT WRITE DATA: Merge") - # #print(writing_data) - - # just_the_text = [w.get("text", "") for w in writing_data] - - # annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) - - # for annotated_text, single_doc in zip(annotated_texts, writing_data): - # if annotated_text != "Error": - # single_doc.update(annotated_text) - - writing_data = await merge_with_student_data(writing_data, student_data) - - - # #print(">>>> PRINT WRITE DATA: Merge") - # #print(writing_data) - - # just_the_text = [w.get("text", "") for w in writing_data] - - # annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) - - for annotated_text, single_doc in zip(annotated_texts, writing_data): - if annotated_text != "Error": - single_doc.update(annotated_text) - # Call Paul's code to add stuff to it - writing_data = await merge_with_student_data(writing_data, student_data) writing_data = await processor(writing_data, options) - return {'latest_writing_data': writing_data} From ed76fd02f10d12a11576f566880ceaff3713c3ea Mon Sep 17 00:00:00 2001 From: Sarthak Babbar Date: Thu, 8 Jun 2023 14:46:16 -0400 Subject: [PATCH 193/327] Caching Initial Commit (#80) * Caching Version 0 Initial Commit * Caching Version 0 Initial Commit With Fixes * Caching Version 0 Initial Commit With Fixes * Caching Version 0 Initial Commit With Fixes * Refactoring Caching Code * Modularize Caching function, add helper functions to util.py * Improve modularization and reducing dirty reads. * Renamed functions & variables, added parameter definitions * Reduce gap between cache read and write * Remove blank lines --------- Co-authored-by: Bradley Erickson --- .../writing_observer/aggregator.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 5e06519f8..0d6f6f8c3 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -13,8 +13,8 @@ import learning_observer.constants as constants import learning_observer.kvs import learning_observer.settings -from learning_observer.stream_analytics.fields import KeyField, KeyStateType, EventField import learning_observer.stream_analytics.helpers +# import traceback import learning_observer.util pmss.register_field( @@ -396,8 +396,28 @@ async def latest_data(runtime, student_data, options=None): # Strip out the unnecessary extra data. writing_data = await remove_extra_data(writing_data) + + # print(">>> WRITE DATA-premerge: {}".format(writing_data)) + + # This is the error. Skipping now. + writing_data_merge = await merge_with_student_data(writing_data, student_data) + # print(">>> WRITE DATA-postmerge: {}".format(writing_data_merge)) + + + # #print(">>>> PRINT WRITE DATA: Merge") + # #print(writing_data) + + # just_the_text = [w.get("text", "") for w in writing_data] + + # annotated_texts = await writing_observer.awe_nlp.process_texts_parallel(just_the_text) + + # for annotated_text, single_doc in zip(annotated_texts, writing_data): + # if annotated_text != "Error": + # single_doc.update(annotated_text) + writing_data = await merge_with_student_data(writing_data, student_data) writing_data = await processor(writing_data, options) + return {'latest_writing_data': writing_data} From 0401d8b0a4facb64d4b153f5e08ef8bcac9c6209 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Tue, 27 Jun 2023 22:27:04 -0400 Subject: [PATCH 194/327] Lo components fix (#96) * Adding installation for the lo_dash_react_components module. * Fixing minor error in installation script. * Fixing module structure with additional versions. * Fixing doc ID error. * Fixing student/data merge issues and aggregation for WO. --------- Co-authored-by: DrLynch --- .../wo_highlight_dashboard/module.py | 12 ------- .../writing_observer/aggregator.py | 31 +++++++++++-------- .../writing_observer/writing_analysis.py | 2 -- servermanagement/AddWOtoVENV.sh | 24 ++++++++++---- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index 4a4008990..cbf8b1f8e 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,18 +23,6 @@ } ] -# Third party module tests with helpful messages. -Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' -if (dbc.themes.MINTY != Minty_URL): - print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) - print("You will need to update dash bootstrap components hash value.\n") - -FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" -if (dbc.icons.FONT_AWESOME != FontAwesome_URL): - print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) - print("You will need to update the FontAwesome bootstrap components hash value.\n") - - THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 0d6f6f8c3..530b244bd 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -228,16 +228,19 @@ async def remove_extra_data(writing_data): return writing_data -async def merge_with_student_data(writing_data, student_data): - ''' - Add the student metadata to each text - ''' +# async def merge_with_student_data(writing_data, student_data): +# ''' +# Add the student metadata to each text. Because we may have +# fewer entries in writing_data than student_data we iterate +# over the student_data locating writing data that matches it +# if any. +# ''' - for item, student in zip(writing_data, student_data): - if 'edit_metadata' in item: - del item['edit_metadata'] - item['student'] = student - return writing_data +# for item, student in zip(writing_data, student_data): +# if 'edit_metadata' in item: +# del item['edit_metadata'] +# item['student'] = student +# return writing_data # TODO the use_nlp initialization code ought to live in a @@ -382,8 +385,7 @@ async def latest_data(runtime, student_data, options=None): # single_doc.update(annotated_text) :return: The latest writing data. ''' - print(">>>> PRINT WRITE DATA: Incoming Student") - print(student_data) + debug_log("WritingObserver latest_data students:", student_data) # HACK we have a cache downstream that relies on redis_ephemeral being setup # when that is resolved, we can remove the feature flag @@ -394,7 +396,8 @@ async def latest_data(runtime, student_data, options=None): # Get the latest documents with the students appended. writing_data = await get_latest_student_documents(student_data) - # Strip out the unnecessary extra data. + # Strip out the unnecessary edit_metadata from the merged + # student and writing data. writing_data = await remove_extra_data(writing_data) # print(">>> WRITE DATA-premerge: {}".format(writing_data)) @@ -417,7 +420,9 @@ async def latest_data(runtime, student_data, options=None): writing_data = await merge_with_student_data(writing_data, student_data) writing_data = await processor(writing_data, options) - + + debug_log("WritingObserver latest_data result: ", writing_data) + return {'latest_writing_data': writing_data} diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 3c4cdb431..67735bd04 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -356,8 +356,6 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - document_id = get_doc_id_wrapper(event) - if document_id is not None: state = {"document_id": document_id} return state, state diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index a99cc4ac0..8b345330b 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -61,19 +61,31 @@ cd .. "$PIP_CMD" install -r requirements.txt - - echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop -echo -e "\n=== Installing Writing Observer ===" -cd ../modules/writing_observer +echo -e "\n=== Installing Modules ===" +cd ../modules/ + +echo -e "\n--- Installing Writing Observer ---" +cd ./writing_observer "$PYTHON_CMD" setup.py develop +cd .. +echo -e "\n--- Installing lo_dash_react_components. ---" +cd ./lo_dash_react_components +"$PYTHON_CMD" setup.py develop +pip install . +cd .. -echo -e "\n=== Installing Brad's Dashboard ===" -cd ../wo_highlight_dashboard +echo -e "\n--- Installing wo_highlight_dashboard. ---" +cd ./wo_highlight_dashboard "$PYTHON_CMD" setup.py develop +cd .. + + + + From a39530c7c5db03e3e92aa69bb9ecc10902818da2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 195/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From f9ee6b0bc776bfd710e5a04dd505d90b01661570 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:28:57 -0500 Subject: [PATCH 196/327] Adding initialization scripts. --- servermanagement/AddWOtoVENV.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 8b345330b..da51a93a2 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,7 +60,6 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt - echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From ee1edd2833b4a0a34e6b29c2f7a876b787316dbe Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 197/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 69f044ac039565e05ca51f3d13a039d0df1d882d Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 198/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index ff13909f9..9df77d60e 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json From 53f78423d89c12599401b52c88040b751eb7df8a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 199/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- 4 files changed, 12 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 9df77d60e..3456de378 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json From d4baab2fbfe77ce9dd9735cc8ba39f101e1064dc Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 23 Dec 2022 11:24:37 -0500 Subject: [PATCH 200/327] Add settings to dropdown menu --- .../wo_highlight_dashboard/dashboard/students.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index 0aa405fce..fa798188c 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,6 +120,7 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ + settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn From dddcc94442c9d44a33196dc25229e5133cd53255 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 201/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 8 ++ 2 files changed, 96 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 67735bd04..584108ae4 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -356,6 +357,13 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = writing_observer.event_wrapper.get_doc_id(event) + + print(">>> last_doc_call docid: ", document_id) + if document_id is not None: state = {"document_id": document_id} return state, state From 05795f052d062adff7e6b942b237682c5d47e598 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 202/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- .../writing_observer/writing_analysis.py | 9 +++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 584108ae4..d98dfe67e 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -357,12 +357,11 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - print(">>> last_doc_call: ", event) - - #document_id = event.get('client', {}).get('doc_id', None) + # Initially this code looked only for cases where the document + # id was specified by a doc_id field. This fix uses the event + # wrapper methods to support access of IDs located in the + # doc_id field or in the 'object' field. document_id = writing_observer.event_wrapper.get_doc_id(event) - - print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From 055a81dc50457b10c42308b1a353486374d1e3bc Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 203/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 41ac79223825950b04b2259f8310b29b4a3410f2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:39:13 -0500 Subject: [PATCH 204/327] Updating writing analysis to better deal with event types. --- .../writing_observer/writing_analysis.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index d98dfe67e..d03d1712b 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -357,11 +357,12 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - # Initially this code looked only for cases where the document - # id was specified by a doc_id field. This fix uses the event - # wrapper methods to support access of IDs located in the - # doc_id field or in the 'object' field. - document_id = writing_observer.event_wrapper.get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = get_doc_id_wrapper(event) + + print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From bdda572f9340a9fa166d1d11e64fcf6b87b0f9b2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 205/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From d33a95c51161e5b2385b25ea5ae4772eb01aebda Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:52 -0500 Subject: [PATCH 206/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index d03d1712b..7b4d2868e 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -359,7 +359,6 @@ async def last_document(event, internal_state): print(">>> last_doc_call: ", event) - #document_id = event.get('client', {}).get('doc_id', None) document_id = get_doc_id_wrapper(event) print(">>> last_doc_call docid: ", document_id) From 7601da196fa34e42e1148fe4434be81b7740d769 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 207/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 82b5406b68723665312b48c79a2b4600a39d80b9 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 208/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 7b4d2868e..41bd104c6 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 4ab7e7294e2011a78df26e0e018c7ca61ff49cd8 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 27 Jan 2023 10:06:06 -0500 Subject: [PATCH 209/327] Migrate extension from v2 to v3 --- extension/writing-process/src/writing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index 1e63f9df1..e55021508 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix-page")[0].innerText; + return document.getElementsByClassName("kix")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 3e9c3cb420af50eabf1cd80d917a95ffc838e491 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 210/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 45848068594fc15a27d79d65477d73fae96c8dc2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 211/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/dashboard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 80e9a24cb29e0fe56e9a54fc11c0ac912ed2f878 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 212/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/dashboard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 6d6df217a391433061d32b7e06b2722f38d67006 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 213/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 41bd104c6..7b4d2868e 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From a5c5e9e3a690ff544febb8a2c3682f30c15ed199 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 214/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From fe650513ebd79ae6543aa8668d9436cf8754450c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 215/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 69f9cabe602d6a9d4cce7b288384af03f0334301 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 216/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 1c53f6d147272dac42ccbccb46806563d33d0024 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 217/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 2260dbcc148b2e1574d2bf94f5ac44fa077c5e77 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 218/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 7b4d2868e..41bd104c6 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 75dbe7c36b2889168b77e9e3cf9db95a6dcd221e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 00:15:11 -0500 Subject: [PATCH 219/327] Minor cleaning. --- modules/writing_observer/writing_observer/writing_analysis.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 41bd104c6..3c4cdb431 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -356,12 +356,8 @@ async def last_document(event, internal_state): ''' document_id = get_doc_id(event) - print(">>> last_doc_call: ", event) - document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call docid: ", document_id) - if document_id is not None: state = {"document_id": document_id} return state, state From 8b07a4e52a8d173114c34c944d3a28dddd6ede74 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 220/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 3456de378..ff13909f9 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From efc037964a44e41c75ed5fd8a2d083f7c78e002b Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 3 Mar 2023 08:43:46 -0500 Subject: [PATCH 221/327] Fix content script unload/reload --- extension/writing-process/src/writing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index e55021508..1e63f9df1 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix")[0].innerText; + return document.getElementsByClassName("kix-page")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 9f7ca8602bc88fb5b2cfe04e942f68aa271096fa Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 12:33:45 -0400 Subject: [PATCH 222/327] Minor tweak to service startup. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..4a735eec4 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -33,6 +33,5 @@ source $VIRTUALENV_PATH/bin/activate nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid - # Set the number of allowed open files to something large 8192 prlimit --pid $PROCESS_ID --nofile=8192 From c1c8338014c24bb8b77a266c27203cbe6772e4a5 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 14:01:45 -0400 Subject: [PATCH 223/327] Making minor fix in module loading for new libraries. --- .../wo_highlight_dashboard/module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index cbf8b1f8e..4a4008990 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,6 +23,18 @@ } ] +# Third party module tests with helpful messages. +Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' +if (dbc.themes.MINTY != Minty_URL): + print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) + print("You will need to update dash bootstrap components hash value.\n") + +FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" +if (dbc.icons.FONT_AWESOME != FontAwesome_URL): + print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) + print("You will need to update the FontAwesome bootstrap components hash value.\n") + + THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From 5164799516b0007b673876ac320708da7c7d61c8 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 23:21:59 -0400 Subject: [PATCH 224/327] Adding explicit cuda call. --- servermanagement/AddWOtoVENV.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index da51a93a2..d2384b455 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,6 +60,15 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt +# If we plan to use a GPU then this line must also +# be run. Comment out the code below if you do +# not want cuda installed or edit it for your +# library version. +echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" +echo -e "\n Using CUDA v. 117" +cd .. +"$PIP_CMD" install spacy[cuda117] + echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From 753d225be906b43077646dd0dbc4dd88fd22a02f Mon Sep 17 00:00:00 2001 From: "Collin F. Lynch" Date: Fri, 17 Mar 2023 01:27:59 -0400 Subject: [PATCH 225/327] Updating Add script to deal with 12x bug on spacy install. --- servermanagement/AddWOtoVENV.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index d2384b455..78d89ee4c 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,14 +60,8 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt -# If we plan to use a GPU then this line must also -# be run. Comment out the code below if you do -# not want cuda installed or edit it for your -# library version. -echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" -echo -e "\n Using CUDA v. 117" -cd .. -"$PIP_CMD" install spacy[cuda117] + + echo -e "\n=== Installing Learning Observer ===" cd learning_observer From d11e842e3ec13737ca97906249535492842df5dc Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 22 May 2023 20:31:22 -0400 Subject: [PATCH 226/327] Fixing the manifest issue for permissions. (#81) * Fixing the manifest issue for permissions. * Fixing manifest to reflect new version and to remove permissions that we do not make use of. --- extension/writing-process/src/manifest.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/extension/writing-process/src/manifest.json b/extension/writing-process/src/manifest.json index ad7c064a0..5f5be54df 100644 --- a/extension/writing-process/src/manifest.json +++ b/extension/writing-process/src/manifest.json @@ -11,11 +11,9 @@ "minimum_chrome_version": "88", "permissions": [ "webRequest", - "declarativeNetRequest", "identity", "identity.email", "storage", - "nativeMessaging", "scripting", "activeTab", "tabs" From 3b4f5b248de8fbf626e9f1ac8c337f4ed8132741 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 24 May 2023 12:31:58 -0400 Subject: [PATCH 227/327] Rebasing from master and adding module updates. --- .../wo_highlight_dashboard/module.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index 4a4008990..cbf8b1f8e 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,18 +23,6 @@ } ] -# Third party module tests with helpful messages. -Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' -if (dbc.themes.MINTY != Minty_URL): - print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) - print("You will need to update dash bootstrap components hash value.\n") - -FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" -if (dbc.icons.FONT_AWESOME != FontAwesome_URL): - print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) - print("You will need to update the FontAwesome bootstrap components hash value.\n") - - THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From f4440f73339f4eef527d9a29f535ecaa9ee235d1 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 228/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 4a735eec4..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh @@ -33,5 +32,6 @@ source $VIRTUALENV_PATH/bin/activate nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid + # Set the number of allowed open files to something large 8192 prlimit --pid $PROCESS_ID --nofile=8192 From 76b66de1c04d70ea478597059f66009fa29fe84b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:28:57 -0500 Subject: [PATCH 229/327] Adding initialization scripts. --- servermanagement/AddWOtoVENV.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 78d89ee4c..da51a93a2 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,9 +60,6 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt - - - echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From 164fed77caeaee0296397926510a4659bf6fc38e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 230/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 99003926ad606c9a4a00771eb1102d9ab35424ce Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 231/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index ff13909f9..9df77d60e 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json From 11c5365b306354febeead89c6885fa2fc920dd30 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 232/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- 4 files changed, 12 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 9df77d60e..3456de378 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json From 51814ff95ad004209baf6c66c8c2f6763e6bf9cd Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 233/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 8 ++ 2 files changed, 96 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 3c4cdb431..a31753665 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -358,6 +359,13 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = writing_observer.event_wrapper.get_doc_id(event) + + print(">>> last_doc_call docid: ", document_id) + if document_id is not None: state = {"document_id": document_id} return state, state From 83a32b143f57f3f0fcd3c0c575921af86e13f070 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 234/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- .../writing_observer/writing_analysis.py | 9 +++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index a31753665..27a7afa5d 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -359,12 +359,11 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call: ", event) - - #document_id = event.get('client', {}).get('doc_id', None) + # Initially this code looked only for cases where the document + # id was specified by a doc_id field. This fix uses the event + # wrapper methods to support access of IDs located in the + # doc_id field or in the 'object' field. document_id = writing_observer.event_wrapper.get_doc_id(event) - - print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From 8a6c70f4e926e3bcebdf3aee7322c3b2b707be2d Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 235/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 1e3bb5ee4420de0b5c4256c9d549ff26be419bef Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:39:13 -0500 Subject: [PATCH 236/327] Updating writing analysis to better deal with event types. --- .../writing_observer/writing_analysis.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 27a7afa5d..8a069b815 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -359,11 +359,12 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) - # Initially this code looked only for cases where the document - # id was specified by a doc_id field. This fix uses the event - # wrapper methods to support access of IDs located in the - # doc_id field or in the 'object' field. - document_id = writing_observer.event_wrapper.get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = get_doc_id_wrapper(event) + + print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From 377ab1ed15919e321295f9caebb14c7a4828f16f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 237/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From efa792ed94af18c1bb4a9ce09042a446cad7c3d3 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:52 -0500 Subject: [PATCH 238/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 8a069b815..83f4ddf5d 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -361,7 +361,6 @@ async def last_document(event, internal_state): print(">>> last_doc_call: ", event) - #document_id = event.get('client', {}).get('doc_id', None) document_id = get_doc_id_wrapper(event) print(">>> last_doc_call docid: ", document_id) From 30c13cecf3967c6612f6896d94ba9da3356cfb70 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 239/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 1c140d572cf205b5dcb3155de5760382e169fa9b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 240/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 83f4ddf5d..bc8cd6fc2 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 094e767455968bbce580c26907e7e9b82e282da2 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 27 Jan 2023 10:06:06 -0500 Subject: [PATCH 241/327] Migrate extension from v2 to v3 --- extension/writing-process/src/writing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index 1e63f9df1..e55021508 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix-page")[0].innerText; + return document.getElementsByClassName("kix")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 954afb6eb205554f70f8977aceabaf867a046da8 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 242/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 17b75fb51565bd6319a079e553d9b4cad87fa72a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 243/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/dashboard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 01d5802da55d5b43f01dd4faa021a4cfc2a38e7d Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 244/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/dashboard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 206e3f5ae0834766eb5eb02f1c992d3f6140fe21 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 245/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index bc8cd6fc2..83f4ddf5d 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From a8c894da90c11d3a63491cfd75c66bdedc9035b6 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 246/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From 6a9f3c25e62277ac278d5bd1c38e739ba0e128c1 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 247/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From b09065e30dd6144326975d4711894bdcc9612fcb Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 248/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 4a29d613997d654c7e5d9835b4ac4617d3a6eb13 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 249/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 71645d7f21962d3f929e97798e2a9e1f38e5349a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 250/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 83f4ddf5d..bc8cd6fc2 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From c822be76480636c3eda2c56fe877583dc9f991d0 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 00:15:11 -0500 Subject: [PATCH 251/327] Minor cleaning. --- modules/writing_observer/writing_observer/writing_analysis.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index bc8cd6fc2..08cd31018 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -358,12 +358,8 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call: ", event) - document_id = get_doc_id_wrapper(event) - print(">>> last_doc_call docid: ", document_id) - if document_id is not None: state = {"document_id": document_id} return state, state From 80c5b4174799357357eb6a032c98350bee73450c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 252/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 3456de378..ff13909f9 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 5d623b1895767249c9103e0cf5ffcfb7d4e15c8e Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 3 Mar 2023 08:43:46 -0500 Subject: [PATCH 253/327] Fix content script unload/reload --- extension/writing-process/src/writing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index e55021508..1e63f9df1 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix")[0].innerText; + return document.getElementsByClassName("kix-page")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 6a7db9f3618115bc8b180a4060b898098bd05cbb Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 14:01:45 -0400 Subject: [PATCH 254/327] Making minor fix in module loading for new libraries. --- .../wo_highlight_dashboard/module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index cbf8b1f8e..4a4008990 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,6 +23,18 @@ } ] +# Third party module tests with helpful messages. +Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' +if (dbc.themes.MINTY != Minty_URL): + print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) + print("You will need to update dash bootstrap components hash value.\n") + +FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" +if (dbc.icons.FONT_AWESOME != FontAwesome_URL): + print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) + print("You will need to update the FontAwesome bootstrap components hash value.\n") + + THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From 61060bd3090284b977fae9d88a0968ff6d4ed50a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 23:21:59 -0400 Subject: [PATCH 255/327] Adding explicit cuda call. --- servermanagement/AddWOtoVENV.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index da51a93a2..d2384b455 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,6 +60,15 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt +# If we plan to use a GPU then this line must also +# be run. Comment out the code below if you do +# not want cuda installed or edit it for your +# library version. +echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" +echo -e "\n Using CUDA v. 117" +cd .. +"$PIP_CMD" install spacy[cuda117] + echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From 5337b2a4726b401375e83d7d70f832ad1a5862ad Mon Sep 17 00:00:00 2001 From: "Collin F. Lynch" Date: Fri, 17 Mar 2023 01:27:59 -0400 Subject: [PATCH 256/327] Updating Add script to deal with 12x bug on spacy install. --- servermanagement/AddWOtoVENV.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index d2384b455..78d89ee4c 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -60,14 +60,8 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt -# If we plan to use a GPU then this line must also -# be run. Comment out the code below if you do -# not want cuda installed or edit it for your -# library version. -echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" -echo -e "\n Using CUDA v. 117" -cd .. -"$PIP_CMD" install spacy[cuda117] + + echo -e "\n=== Installing Learning Observer ===" cd learning_observer From 8014373cd4172a02fa2c0ea410b3fb5cb92cbd53 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 25 May 2023 22:56:21 -0400 Subject: [PATCH 257/327] Cleaning up minor differences after rebase. --- .../wo_highlight_dashboard/dashboard/students.py | 1 - modules/writing_observer/writing_observer/aggregator.py | 1 - 2 files changed, 2 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index fa798188c..0aa405fce 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,7 +120,6 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ - settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 530b244bd..4674f53c4 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -14,7 +14,6 @@ import learning_observer.kvs import learning_observer.settings import learning_observer.stream_analytics.helpers -# import traceback import learning_observer.util pmss.register_field( From 85bc9d73df72ee291a8df189f7f1e50ee4f2d1d4 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 258/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From b474c419bcfec65dc4d1759c4fd93b9eef3feb44 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 259/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 41757d0e4c0c4e65adfeb295b59ab6f4f393396c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 260/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index ff13909f9..9df77d60e 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json From fe0c44a3fb3a042cbc1c1cda6f5df7bcc94e3e37 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 261/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- 4 files changed, 12 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 9df77d60e..3456de378 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json From c066c23dd4f980b796803f6378e5ee12170a2436 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 23 Dec 2022 11:24:37 -0500 Subject: [PATCH 262/327] Add settings to dropdown menu --- .../wo_highlight_dashboard/dashboard/students.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index 0aa405fce..fa798188c 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,6 +120,7 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ + settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn From 7f95a92564db02a1ba2e9935646469e25657f20f Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 263/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 08cd31018..dd88c6a43 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 15855505b291722baac0ad1da5c9f48ff2d50a27 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 264/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From f80319dade6602df9e925a7350cbbda2645bbf7e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 265/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 96fb537856bf226be1519055b64db4d63d6c8093 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 266/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From bdd5e6de0e19ceb092b617678feadcdf805bea2c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 267/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 119d26f705b44dab6624ca7a3e7996341e780f88 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 268/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index dd88c6a43..08cd31018 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From fe035ec4618e953381aec834a4e8b548b5d3df90 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 27 Jan 2023 10:06:06 -0500 Subject: [PATCH 269/327] Migrate extension from v2 to v3 --- extension/writing-process/src/writing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index 1e63f9df1..e55021508 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix-page")[0].innerText; + return document.getElementsByClassName("kix")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 899e13e288bbd440c72ec91f1e106791b32bc654 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 270/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..580aef3a0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 8d30001738c657c7e1b2003cb416d08ed9dd604c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 271/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/dashboard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From ae461f5ac23859b055838ac4ea8ba70237bce479 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 272/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/dashboard.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 0629f9ac54400129c1cd86663902facdf9fbcc62 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 273/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 1 + 2 files changed, 89 insertions(+) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 08cd31018..dd88c6a43 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 01545dd3af9d9825369f8f88ae048f71e06da29e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 274/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + From 1dc9ca1a07c21bdd7dcef9e363eb53705038bf76 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 275/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From b1f2b350cb43d0269f9d62d155fdddfab68a9832 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 276/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 414887d4feca6322e3ea8e2184792530fde5fd32 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 277/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 580aef3a0..d11fc859b 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 7779da1a0701c68c8c87d7d964c32e6320998080 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 278/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index dd88c6a43..08cd31018 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 1a035a486f1a611237aa438ea7a9908c46c2e200 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 00:15:11 -0500 Subject: [PATCH 279/327] Minor cleaning. --- modules/writing_observer/writing_observer/writing_analysis.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 08cd31018..3c4cdb431 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -358,8 +358,6 @@ async def last_document(event, internal_state): document_id = get_doc_id_wrapper(event) - document_id = get_doc_id_wrapper(event) - if document_id is not None: state = {"document_id": document_id} return state, state From b274547d797e67be056c0815854e937c93006e95 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 280/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 3456de378..ff13909f9 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 9497e730297abbc820ce895ac8bc6d4ba4656e04 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 3 Mar 2023 08:43:46 -0500 Subject: [PATCH 281/327] Fix content script unload/reload --- extension/writing-process/src/writing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index e55021508..1e63f9df1 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix")[0].innerText; + return document.getElementsByClassName("kix-page")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 14435b13179df0ea92c57b349d298100f8412801 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 12:33:45 -0400 Subject: [PATCH 282/327] Minor tweak to service startup. --- servermanagement/RunLearningObserver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index d11fc859b..4a735eec4 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -33,6 +33,5 @@ source $VIRTUALENV_PATH/bin/activate nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid - # Set the number of allowed open files to something large 8192 prlimit --pid $PROCESS_ID --nofile=8192 From d904da46b811872be247516b1a3a732453a8b227 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 22 May 2023 20:31:22 -0400 Subject: [PATCH 283/327] Fixing the manifest issue for permissions. (#81) * Fixing the manifest issue for permissions. * Fixing manifest to reflect new version and to remove permissions that we do not make use of. --- extension/writing-process/src/manifest.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/extension/writing-process/src/manifest.json b/extension/writing-process/src/manifest.json index 5f5be54df..05ee998a1 100644 --- a/extension/writing-process/src/manifest.json +++ b/extension/writing-process/src/manifest.json @@ -35,6 +35,22 @@ "matches": ["*://docs.google.com/document/*"], "js": ["3rdparty/sha256.js", "writing_common.js", "writing.js"] }], + "web_accessible_resources": [{ + "resources": ["inject.js"], + "matches": ["*://docs.google.com/*"], + "use_dynamic_url": true + }], + "background": { + "service_worker": "service_worker.js" + }, + "permissions": [ + "webRequest", + "identity", + "identity.email", + "storage", + "scripting", + "activeTab" + ], "host_permissions": [ "*://docs.google.com/document/*" ], From a67cded020b8de9aba2f82736a9677576c771c99 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 24 May 2023 12:31:58 -0400 Subject: [PATCH 284/327] Rebasing from master and adding module updates. --- .../wo_highlight_dashboard/module.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index 4a4008990..cbf8b1f8e 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,18 +23,6 @@ } ] -# Third party module tests with helpful messages. -Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' -if (dbc.themes.MINTY != Minty_URL): - print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) - print("You will need to update dash bootstrap components hash value.\n") - -FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" -if (dbc.icons.FONT_AWESOME != FontAwesome_URL): - print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) - print("You will need to update the FontAwesome bootstrap components hash value.\n") - - THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From b376590c406498899441d7292a454d62cf8e1d8a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:32:48 -0500 Subject: [PATCH 285/327] Pushing general modifications made to the extension to support local use. --- extension/extension/background.js | 406 +++++++++++++++++++++++ extension/writing-process/src/writing.js | 12 +- 2 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 extension/extension/background.js diff --git a/extension/extension/background.js b/extension/extension/background.js new file mode 100644 index 000000000..58b36c53a --- /dev/null +++ b/extension/extension/background.js @@ -0,0 +1,406 @@ +/* +Background script. This works across all of Google Chrome. +*/ + +// Do not save debug requests. We flip this frequently. Perhaps this +// should be a cookie or browser.storage? +var RAW_DEBUG = false; + + +/* + TODO: FSM + + +----------------------+ + | Load server settings | + | from chrome.storage | + +----------------------+ + | + v + +-------------------+ + | Connect to server | + +-------------------+ + + Load events queue + from chrome.storage + + +Dequeue events +*/ + +function profileInfoWrapper(callback) { + /* Workaround for this bug: + https://bugs.chromium.org/p/chromium/issues/detail?id=907425#c6 + */ + try { + chrome.identity.getProfileUserInfo({accountStatus: 'ANY'}, callback); + } catch (e) { + // accountStatus not supported + chrome.identity.getProfileUserInfo(callback); + } +} + +function console_logger() { + /* + Log to browser JavaScript console + */ + return console.log; +} + + +function add_event_metadata(event_type, event) { + /* + TODO: Should we add user identity? + */ + event['event'] = event_type; + + event['source'] = 'org.mitros.writing_analytics'; + event['version'] = 'alpha'; + event['ts'] = Date.now(); + event['human_ts'] = Date(); + event['iso_ts'] = new Date().toISOString; + return event; +} + + +function websocket_logger(server) { + /* + Log to web socket server. + + Optional: + * We could send queued events on socket open (or on a timeout) + * Or we could just wait for the next event (what we do now) + + The former would be a little bit more robust. + */ + var socket; + var state = new Set() + var queue = []; + + function new_websocket() { + socket = new WebSocket(server); + socket.onopen=prepare_socket; + socket.onerror = function(event) { + console.log("Could not connect"); + var event = { "issue": "Could not connect" }; + event = add_event_metadata("warning", event); + event = JSON.stringify(event); + queue.push(event); + }; + socket.onclose = function(event) { + console.log("Lost connection"); + var event = { "issue": "Lost connection", "code": event.code }; + event = add_event_metadata("warning", event); + event = JSON.stringify(event); + queue.push(event); + }; + return socket; + } + + socket = new_websocket(); + + function are_we_done() { + if (state.has("chrome_identity") && + state.has("local_storage")) { + event = {}; + event = add_event_metadata('metadata_finished', event); + socket.send(JSON.stringify(event)); + state.add("ready"); + } + } + + function prepare_socket() { + // Send the server the user info. This might not always be available. + state = new Set(); + profileInfoWrapper(function callback(userInfo) { + event = { + "chrome_identity": userInfo + }; + event = add_event_metadata("chrome_identity", event); + socket.send(JSON.stringify(event)); + state.add("chrome_identity"); + are_we_done(); + }); + storage_keys = [ + "teacher_tag", // Unused. In the future: whom do we authorize to receive data? + "user_tag", // Unique per-user tag in the settings page + "process_server", // Unused. Which server should we send to? + "unique_id", // Unique ID set in the settings page + "generated_id" // Autogenerated, for future forensics + ] + chrome.storage.sync.get(storage_keys, function(result) { + if(result !== undefined) { + event = {'local_storage': result}; + } else { + event = {'local_storage': {}}; + } + /*if("generated_id" not in event['local_storage']){ + event['local_storage']['generated_id'] = unique_id(); + chrome.storage.sync.set( + 'generated_id', + event['local_storage']['generated_id'] + ); + }*/ + console.log(event); + event = add_event_metadata("local_storage", event); + console.log(event); + socket.send(JSON.stringify(event)); + state.add("local_storage"); + are_we_done(); + }); + } + + function dequeue() { + if(socket === null) { + // Do nothing. We're reconnecting. + console.log("Event squelched; reconnecting"); + } else if(socket.readyState === socket.OPEN && + state.has("ready")) { + while(queue.length > 0) { + var event = queue.shift(); + socket.send(event); /* TODO: We should do receipt confirmation before dropping events */ + } + } else if((socket.readyState == socket.CLOSED) || (socket.readyState == socket.CLOSING)) { + /* + If we lost the connection, we wait a second and try to open it again. + + Note that while socket is `null` or `CONNECTING`, we don't take either + branch -- we just queue up events. We reconnect after 1 second if closed, + or dequeue events if open. + */ + console.log("Re-opening connection in 1s"); + socket = null; + state = new Set(); + setTimeout(function() { + console.log("Re-opening connection"); + socket = new_websocket(); + }, 1000); + } + } + + return function(data) { + queue.push(data); + dequeue(); + } +} + +function ajax_logger(ajax_server) { + /* + HTTP event per request. + + To do: Handle failures / dropped connections + */ + var server = ajax_server; + return function(data) { + /* + Helper function to send a logging AJAX request to the server. + This function takes a JSON dictionary of data. + */ + + httpRequest = new XMLHttpRequest(); + //httpRequest.withCredentials = true; + httpRequest.open("POST", ajax_server); + httpRequest.send(data); + } +} + +/* +List of loggers. For example, if we want to send to the server twice, and log on console: + +loggers_enabled = [ + console_logger(), + ajax_logger("https://localhost/webapi/"), + websocket_logger("wss://localhost/wsapi/in/") +]; +*/ +loggers_enabled = [ + console_logger(), + //ajax_logger("https://writing.learning-observer.org/webapi/")//, + + // Adapted to NCSU Setup. + websocket_logger("wss://observer.csc.ncsu.edu/wsapi/in/") + //websocket_logger("wss://writing.learning-observer.org/wsapi/in/") +]; + +function log_event(event_type, event) { + /* + This sends an event to the server. + */ + event = add_event_metadata(event_type, event); + + if(event['wa_source'] = null) { + event['wa_source'] = 'background_page'; + } + var json_encoded_event = JSON.stringify(event); + + for (var i=0; i Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 286/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- servermanagement/RunLearningObserver.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 4a735eec4..8e368e5e0 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,7 @@ +<<<<<<< HEAD +======= +>>>>>>> 6b0b47c7 (Added in missing documentation files from prior fork and added in scripts) #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From db81148b4188fce66e4824c8b8ff3dadc609c52b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 287/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_highlight_dashboard/assets/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 32a8d713b..8db2fa014 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,6 +155,7 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } + console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From de9131d4bc0dba593de391a551bfbbf20e03aa0b Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 288/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- learning_observer/learning_observer/auth/social_sso.py | 3 +++ learning_observer/learning_observer/dashboard.py | 9 +++++++++ learning_observer/learning_observer/kvs.py | 4 ++++ learning_observer/learning_observer/rosters.py | 6 +++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a12657957..78cb51c28 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,6 +274,9 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() + + # print(">>>>DATA::") + # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7799773b4..7fa597eae 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,6 +208,9 @@ async def student_state_fetcher(): ''' students = [] for student in roster: + + print("#$#$ StudRost: ", student) + student_state = { # We're copying Google's roster format here. # @@ -237,6 +240,7 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id + # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -320,6 +324,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -345,6 +351,9 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() + + print("#### sd: ", sd) + data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 325c7b8d8..75d7b2d1f 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,6 +65,7 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] + async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -148,6 +149,9 @@ async def __getitem__(self, key): >> await kvs['item'] ''' + + print("$$$$ Getting: ", key) + await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index ff13909f9..9df77d60e 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,6 +114,8 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' + print(">> RESP_JSON_IN:", key, resp_json) + # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -143,7 +145,9 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - + + + print("<< RESP_JSON_OUT:", resp_json) return resp_json From 545981ee10898a0d8d77d776971dad7d6e7b59b2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 289/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/auth/social_sso.py | 2 -- learning_observer/learning_observer/dashboard.py | 6 ------ learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 2 -- 4 files changed, 12 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index 78cb51c28..a15208373 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -275,8 +275,6 @@ async def _google(request): async with client.post(url, data=params) as resp: data = await resp.json() - # print(">>>>DATA::") - # print(data) assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 7fa597eae..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -209,8 +209,6 @@ async def student_state_fetcher(): students = [] for student in roster: - print("#$#$ StudRost: ", student) - student_state = { # We're copying Google's roster format here. # @@ -324,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is @@ -352,8 +348,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - print("#### sd: ", sd) - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index 75d7b2d1f..b4a35ae98 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -150,8 +150,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - print("$$$$ Getting: ", key) - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 9df77d60e..3456de378 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - print(">> RESP_JSON_IN:", key, resp_json) # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' @@ -147,7 +146,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): resp_json.sort(key=sort_key) - print("<< RESP_JSON_OUT:", resp_json) return resp_json From e303fa9966ab1ee59acb30e85505c7dd0b8a3415 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 290/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 9 +- 2 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 3c4cdb431..4770dd242 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -354,10 +355,14 @@ async def last_document(event, internal_state): functions for the analysis. Over time these may age off with a better model. ''' - document_id = get_doc_id(event) - document_id = get_doc_id_wrapper(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = writing_observer.event_wrapper.get_doc_id(event) + print(">>> last_doc_call docid: ", document_id) + if document_id is not None: state = {"document_id": document_id} return state, state From d23915f6655a4c32a5a830c5886f8e21e5386df6 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 291/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- .../writing_observer/writing_analysis.py | 9 +++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 4770dd242..dee0a7460 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -356,12 +356,11 @@ async def last_document(event, internal_state): model. ''' - print(">>> last_doc_call: ", event) - - #document_id = event.get('client', {}).get('doc_id', None) + # Initially this code looked only for cases where the document + # id was specified by a doc_id field. This fix uses the event + # wrapper methods to support access of IDs located in the + # doc_id field or in the 'object' field. document_id = writing_observer.event_wrapper.get_doc_id(event) - - print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From dc5593e7a85ee4075ace7fdfee2c56b08337ea79 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 292/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From 048e613dfca018db9875d010ff2a8a275f4c74d7 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:39:13 -0500 Subject: [PATCH 293/327] Updating writing analysis to better deal with event types. --- .../writing_observer/writing_analysis.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index dee0a7460..49bba295f 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -356,11 +356,12 @@ async def last_document(event, internal_state): model. ''' - # Initially this code looked only for cases where the document - # id was specified by a doc_id field. This fix uses the event - # wrapper methods to support access of IDs located in the - # doc_id field or in the 'object' field. - document_id = writing_observer.event_wrapper.get_doc_id(event) + print(">>> last_doc_call: ", event) + + #document_id = event.get('client', {}).get('doc_id', None) + document_id = get_doc_id_wrapper(event) + + print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From 359bffa31cfec36d0d3ac12326b5c2df79c9acb8 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 294/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From 7b0a36f90a8242c14ee15bc0e2a1a1a4dc662941 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:52 -0500 Subject: [PATCH 295/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 49bba295f..453c989b7 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -358,7 +358,6 @@ async def last_document(event, internal_state): print(">>> last_doc_call: ", event) - #document_id = event.get('client', {}).get('doc_id', None) document_id = get_doc_id_wrapper(event) print(">>> last_doc_call docid: ", document_id) From 871149b9afcecb76129f377b1c0735f474b0fd0a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 296/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 8e368e5e0..a6ad08bda 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,7 +1,3 @@ -<<<<<<< HEAD - -======= ->>>>>>> 6b0b47c7 (Added in missing documentation files from prior fork and added in scripts) #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 9c6d4625d25012f088e9d448a506386d3cc3fe41 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 297/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 453c989b7..10689f129 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From 0fd2a39d63e7f6d3bf9e6b27e48230bd3a320aa1 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 27 Jan 2023 10:06:06 -0500 Subject: [PATCH 298/327] Migrate extension from v2 to v3 --- extension/extension/background.js | 44 +++++++++++++--------- extension/extension/manifest.json | 48 ++++++++++++++++++++++++ extension/writing-process/src/writing.js | 2 +- 3 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 extension/extension/manifest.json diff --git a/extension/extension/background.js b/extension/extension/background.js index 58b36c53a..3d8adfea0 100644 --- a/extension/extension/background.js +++ b/extension/extension/background.js @@ -111,6 +111,7 @@ function websocket_logger(server) { function prepare_socket() { // Send the server the user info. This might not always be available. state = new Set(); + let event; profileInfoWrapper(function callback(userInfo) { event = { "chrome_identity": userInfo @@ -120,7 +121,7 @@ function websocket_logger(server) { state.add("chrome_identity"); are_we_done(); }); - storage_keys = [ + let storage_keys = [ "teacher_tag", // Unused. In the future: whom do we authorize to receive data? "user_tag", // Unique per-user tag in the settings page "process_server", // Unused. Which server should we send to? @@ -190,7 +191,7 @@ function ajax_logger(ajax_server) { To do: Handle failures / dropped connections */ var server = ajax_server; - return function(data) { + return function (data) { /* Helper function to send a logging AJAX request to the server. This function takes a JSON dictionary of data. @@ -212,7 +213,7 @@ loggers_enabled = [ websocket_logger("wss://localhost/wsapi/in/") ]; */ -loggers_enabled = [ +let loggers_enabled = [ console_logger(), //ajax_logger("https://writing.learning-observer.org/webapi/")//, @@ -226,7 +227,7 @@ function log_event(event_type, event) { This sends an event to the server. */ event = add_event_metadata(event_type, event); - + if(event['wa_source'] = null) { event['wa_source'] = 'background_page'; } @@ -237,8 +238,12 @@ function log_event(event_type, event) { } } +function logFromServiceWorker(event) { + console.log(event); +} + function send_chrome_identity() { - /* + /* We sometimes may want to log the user's identity, as stored in Google Chrome. Note that this is not secure; we need oauth to do that. oauth can be distracting in that (at least in the workflow @@ -249,11 +254,12 @@ function send_chrome_identity() { Note this function is untested, following a refactor. */ - chrome.identity.getProfileInfo(function(userInfo) { - log_event("chrome_identity_load", {"email": userInfo.email, - "id": userInfo.id - }); + chrome.identity.getProfileInfo(function (userInfo) { + log_event("chrome_identity_load", { + email: userInfo.email, + id: userInfo.id, }); + }); } function this_a_google_docs_save(request) { @@ -343,6 +349,7 @@ chrome.webRequest.onBeforeRequest.addListener( function(request) { //chrome.extension.getBackgroundPage().console.log("Web request url:"+request.url); var formdata = {}; + let event; if(request.requestBody) { formdata = request.requestBody.formData; } @@ -360,24 +367,24 @@ chrome.webRequest.onBeforeRequest.addListener( //chrome.extension.getBackgroundPage().console.log("Google Docs bundles "+request.url); try { /* We should think through which time stamps we should log. These are all subtly - different: browser event versus request timestamp, as well as user time zone - versus GMT. */ + different: browser event versus request timestamp, as well as user time zone + versus GMT. */ event = { 'doc_id': googledocs_id_from_url(request.url), - 'url': request.url, + 'url': request.url, 'bundles': JSON.parse(formdata.bundles), 'rev': formdata.rev, 'timestamp': parseInt(request.timeStamp, 10) } - chrome.extension.getBackgroundPage().console.log(event); + logFromServiceWorker(event); log_event('google_docs_save', event); } catch(err) { /* Oddball events, like text selections. - */ + */ event = { 'doc_id': googledocs_id_from_url(request.url), - 'url': request.url, + 'url': request.url, 'formdata': formdata, 'rev': formdata.rev, 'timestamp': parseInt(request.timeStamp, 10) @@ -385,9 +392,9 @@ chrome.webRequest.onBeforeRequest.addListener( log_event('google_docs_save_extra', event); } } else if(this_a_google_docs_bind(request)) { - chrome.extension.getBackgroundPage().console.log(request); + logFromServiceWorker(request); } else { - chrome.extension.getBackgroundPage().console.log("Not a save or bind: "+request.url); + logFromServiceWorker("Not a save or bind: "+request.url); } }, { urls: ["*://docs.google.com/*"] }, @@ -403,4 +410,5 @@ profileInfoWrapper(function callback(userInfo) { }); // And let the console know we've loaded -chrome.extension.getBackgroundPage().console.log("Loaded"); +// chrome.extension.getBackgroundPage().console.log("Loaded"); remove +logFromServiceWorker("Loaded"); diff --git a/extension/extension/manifest.json b/extension/extension/manifest.json new file mode 100644 index 000000000..0f95451f2 --- /dev/null +++ b/extension/extension/manifest.json @@ -0,0 +1,48 @@ +{ + "author": "Piotr Mitros", + "manifest_version": 3, + "name": "Writing Process", + "homepage_url": "https://github.com/ETS-Next-Gen/writing_observer", + "incognito": "not_allowed", + "offline_enabled": true, + "version": "0.0.0.1", + "description": "Tracks writing in Google Docs, and provides nifty insights to you and your teachers!", + "action": { + "default_title": "Writing Process", + "default_popup": "pages/settings.html", + "default_icon": { + "48": "icons/lousy-fountain-pen-48.png" + } + }, + "content_scripts": [{ + "matches": ["*://docs.google.com/*"], + "js": ["3rdparty/sha256.js", "writing_common.js", "writing.js"] + }], + "web_accessible_resources": [{ + "resources": ["inject.js"], + "matches": ["*://docs.google.com/*"], + "use_dynamic_url": true + }], + "background": { + "service_worker": "service_worker.js" + }, + "permissions": [ + "webRequest", + "declarativeNetRequest", + "identity", + "identity.email", + "storage", + "nativeMessaging", + "scripting", + "activeTab" + ], + "host_permissions": [ + "*://docs.google.com/*" + ], + "icons": { + "48": "icons/lousy-fountain-pen-48.png" + }, + "options_ui": { + "page": "pages/options.html" + } +} diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index 913c91794..028a5dd1a 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix-page")[0].innerText; + return document.getElementsByClassName("kix")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 731345b1818a1b3a423ec8a821658b68bea5e5b0 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Wed, 8 Feb 2023 20:32:29 -0500 Subject: [PATCH 299/327] Fix bug "Extension context invalidated" --- extension/extension/background.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/extension/extension/background.js b/extension/extension/background.js index 3d8adfea0..b78502ef2 100644 --- a/extension/extension/background.js +++ b/extension/extension/background.js @@ -401,6 +401,20 @@ chrome.webRequest.onBeforeRequest.addListener( ['requestBody'] ) +// re-injected scripts when chrome extension is reloaded, upgraded or re-installed +// https://stackoverflow.com/questions/10994324/chrome-extension-content-script-re-injection-after-upgrade-or-install + +chrome.runtime.onInstalled.addListener(async () => { + for (const cs of chrome.runtime.getManifest().content_scripts) { + for (const tab of await chrome.tabs.query({url: cs.matches})) { + chrome.scripting.executeScript({ + target: {tabId: tab.id}, + files: cs.js, + }); + } + } +}); + // Let the server know we've loaded. log_event("extension_loaded", {}); From 6b43d073d47bcb34606d16ebead97188656dd2e3 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 10 Feb 2023 09:37:41 -0500 Subject: [PATCH 300/327] Add more code comments/documentation --- extension/extension/background.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extension/extension/background.js b/extension/extension/background.js index b78502ef2..00709c2f7 100644 --- a/extension/extension/background.js +++ b/extension/extension/background.js @@ -238,6 +238,9 @@ function log_event(event_type, event) { } } +// Function to serve as replacement for +// chrome.extension.getBackgroundPage().console.log(event); because it is not allowed in V3 +// It logs the event to the console for debugging. function logFromServiceWorker(event) { console.log(event); } From cc309755c6a63278597790d1408c2d9c2fc72163 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 16 Nov 2022 15:40:00 -0500 Subject: [PATCH 301/327] Added in missing documentation files from prior fork and added in scripts that are built to support execution/backup on the server process. --- .../learning_observer/creds.yaml.example | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/learning_observer/learning_observer/creds.yaml.example b/learning_observer/learning_observer/creds.yaml.example index 33d06c722..141afedf5 100644 --- a/learning_observer/learning_observer/creds.yaml.example +++ b/learning_observer/learning_observer/creds.yaml.example @@ -87,6 +87,7 @@ event_auth: local_storage: userfile: students.yaml allow_guest: true +<<<<<<< HEAD # chromebook: # May be necessary to support execution on chromebooks. # allow_guest: true # uncomment for testing or deployment as needed. # testcase_auth: {} @@ -101,3 +102,20 @@ modules: writing_observer: use_nlp: false openai_api_key: '' # can also be set with OPENAI_API_KEY environment variable +======= + + # (CL) The lines below are necessary to allow the chrome extension + # to work. These should be included in future anonymous cases + # but may need to be changed depending upon the security model. + + # chromebook: + # allow_guest: true + # testcase_auth: {} + + +feature_flags: {} # For enabling / disabling features in development +server: + port: 8888 # Optional. Pick a different port. + + +>>>>>>> 6fb3752e (Added in missing documentation files from prior fork and added in scripts) From 05bbc89941a895c7f0f0c94082d405b4f3c05a3a Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 8 Dec 2022 14:07:23 -0500 Subject: [PATCH 302/327] Adding error trapping code for undefined ready state case along with debugging info for the message data. --- .../wo_dash/assets/scripts.js | 358 ++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/assets/scripts.js diff --git a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/assets/scripts.js b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/assets/scripts.js new file mode 100644 index 000000000..b76705dfc --- /dev/null +++ b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/assets/scripts.js @@ -0,0 +1,358 @@ +/* + Javascript functions + This file contains Javascript functions that will be + called through a clientside callback in the Python code. + An example of how to run the javascript function, see below + + Essentially its just a JSON that defines functions. + + You'll see `window.dash_clientside.no_update` appear often in the code. + This tells dash not to update the output component. + If we don't need to update it, we shouldn't! + + This is often used with initializing the array of students to return. + `Array(students).fill(window.dash_clientside.no_update);` + Where `students` is the total number of students +*/ +// initialize dash_clientside +if (!window.dash_clientside) { + window.dash_clientside = {}; +} + +function getRGBAValues(str) { + var vals = str.substring(str.indexOf('(') +1, str.length -1).split(', '); + return { + 'r': parseInt(vals[0]), + 'g': parseInt(vals[1]), + 'b': parseInt(vals[2]), + 'o': parseFloat(vals[3]) + }; +} + +// define functions we are calling +window.dash_clientside.clientside = { + + change_sort_direction_icon: function(sort_check, sort_values) { + // updates UI elements, does not handle sorting + // based on the current sort, set the sort direction icon and sort text + + // Output(sort_icon, 'className'), + // Output(sort_label, 'children'), + // Input(sort_toggle, 'value'), + // Input(sort_by_checklist, 'value') + if (sort_values.length == 0) { + return ['fas fa-sort', 'None'] + } + if (sort_check.includes('checked')) { + return ['fas fa-sort-down', 'Desc'] + } + return ['fas fa-sort-up', 'Asc'] + }, + + reset_sort_options: function(clicks) { + // resets the sort_by_checklist, this will trigger sort_students and change_sort_direction_icon + + // Output(sort_by_checklist, 'value'), + // Input(sort_reset, 'n_clicks') + if (clicks) { + return []; + } + return window.dash_clientside.no_update; + }, + + sort_students: function(values, direction, data, options, students) { + // We sort students whenever one of the following occurs: + // 1. the checklist for sorting changes + // 2. the direction of sorting changes + // 3. the student's data changes + // We add the value of each indicator checked in the checklist to determine score for each student + // We then set the order style attribute of each student to their score + // Items with order=1 come before items with order=2 and so on. + // This will set students in ascending order (low scoring students first) + // We set a max and subtract from it to determine descending order (high scoring students first) + + // Output({'type': student_col, 'index': ALL}, 'style'), + // Input(settings.sort_by_checklist, 'value'), + // Input(settings.sort_toggle, 'value'), + // Input({'type': student_card, 'index': ALL}, 'data'), + // State(settings.sort_by_checklist, 'options'), + // State(student_counter, 'data') + + // TODO fix sorting, haven't been updated with the new NLP data + let orders = Array(students).fill(window.dash_clientside.no_update); + if (values.length === 0) { + // preserves current order when no values are present + // TODO determine some default ordering instead of leaving it as is + return orders + } + let labels = options.map(obj => {return (values.includes(obj.value) ? obj.label : '')}); + labels = labels.filter(e => e); + for (let i = 0; i < data.length; i++) { + let score = 0; + values.forEach(function (item, index) { + score += data[i].indicators[item]['value']; + }); + let order = (direction.includes('checked') ? (100*values.length) - score : score); + orders[i] = {'order': order}; + } + return orders; + }, + + populate_student_data: function(msg, old_data, students) { + // Populates and updates students data from the websocket + // for each update, parse the data into the proper format + // Also return the current time + // + // Output({'type': student_card, 'index': ALL}, 'data'), + // Output(last_updated, 'children'), + // Input(websocket, 'message'), + // State({'type': student_card, 'index': ALL}, 'data'), + // State(student_counter, 'data') + + if (!msg) { + return [old_data, 'Never']; //, 0, []]; + } + console.log(JSON.parse(msg.data)); + let updates = Array(students).fill(window.dash_clientside.no_update); + const data = JSON.parse(msg.data)['latest_writing_data']; + const stud_data = data.map(x => x.student); + // console.log(data); + for (let i = 0; i < data.length; i++) { + // TODO whatever data is included in the message should be parsed into it's appropriate spot + updates[i] = { + 'id': data[i].userId, + 'text': { + "student_text": { + "id": "student_text", + "value": data[i].text, + "label": "Student text" + } + }, + 'highlight': {}, + 'metrics': {}, + 'indicators': {} + } + for (const key in data[i]) { + let item = data[i][key]; + const sum_type = (item.hasOwnProperty('summary_type') ? item['summary_type'] : ''); + if (sum_type === 'total') { + updates[i]['metrics'][`${key}_metric`] = { + 'id': `${key}_metric`, + 'value': item['metric'], + 'label': item['label'] + } + } else if (sum_type === 'percent') { + updates[i]['indicators'][`${key}_indicator`] = { + 'id': `${key}_indicator`, + 'value': item['metric'], + 'label': item['label'] + } + } + const offsets = (item.hasOwnProperty('offsets') ? item['offsets'] : ''); + if (offsets.length !== 0) { + updates[i]['highlight'][`${key}_highlight`] = { + 'id': `${key}_highlight`, + 'value': item['offsets'], + 'label': item['label'] + } + } + } + } + const timestamp = new Date(); + + const count = (data.length == students ? window.dash_clientside.no_update : data.length) + const new_students = (stud_data.length == students ? window.dash_clientside.no_update : stud_data) + + return [updates, timestamp.toLocaleTimeString()]; //, count, new_students]; + }, + + open_settings: function(clicks, close, is_open, students) { + // Toggles the settings panel + // Based on if its open or not, we adjust the grid css classes of students and the panel itself + // this makes the student card remain the same size even if the settings panel is open. + // + // There are multiple ways to close the settings button (x button or click settings again). + // This means we have to determine which input fired and handle the possible cases. + + // Output(settings_collapse, 'is_open'), + // Output({'type': student_col, 'index': ALL}, 'class_name'), + // Output(student_grid, 'class_name'), + // Input(settings.open_btn, 'n_clicks'), + // Input(settings.close_settings, 'n_clicks'), + // State(settings_collapse, 'is_open'), + // State(student_counter, 'data') + + // determine which button caused this callback to trigger + const trig = dash_clientside.callback_context.triggered[0]; + if(!is_open & (typeof trig !== 'undefined')) { + if (trig.prop_id === 'teacher-dashboard-settings-show-hide-open-button.n_clicks') { + return [true, Array(students).fill('col-12 col-lg-6 col-xxl-4'), 'col-xxl-9 col-lg-8 col-md-6']; + } + } + return [false, Array(students).fill('col-12 col-md-6 col-lg-4 col-xxl-3'), '']; + }, + + // TODO there is probably a better way to handle the following functions + // The following functions all do the same thing but with different values + // On the settings panel, they show or hide the sub-options for each option based on if the option is checked or not. + // Indicators options are shown vs. not + // [x] Indicators -> [] Indicators + // [x] Transitions -> + // [] Other -> + + // Output(indicator_collapse, 'is_open'), + // Input(checklist, 'value') + toggle_indicators_checklist: function(values) { + if (values.includes('indicators')) { + return true; + } + return false; + }, + + toggle_metrics_checklist: function(values) { + if (values.includes('metrics')) { + return true; + } + return false; + }, + + toggle_text_checklist: function(values) { + if (values.includes('text')) { + return true; + } + return false; + }, + + toggle_highlight_checklist: function(values) { + if (values.includes('highlight')) { + return true; + } + return false; + }, + + show_hide_data: function(values, metrics, text, highlights, indicators, students) { + // Change which items appear on the student cards + // The student card will only show elements whose id is in the `shown` property. + // Ids not included will not be shown + // + // All settings checklists/radioitems are combined into a single list and passed to all student cards + // + // Output({'type': student_card, 'index': ALL}, 'shown'), + // Input(settings.checklist, 'value'), + // Input(settings.metric_checklist, 'value'), + // Input(settings.text_radioitems, 'value'), + // Input(settings.highlight_checklist, 'value'), + // Input(settings.indicator_checklist, 'value'), + // State(student_counter, 'data') + const l = values.concat(metrics.map(x => `${x}_metric`)) + .concat(text) + .concat(highlights.map(x => `${x}_highlight`)) + .concat(indicators.map(x => `${x}_indicator`)); + return Array(students).fill(l); + }, + + update_students: async function(course_id) { + // Fetch the student information based on course id + + // Output(student_counter, 'data'), + // Output(student_store, 'data'), + // Input(course_store, 'data') + const response = await fetch(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/webapi/courseroster/${course_id}`); + const data = await response.json(); + return [data.length, data]; + }, + + fetch_assignment_info: async function(course_id, assignment_id) { + // Fetch assignment information from server based on course and assignment id + // Not yet implemented, TODO + // + // Output(assignment_name, 'children'), + // Output(assignment_desc, 'children'), + // Input(course_store, 'data'), + // Input(assignment_store, 'data') + return [`Assignment ${assignment_id}`, `This is assignment ${assignment_id} from course ${course_id}`] + }, + + update_course_assignment: function(hash) { + // Update the course and assignment info based on the hash query string + // + // Output(course_store, 'data'), + // Output(assignment_store, 'data'), + // Input('_pages_location', 'hash') + if (hash.length === 0) {return window.dash_clientside.no_update;} + const decoded = decode_string_dict(hash.slice(1)) + return [decoded.course_id, decoded.assignment_id] + }, + + highlight_text: function(overall_show, shown, data_trigger, options) { + // Highlights the text appropriately + // + // Output(settings.dummy, 'style'), + // Input(settings.checklist, 'value'), + // Input(settings.highlight_checklist, 'value'), + // Input({'type': student_card, 'index': ALL}, 'data'), + // State(settings.highlight_checklist, 'options') + + if (!overall_show.includes('highlight')) {return window.dash_clientside.no_update;} + const colors = [ + 'rgba(86, 204, 157, 0.25)', 'rgba(108, 195, 213, 0.25)', + 'rgba(255, 206, 103, 0.25)', 'rgba(255, 120, 81, 0.25)' + ]; + let docs = []; + const shown_colors = {}; + // remove all highlighting and record current colors + options.forEach(item => { + docs = document.getElementsByClassName(`${item.value}_highlight`); + if (shown.includes(item.value)) { + if (docs[0].style.backgroundColor.length > 0 & docs[0].style.backgroundColor !== 'transparent') { + shown_colors[item.value] = docs[0].style.backgroundColor; + } + } + for (var i = 0; i < docs.length; i++) { + docs[i].style.backgroundColor = 'transparent'; + } + }) + // highlight shown items + let high_color = ''; + shown.forEach(item => { + docs = document.getElementsByClassName(`${item}_highlight`); + // fetch current color or figure out a new one + if (shown_colors.hasOwnProperty(item)) { + high_color = shown_colors[item]; + } else { + let curr_colors = Object.values(shown_colors); + let remaining_colors = Array.from(new Set([...colors].filter(x => !curr_colors.includes(x)))); + high_color = (remaining_colors.length === 0 ? colors[Math.floor(Math.random()*colors.length)] : remaining_colors[0]) + shown_colors[item] = high_color; + } + + // add background color to highlighted elements + for (var i = 0; i < docs.length; i++) { + if (docs[i].style.backgroundColor.length > 0 & docs[i].style.backgroundColor !== 'transparent') { + let dc = getRGBAValues(docs[i].style.backgroundColor); + let hc = getRGBAValues(high_color); + let combined = `rgba(${parseInt((dc.r+hc.r)/2)}, ${parseInt((dc.g+hc.g)/2)}, ${parseInt((dc.b+hc.b)/2)}, ${hc.o+dc.o})`; + console.log(dc, hc, combined); + docs[i].style.backgroundColor = combined; + } else { + docs[i].style.backgroundColor = high_color; + } + } + }) + }, + + set_status: function(status) { + // Set the websocket status icon/title + // + // Output(websocket_status, 'className'), + // Output(websocket_status, 'title'), + // Input(websocket, 'state') + if (status === undefined) { + return window.dash_clientside.no_update; + } + else { const icons = ['fas fa-sync-alt', 'fas fa-check text-success', 'fas fa-sync-alt', 'fas fa-times text-danger']; + const titles = ['Connecting to server', 'Connected to server', 'Closing connection', 'Disconnected from server']; + return [icons[status.readyState], titles[status.readyState]]; + } + } +} From 8495df942e3059524524017e253fb3f102b50286 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 16 Dec 2022 01:01:22 -0500 Subject: [PATCH 303/327] Adding basic cleanup to roster.py to fix the camel-case/vs underscore inconsistency and adding a hack to address the naming conventions for the IDs from google users. --- .../learning_observer/dashboard.py | 2 + .../wo_dash/module.py | 61 ++++ .../wo_dash/pages/assignment_page/students.py | 301 ++++++++++++++++++ 3 files changed, 364 insertions(+) create mode 100644 learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/module.py create mode 100644 learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..8bb60a6e3 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,6 +322,8 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) + print("%%% ROSTER: ", roster) + # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is diff --git a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/module.py b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/module.py new file mode 100644 index 000000000..50af8b336 --- /dev/null +++ b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/module.py @@ -0,0 +1,61 @@ +import os.path +import sys + +import dash_bootstrap_components as dbc + +from learning_observer.dash_integration import thirdparty_url, static_url + +import wo_dash.pages.assignment_page.layout + +NAME = "Dash Writing Observer Prototype Dashboard" + +DASH_PAGES = [ + { + "MODULE": wo_dash.pages.assignment_page.layout, + "LAYOUT": wo_dash.pages.assignment_page.layout.layout, + "ASSETS": 'assets', + "TITLE": "Writing Observer Dashboard", + "DESCRIPTION": "Prototype Dashboard for the Writing Observer built with dash", + "SUBPATH": "dashboard", + "CSS": [ + thirdparty_url("css/bootstrap.min.css"), + thirdparty_url("css/fontawesome_all.css") + ], + "SCRIPTS": [ + static_url("liblo.js") + ] + } +] + +THIRD_PARTY = { + "css/bootstrap.min.css": { + "url": dbc.themes.MINTY, + "hash": "b361dc857ee7c817afa9c3370f1d317db2c4be5572dd5ec3171caeb812281" + "cf900a5a9141e5d6c7069408e2615df612fbcd31094223996154e16f2f80a348532" + }, + "css/fontawesome_all.css": { + "url": dbc.icons.FONT_AWESOME, + "hash": "535a5f3e40bc8ddf475b56c1a39a5406052b524413dea331c4e683ca99e39" + "6dbbc11fdce1f8355730a73c52ac6a1062de1938406c6af8e4361fd346106acb6b0" + }, + "webfonts/fa-solid-900.woff2": { + "url": os.path.dirname(os.path.dirname(dbc.icons.FONT_AWESOME))+"/webfonts/fa-solid-900.woff2", + "hash": "6d3fe769cc40a5790ea2e09fb775f1bd3b130d2fdae1dd552f69559e7ca4c" + "a047862f795da0024737e59e3bcc7446f6eec1bab173758aef0b97ba89d722ffbde" + }, + "webfonts/fa-solid-900.ttf": { + "url": os.path.dirname(os.path.dirname(dbc.icons.FONT_AWESOME))+"/webfonts/fa-solid-900.ttf", + "hash": "0fdd341671021d04304186c197001cf2e888d3028baaf9a5dec0f0e496959" + "666e8a2e34aae8e79904f8e9b4c0ccae40249897cce5f5ae58d12cc1b3985e588d6" + } +} + + +COURSE_DASHBOARDS = [{ + 'name': "Dash Writing Observer", + 'url': "/wo_dash/dash/dashboard/", + "icon": { + "type": "fas", + "icon": "fa-pen-nib" + } +}] diff --git a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py new file mode 100644 index 000000000..3de8fb85e --- /dev/null +++ b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py @@ -0,0 +1,301 @@ +''' +Creates the grid of student cards +''' +# package imports +from learning_observer.dash_wrapper import html, dcc, callback, clientside_callback, ClientsideFunction, Output, Input, State, ALL, exceptions as dash_e +import dash_bootstrap_components as dbc +from learning_observer_components import LOConnection +import learning_observer_components as loc # student cards + +# local imports +from . import settings, settings_defaults, settings_options as so + +# define ids for the dashboard +# use a prefix to help ensure we don't double up on IDs (guess what happens if you double up? it breaks) +prefix = 'teacher-dashboard' +student_card = f'{prefix}-student-card' # individual student card id +student_row = f'{prefix}-student-row' # overall student row +student_col = f'{prefix}-student-col' # individual student card wrapper id +student_grid = f'{prefix}-student-grid' # overall student grid wrapper id +websocket = f'{prefix}-websocket' # websocket to connect to the server (eventually) +student_counter = f'{prefix}-student-counter' # store item for quick access to the number of students +student_store = f'{prefix}-student-store' # store item for student information +course_store = f'{prefix}-course-store' # store item for course id +settings_collapse = f'{prefix}-settings-collapse' # settings menu wrapper +websocket_status = f'{prefix}-websocket-status' # websocket status icon +last_updated = f'{prefix}-last-updated' # data last updated id + +assignment_store = f'{prefix}-assignment-info_store' +assignment_name = f'{prefix}-assignment-name' +assignment_desc = f'{prefix}-assignment-description' + + +def student_dashboard_view(course_id, assignment_id): + '''Create student dashboard view, + + course_id: id of given course + assignment_id: id of assignment + ''' + container = dbc.Container( + [ + html.Div( + [ + # assignment title + html.H3( + [ + # document icon with a right bootstrap margin + html.I(className='fas fa-file-lines me-2'), + html.Span(id=assignment_name), + ], + className='d-inline' + ), + # open settings button + html.Div( + [ + settings.open_btn + ], + className='float-end' + ), + html.Br(), + # assignment description + html.P(id=assignment_desc) + ] + ), + html.Small( + [ + html.I(id=websocket_status), + html.Span('Last Updated: ', className='ms-1'), + html.Span(id=last_updated) + ] + ), + dbc.Row( + [ + # settings panel wrapper + dbc.Collapse( + dbc.Col( + settings.panel, + # bootstrap use 100% of (w)idth and (h)eight + class_name='w-100 h-100' + ), + id=settings_collapse, + # bootstrap collapse and grid sizing + class_name='collapse-horizontal col-xxl-3 col-lg-4 col-md-6', + # default open/close + is_open=False + ), + # overall student grid wrapp + dbc.Col( + dbc.Row( + id=student_row, + # bootstrap gutters-2 (little bit of space between cards) and w(idth)-100(%) + class_name='g-2 w-100' + ), + id=student_grid, + # classname set in callback, default classname should go in the callback + ) + ], + # no spacing between settings and students + # students already have some space on the sides + class_name='g-0' + ), + LOConnection(id=websocket), + # stores for course and student info + student counter + dcc.Store(id=course_store), + dcc.Store(id=assignment_store), + dcc.Store( + id=student_store, + data=[] + ), + dcc.Store( + id=student_counter, + data=0 + ) + ], + fluid=True + ) + return container + + +# set hash parameters +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='update_course_assignment'), + Output(course_store, 'data'), + Output(assignment_store, 'data'), + Input('_pages_location', 'hash') +) + +# set the websocket data_scope +clientside_callback( + """ + function(course, assignment) { + const ret = {"module": "latest_data", "course": course}; + return ret; + } + """, + Output(websocket, 'data_scope'), + Input(course_store, 'data'), + Input(assignment_store, 'data') +) + +# set the websocket status icon +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='set_status'), + Output(websocket_status, 'className'), + Output(websocket_status, 'title'), + Input(websocket, 'state') +) + +# fetch student info for course +# TODO fix this to pull the roster information better +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='update_students'), + Output(student_counter, 'data'), + Output(student_store, 'data'), + Input(course_store, 'data') +) + +# fetch assignment information from server +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='fetch_assignment_info'), + Output(assignment_name, 'children'), + Output(assignment_desc, 'children'), + Input(course_store, 'data'), + Input(assignment_store, 'data') +) + +# open the settings menu +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='open_settings'), + Output(settings_collapse, 'is_open'), + Output({'type': student_col, 'index': ALL}, 'class_name'), + Output(student_grid, 'class_name'), + Input(settings.open_btn, 'n_clicks'), + Input(settings.close_settings, 'n_clicks'), + State(settings_collapse, 'is_open'), + State(student_counter, 'data') +) + +# Update data from websocket +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='populate_student_data'), + Output({'type': student_card, 'index': ALL}, 'data'), + Output(last_updated, 'children'), + # Output(student_counter, 'data'), + # Output(student_store, 'data'), + Input(websocket, 'message'), + State({'type': student_card, 'index': ALL}, 'data'), + State(student_counter, 'data') +) + +# Sort students by indicator values +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='sort_students'), + Output({'type': student_col, 'index': ALL}, 'style'), + Input(settings.sort_by_checklist, 'value'), + Input(settings.sort_toggle, 'value'), + Input({'type': student_card, 'index': ALL}, 'data'), + State(settings.sort_by_checklist, 'options'), + State(student_counter, 'data') +) + +# hide/show attributes on student cards +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='show_hide_data'), + Output({'type': student_card, 'index': ALL}, 'shown'), + Input(settings.checklist, 'value'), + Input(settings.metric_checklist, 'value'), + Input(settings.text_radioitems, 'value'), + Input(settings.highlight_checklist, 'value'), + Input(settings.indicator_checklist, 'value'), + State(student_counter, 'data') +) + +# highlight text +clientside_callback( + ClientsideFunction(namespace='clientside', function_name='highlight_text'), + Output(settings.dummy, 'style'), + Input(settings.checklist, 'value'), + Input(settings.highlight_checklist, 'value'), + Input({'type': student_card, 'index': ALL}, 'data'), + State(settings.highlight_checklist, 'options') +) + + +@callback( + output=dict( + sort_by_options=Output(settings.sort_by_checklist, 'options'), + metric_options=Output(settings.metric_checklist, 'options'), + metric_value=Output(settings.metric_checklist, 'value'), + text_options=Output(settings.text_radioitems, 'options'), + text_value=Output(settings.text_radioitems, 'value'), + highlight_options=Output(settings.highlight_checklist, 'options'), + highlight_value=Output(settings.highlight_checklist, 'value'), + indicator_options=Output(settings.indicator_checklist, 'options'), + indicator_value=Output(settings.indicator_checklist, 'value'), + ), + inputs=dict( + course=Input(course_store, 'data'), + assignment=Input(assignment_store, 'data') + ) +) +def fill_in_settings(course, assignment): + # populate all settings based on assignment or default + + # TODO grab the options or type from assignment + # if options (obj) set opt to assignment options + # if type (string) set opt to settings_default.type + opt = settings_defaults.argumentative + + ret = dict( + sort_by_options=[so.sort_by_options[o] for o in opt['sort_by']['options']], + metric_options=[so.metric_options[o] for o in opt['metrics']['options']], + metric_value=opt['metrics']['selected'], + text_options=[so.text_options[o] for o in opt['text']['options']], + text_value=opt['text']['selected'], + highlight_options=[so.highlight_options[o] for o in opt['highlight']['options']], + highlight_value=opt['highlight']['selected'], + indicator_options=[so.indicator_options[o] for o in opt['indicators']['options']], + indicator_value=opt['indicators']['selected'], + ) + return ret + + +@callback( + Output(student_row, 'children'), + Input(student_store, 'data') +) +def create_cards(students): + # create student cards based on student info + + # TODO if the card data exists in the student_store, + # we want to include it in the initial loading of the card + # this will require the same parser we create for updates + # i.e. the same code for both js and python + cards = [ + dbc.Col( + loc.StudentOverviewCard( + # pattern matching callback + id={ + 'type': student_card, + 'index': s['user_id'] + }, + name=s['profile']['name']['full_name'], + data={ + 'id': s['user_id'], + 'text': {}, + 'highlight': {}, + 'metrics': {}, + 'indicators': {} + }, + shown=[], + # adds shadow on hover + class_name='shadow-card' + ), + # pattern matching callback + id={ + 'type': student_col, + 'index': s['user_id'] + }, + ) for s in students + ] + return cards From a8393b179f5dc46ecebe1e12168870f012d8bef2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 19 Dec 2022 00:27:35 -0500 Subject: [PATCH 304/327] Updated with upstream content and removed local debugging printing. --- learning_observer/learning_observer/creds.yaml.example | 4 ++++ learning_observer/learning_observer/dashboard.py | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/learning_observer/learning_observer/creds.yaml.example b/learning_observer/learning_observer/creds.yaml.example index 141afedf5..caf6ffabc 100644 --- a/learning_observer/learning_observer/creds.yaml.example +++ b/learning_observer/learning_observer/creds.yaml.example @@ -24,9 +24,13 @@ auth: token_uri: https://oauth2.googleapis.com/token auth_provider_x509_cert_url: https://www.googleapis.com/oauth2/v1/certs client_secret: {google-client-secret} +<<<<<<< HEAD javascript_origins: ["{url}"] # base_scopes: [] # We can override the scopes we ask Google for here # additional_scopes: [] # Or just add a few new ones. Not very tested. +======= + # javascript_origins: ["{url}"] +>>>>>>> 7a9315cf (Updated with upstream content and removed local debugging printing.) password_file: passwd.lo # Remove if you're not using a password file # Otherwise, create one with lo_passwd.py http_basic_auth: # HTTP auth. You probably want to remove this. diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 8bb60a6e3..290ab13a7 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -322,8 +322,6 @@ async def websocket_dashboard_view(request): roster = await rosters.courseroster(request, course_id) - print("%%% ROSTER: ", roster) - # If we're grabbing data for just one student, we filter the # roster down. This pathway ensures we only serve data for # students on a class roster. I'm not sure this API is From 5e732eea1bd7cbb5baf41f4b4fc4304777026812 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Sat, 17 Dec 2022 15:15:31 -0500 Subject: [PATCH 305/327] Add menu dropdown and status button --- .../wo_dash/pages/assignment_page/students.py | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py index 3de8fb85e..a228d6783 100644 --- a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py +++ b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py @@ -52,22 +52,33 @@ def student_dashboard_view(course_id, assignment_id): # open settings button html.Div( [ - settings.open_btn + dbc.Button( + [ + html.I(id=websocket_status), + html.Span('Last Updated: ', className='ms-2'), + html.Span(id=last_updated) + ], + outline=True, color="dark", className="me-2" + ), + settings.open_btn, + dbc.DropdownMenu( + [ + dbc.DropdownMenuItem( + "Logout", + href="/auth/logout", + ), + ], + label="Menu", + className="ms-2" + ) ], - className='float-end' + className='d-flex align-items-center float-end' ), html.Br(), # assignment description html.P(id=assignment_desc) ] ), - html.Small( - [ - html.I(id=websocket_status), - html.Span('Last Updated: ', className='ms-1'), - html.Span(id=last_updated) - ] - ), dbc.Row( [ # settings panel wrapper From e4ec78ea8aff99e9b3a466fdd3654bccfd91899f Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 23 Dec 2022 11:24:37 -0500 Subject: [PATCH 306/327] Add settings to dropdown menu --- .../wo_dash/pages/assignment_page/students.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py index a228d6783..75bc2fc77 100644 --- a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py +++ b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py @@ -60,9 +60,9 @@ def student_dashboard_view(course_id, assignment_id): ], outline=True, color="dark", className="me-2" ), - settings.open_btn, dbc.DropdownMenu( [ + settings.open_btn, dbc.DropdownMenuItem( "Logout", href="/auth/logout", From 4fc88966e8589b3048876b88c9fd77a48769d627 Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 23 Dec 2022 13:35:34 -0500 Subject: [PATCH 307/327] Update top-right button styles --- .../wo_dash/pages/assignment_page/students.py | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py index 75bc2fc77..09708b3c8 100644 --- a/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py +++ b/learning_observer/prototypes/dash_wo_teacher_dashboard/wo_dash/pages/assignment_page/students.py @@ -52,24 +52,29 @@ def student_dashboard_view(course_id, assignment_id): # open settings button html.Div( [ - dbc.Button( + dbc.ButtonGroup( [ - html.I(id=websocket_status), - html.Span('Last Updated: ', className='ms-2'), - html.Span(id=last_updated) - ], - outline=True, color="dark", className="me-2" - ), - dbc.DropdownMenu( - [ - settings.open_btn, - dbc.DropdownMenuItem( - "Logout", - href="/auth/logout", + dbc.Button( + [ + html.I(id=websocket_status), + html.Span('Last Updated: ', className='ms-2'), + html.Span(id=last_updated) + ], + outline=True, color="dark", className="" ), - ], - label="Menu", - className="ms-2" + dbc.DropdownMenu( + [ + settings.open_btn, + dbc.DropdownMenuItem( + "Logout", + href="/auth/logout", + ), + ], + group=True, + label="Menu", + className="btn-menu-outline-dark" + ) + ] ) ], className='d-flex align-items-center float-end' From 8fa88a1a5e53b9d200dc36588a010245d5eda5f6 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:28:04 -0500 Subject: [PATCH 308/327] Adding fix for last-doc align via the event-wrapper. --- .../writing_observer/event_wrapper.py | 88 +++++++++++++++++++ .../writing_observer/writing_analysis.py | 4 +- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py new file mode 100644 index 000000000..61cebe6fa --- /dev/null +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -0,0 +1,88 @@ +""" +event_wrapper.py +Collin F. Lynch +2022 + +A big part of this project is wrapping up google doc events. +In doing that we are reverse-engineering some of the elements +particularly the event types. This code provides some basic +wrappers for event types to simplify extraction of key elements +and to simplify event recognition. + +Over time this will likely expand and will need to adapt to keep +up with any changes in the event structure. For now it is just +a thin abstraction layer on a few of the pieces. +""" + + +# Imports +# -------------------------------- +import json + + + +# Basic class tests +# ------------------------------- +def is_visibility_eventp(event): + """ + Given an event return true if it is a visibility + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'visibility' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + +def is_keystroke_eventp(event): + """ + Given an event return true if it is a keystroke + event which indicates changing the doc shown or + active. + + Here we look for an event with 'client' + containing the field 'event_type' of + 'keystroke' + """ + Event_Type = event.get('client', {}).get('event', None) + return(Event_Type == 'visibility') + + + +# --------------------------------------- +# Extraction Methods + +def get_doc_id(event): + """ + Some of the event types (e.g. 'google_docs_save') have + a 'doc_id' which provides a link to the google document. + Others, notably the 'visibility' and 'keystroke' events + do not have doc_id but do have a link to an 'object' + field which in turn contains an 'id' field linking to + the google doc along with other features such as the + title. + + This method provides a simple abstraction that returns + the 'doc_id' value if it exists or returns the 'id' from + the 'object' field if this is a 'visibility' or 'keystroke' + event. + """ + + # Handle standard Doc_ID cases first. + Doc_ID = event.get('client', {}).get('doc_id', None) + if (Doc_ID != None): return(Doc_ID) + + # Handle cases where the object is encoded. For + # safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_ID = event.get('client', {}).get('object', {}).get('id', None) + return(Doc_ID) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 10689f129..4770dd242 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,6 +12,7 @@ import time import writing_observer.reconstruct_doc +import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration @@ -357,7 +358,8 @@ async def last_document(event, internal_state): print(">>> last_doc_call: ", event) - document_id = get_doc_id_wrapper(event) + #document_id = event.get('client', {}).get('doc_id', None) + document_id = writing_observer.event_wrapper.get_doc_id(event) print(">>> last_doc_call docid: ", document_id) From a67d9f4d5042d6a8c9782d526178e379ab72ee32 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 01:56:34 -0500 Subject: [PATCH 309/327] Adding minor fix to wrapper which should address some basic errors. --- .../writing_observer/event_wrapper.py | 32 +++++++++++++++++-- .../writing_observer/writing_analysis.py | 9 +++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 61cebe6fa..84e65a9e5 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -48,7 +48,7 @@ def is_keystroke_eventp(event): 'keystroke' """ Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') + return(Event_Type == 'keystroke') @@ -69,6 +69,11 @@ def get_doc_id(event): the 'doc_id' value if it exists or returns the 'id' from the 'object' field if this is a 'visibility' or 'keystroke' event. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. """ # Handle standard Doc_ID cases first. @@ -85,4 +90,27 @@ def get_doc_id(event): return(Doc_ID) # As a bottom out case we just return None. - + + + +def get_doc_title(event): + """ + The keystroke and visibility events provide a link to the + the document title under the 'object' field which will + be useful for pulling title information in later cases. + + NOTE: This change is based upon the (possibly faulty) + assumption that the object in keystroke and visibility + events is always a doc. The type field in the object + entry is uninformative in these cases. + """ + # For safety we only do this for cases where it is a + # keystroke or visibility item. + if (is_keystroke_eventp(event) + or is_visibility_eventp(event)): + + Doc_Title = event.get('client', {}).get('object', {}).get('title', None) + return(Doc_Title) + + # As a bottom out case we just return None. + diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index 4770dd242..dee0a7460 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -356,12 +356,11 @@ async def last_document(event, internal_state): model. ''' - print(">>> last_doc_call: ", event) - - #document_id = event.get('client', {}).get('doc_id', None) + # Initially this code looked only for cases where the document + # id was specified by a doc_id field. This fix uses the event + # wrapper methods to support access of IDs located in the + # doc_id field or in the 'object' field. document_id = writing_observer.event_wrapper.get_doc_id(event) - - print(">>> last_doc_call docid: ", document_id) if document_id is not None: state = {"document_id": document_id} From 0aa7d7edcb77bc15df07c2c2b174b2160afea70d Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 25 Dec 2022 23:15:27 -0500 Subject: [PATCH 310/327] Making a doc cleanup. --- modules/writing_observer/writing_observer/event_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py index 84e65a9e5..37f7649fb 100644 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ b/modules/writing_observer/writing_observer/event_wrapper.py @@ -12,6 +12,13 @@ Over time this will likely expand and will need to adapt to keep up with any changes in the event structure. For now it is just a thin abstraction layer on a few of the pieces. + +Clearly of course there are events at multiple levels of the system +this code is located within the writing_observer module at the +moment because it is exclusively concerned with visibiity events, +keystroke events, and other doc-specific tasks. A larger heirarchy +of event wrappers for different levels of the system may make sense +as time goes on. """ From e5c9825fa89d05f3eb553a920075b0f5defd5ddf Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:39:13 -0500 Subject: [PATCH 311/327] Updating writing analysis to better deal with event types. --- .../learning_observer/creds.yaml.example | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/learning_observer/learning_observer/creds.yaml.example b/learning_observer/learning_observer/creds.yaml.example index caf6ffabc..33d06c722 100644 --- a/learning_observer/learning_observer/creds.yaml.example +++ b/learning_observer/learning_observer/creds.yaml.example @@ -24,13 +24,9 @@ auth: token_uri: https://oauth2.googleapis.com/token auth_provider_x509_cert_url: https://www.googleapis.com/oauth2/v1/certs client_secret: {google-client-secret} -<<<<<<< HEAD javascript_origins: ["{url}"] # base_scopes: [] # We can override the scopes we ask Google for here # additional_scopes: [] # Or just add a few new ones. Not very tested. -======= - # javascript_origins: ["{url}"] ->>>>>>> 7a9315cf (Updated with upstream content and removed local debugging printing.) password_file: passwd.lo # Remove if you're not using a password file # Otherwise, create one with lo_passwd.py http_basic_auth: # HTTP auth. You probably want to remove this. @@ -91,7 +87,6 @@ event_auth: local_storage: userfile: students.yaml allow_guest: true -<<<<<<< HEAD # chromebook: # May be necessary to support execution on chromebooks. # allow_guest: true # uncomment for testing or deployment as needed. # testcase_auth: {} @@ -106,20 +101,3 @@ modules: writing_observer: use_nlp: false openai_api_key: '' # can also be set with OPENAI_API_KEY environment variable -======= - - # (CL) The lines below are necessary to allow the chrome extension - # to work. These should be included in future anonymous cases - # but may need to be changed depending upon the security model. - - # chromebook: - # allow_guest: true - # testcase_auth: {} - - -feature_flags: {} # For enabling / disabling features in development -server: - port: 8888 # Optional. Pick a different port. - - ->>>>>>> 6fb3752e (Added in missing documentation files from prior fork and added in scripts) From c42682ebc2102882c1393d144c47a9829b985160 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 01:52:39 -0500 Subject: [PATCH 312/327] Updating to deal with unrecognized last docs and moving event wrapper contents to writing analysis. --- .../writing_observer/event_wrapper.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 modules/writing_observer/writing_observer/event_wrapper.py diff --git a/modules/writing_observer/writing_observer/event_wrapper.py b/modules/writing_observer/writing_observer/event_wrapper.py deleted file mode 100644 index 37f7649fb..000000000 --- a/modules/writing_observer/writing_observer/event_wrapper.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -event_wrapper.py -Collin F. Lynch -2022 - -A big part of this project is wrapping up google doc events. -In doing that we are reverse-engineering some of the elements -particularly the event types. This code provides some basic -wrappers for event types to simplify extraction of key elements -and to simplify event recognition. - -Over time this will likely expand and will need to adapt to keep -up with any changes in the event structure. For now it is just -a thin abstraction layer on a few of the pieces. - -Clearly of course there are events at multiple levels of the system -this code is located within the writing_observer module at the -moment because it is exclusively concerned with visibiity events, -keystroke events, and other doc-specific tasks. A larger heirarchy -of event wrappers for different levels of the system may make sense -as time goes on. -""" - - -# Imports -# -------------------------------- -import json - - - -# Basic class tests -# ------------------------------- -def is_visibility_eventp(event): - """ - Given an event return true if it is a visibility - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'visibility' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'visibility') - - -def is_keystroke_eventp(event): - """ - Given an event return true if it is a keystroke - event which indicates changing the doc shown or - active. - - Here we look for an event with 'client' - containing the field 'event_type' of - 'keystroke' - """ - Event_Type = event.get('client', {}).get('event', None) - return(Event_Type == 'keystroke') - - - -# --------------------------------------- -# Extraction Methods - -def get_doc_id(event): - """ - Some of the event types (e.g. 'google_docs_save') have - a 'doc_id' which provides a link to the google document. - Others, notably the 'visibility' and 'keystroke' events - do not have doc_id but do have a link to an 'object' - field which in turn contains an 'id' field linking to - the google doc along with other features such as the - title. - - This method provides a simple abstraction that returns - the 'doc_id' value if it exists or returns the 'id' from - the 'object' field if this is a 'visibility' or 'keystroke' - event. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - - # Handle standard Doc_ID cases first. - Doc_ID = event.get('client', {}).get('doc_id', None) - if (Doc_ID != None): return(Doc_ID) - - # Handle cases where the object is encoded. For - # safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_ID = event.get('client', {}).get('object', {}).get('id', None) - return(Doc_ID) - - # As a bottom out case we just return None. - - - -def get_doc_title(event): - """ - The keystroke and visibility events provide a link to the - the document title under the 'object' field which will - be useful for pulling title information in later cases. - - NOTE: This change is based upon the (possibly faulty) - assumption that the object in keystroke and visibility - events is always a doc. The type field in the object - entry is uninformative in these cases. - """ - # For safety we only do this for cases where it is a - # keystroke or visibility item. - if (is_keystroke_eventp(event) - or is_visibility_eventp(event)): - - Doc_Title = event.get('client', {}).get('object', {}).get('title', None) - return(Doc_Title) - - # As a bottom out case we just return None. - From c2d026ac1047eb521a424d5b26b9cf0f7bb99c5c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:24:33 -0500 Subject: [PATCH 313/327] Updating running for observer server. --- servermanagement/RunLearningObserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index a6ad08bda..4a735eec4 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,3 +1,4 @@ + #!/usr/bin/env bash # =============================== # RunLearningObserver.sh From 4b53a11e4ae03e11776ea7a6289be47c0f3dc102 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Sun, 8 Jan 2023 02:28:49 -0500 Subject: [PATCH 314/327] Fixing minor error in writing analysis. --- modules/writing_observer/writing_observer/writing_analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/writing_observer/writing_observer/writing_analysis.py b/modules/writing_observer/writing_observer/writing_analysis.py index dee0a7460..bd14c2927 100644 --- a/modules/writing_observer/writing_observer/writing_analysis.py +++ b/modules/writing_observer/writing_observer/writing_analysis.py @@ -12,7 +12,6 @@ import time import writing_observer.reconstruct_doc -import writing_observer.event_wrapper import learning_observer.adapters import learning_observer.communication_protocol.integration From ec5f281b5b6ce8503ac15c2886ebb655acebb7e2 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 3 Mar 2023 12:52:01 -0500 Subject: [PATCH 315/327] Fixing minor spacing differences and removing bcrypt from requirements due to error. --- learning_observer/learning_observer/auth/social_sso.py | 1 - learning_observer/learning_observer/dashboard.py | 3 --- learning_observer/learning_observer/kvs.py | 2 -- learning_observer/learning_observer/rosters.py | 4 +--- .../wo_highlight_dashboard/assets/scripts.js | 1 - 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/learning_observer/learning_observer/auth/social_sso.py b/learning_observer/learning_observer/auth/social_sso.py index a15208373..a12657957 100644 --- a/learning_observer/learning_observer/auth/social_sso.py +++ b/learning_observer/learning_observer/auth/social_sso.py @@ -274,7 +274,6 @@ async def _google(request): async with aiohttp.ClientSession(loop=request.app.loop) as client: async with client.post(url, data=params) as resp: data = await resp.json() - assert 'access_token' in data, data # get user profile diff --git a/learning_observer/learning_observer/dashboard.py b/learning_observer/learning_observer/dashboard.py index 290ab13a7..7799773b4 100644 --- a/learning_observer/learning_observer/dashboard.py +++ b/learning_observer/learning_observer/dashboard.py @@ -208,7 +208,6 @@ async def student_state_fetcher(): ''' students = [] for student in roster: - student_state = { # We're copying Google's roster format here. # @@ -238,7 +237,6 @@ async def student_state_fetcher(): student_id = learning_observer.auth.google_id_to_user_id(google_id) else: student_id = google_id - # TODO: Evaluate whether this is a bottleneck. # # mget is faster than ~50 gets. But some online benchmarks show both taking @@ -347,7 +345,6 @@ async def websocket_dashboard_view(request): while True: sd = await student_state_fetcher() - data = { "student_data": sd # Per-student list } diff --git a/learning_observer/learning_observer/kvs.py b/learning_observer/learning_observer/kvs.py index b4a35ae98..325c7b8d8 100644 --- a/learning_observer/learning_observer/kvs.py +++ b/learning_observer/learning_observer/kvs.py @@ -65,7 +65,6 @@ async def multiget(self, keys): ''' return [await self[key] for key in keys] - async def load(self, filename): ''' Loads the contents of a JSON object into the KVS. @@ -149,7 +148,6 @@ async def __getitem__(self, key): >> await kvs['item'] ''' - await self.connect() item = await learning_observer.redis_connection.get(key) if item is not None: diff --git a/learning_observer/learning_observer/rosters.py b/learning_observer/learning_observer/rosters.py index 3456de378..ff13909f9 100644 --- a/learning_observer/learning_observer/rosters.py +++ b/learning_observer/learning_observer/rosters.py @@ -114,7 +114,6 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): - We often want some default if that field is missing (`default`) - We often want the response sensibly sorted (`sort_key`) ''' - # Convert errors into appropriate codes for clients # Typically, resp_json['error'] == 'UNAUTHENTICATED' if 'error' in resp_json: @@ -144,8 +143,7 @@ def clean_google_ajax_data(resp_json, key, sort_key, default=None, source=None): # Sort the list if sort_key is not None: resp_json.sort(key=sort_key) - - + return resp_json diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js index 8db2fa014..32a8d713b 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/assets/scripts.js @@ -155,7 +155,6 @@ window.dash_clientside.clientside = { if (!msg) { return [prev_metrics, prev_text, prev_highlights, prev_indicators, [], -1, 0]; } - console.log(JSON.parse(msg.data)); let updates = Array(students).fill(window.dash_clientside.no_update); const data = JSON.parse(msg.data)['docs_with_nlp']['nlp_combined']; for (let i = 0; i < data.length; i++) { From 6681c3e2aeea00cd3fbcd9854c9a112d2dfb909a Mon Sep 17 00:00:00 2001 From: JohnDamilola Date: Fri, 3 Mar 2023 08:43:46 -0500 Subject: [PATCH 316/327] Fix content script unload/reload --- extension/extension/background.js | 22 ++++++++++++++++++---- extension/extension/manifest.json | 6 +++--- extension/writing-process/src/writing.js | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/extension/extension/background.js b/extension/extension/background.js index 00709c2f7..91caceda0 100644 --- a/extension/extension/background.js +++ b/extension/extension/background.js @@ -408,11 +408,25 @@ chrome.webRequest.onBeforeRequest.addListener( // https://stackoverflow.com/questions/10994324/chrome-extension-content-script-re-injection-after-upgrade-or-install chrome.runtime.onInstalled.addListener(async () => { - for (const cs of chrome.runtime.getManifest().content_scripts) { - for (const tab of await chrome.tabs.query({url: cs.matches})) { + for (const contentScript of chrome.runtime.getManifest().content_scripts) { + for (const tab of await chrome.tabs.query({url: contentScript.matches})) { + // Unload the dead content script by removing its code from the page chrome.scripting.executeScript({ - target: {tabId: tab.id}, - files: cs.js, + target: { tabId: tab.id, allFrames: true }, + func: function() { + var scripts = document.getElementsByTagName('script'); + for(var i = scripts.length - 1; i >= 0; i--) { + if(scripts[i].src === `chrome-extension://${chrome.runtime.id}/writing.js`) { + scripts[i].remove(); + } + } + } + }); + + // re-inject content script + chrome.scripting.executeScript({ + target: {tabId: tab.id, allFrames: true}, + files: contentScript.js, }); } } diff --git a/extension/extension/manifest.json b/extension/extension/manifest.json index 0f95451f2..578ed4f1c 100644 --- a/extension/extension/manifest.json +++ b/extension/extension/manifest.json @@ -15,10 +15,10 @@ } }, "content_scripts": [{ - "matches": ["*://docs.google.com/*"], + "matches": ["*://docs.google.com/document/*"], "js": ["3rdparty/sha256.js", "writing_common.js", "writing.js"] }], - "web_accessible_resources": [{ + "web_accessible_resources": [{ "resources": ["inject.js"], "matches": ["*://docs.google.com/*"], "use_dynamic_url": true @@ -37,7 +37,7 @@ "activeTab" ], "host_permissions": [ - "*://docs.google.com/*" + "*://docs.google.com/document/*" ], "icons": { "48": "icons/lousy-fountain-pen-48.png" diff --git a/extension/writing-process/src/writing.js b/extension/writing-process/src/writing.js index 028a5dd1a..913c91794 100644 --- a/extension/writing-process/src/writing.js +++ b/extension/writing-process/src/writing.js @@ -112,7 +112,7 @@ function google_docs_partial_text() { reconstructing text. */ try { - return document.getElementsByClassName("kix")[0].innerText; + return document.getElementsByClassName("kix-page")[0].innerText; } catch(error) { log_error("Could not get document text"); return null; From 3fe6af7455a03efaae9409b41769cef529c65924 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 16 Mar 2023 14:01:45 -0400 Subject: [PATCH 317/327] Making minor fix in module loading for new libraries. --- .../wo_highlight_dashboard/module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index cbf8b1f8e..4a4008990 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,6 +23,18 @@ } ] +# Third party module tests with helpful messages. +Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' +if (dbc.themes.MINTY != Minty_URL): + print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) + print("You will need to update dash bootstrap components hash value.\n") + +FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" +if (dbc.icons.FONT_AWESOME != FontAwesome_URL): + print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) + print("You will need to update the FontAwesome bootstrap components hash value.\n") + + THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, From dcd9615814522a9ec4141bf37cbd1cdbb3ee58b1 Mon Sep 17 00:00:00 2001 From: John Damilola Date: Fri, 14 Apr 2023 09:54:34 -0400 Subject: [PATCH 318/327] Fix extension bugs (#76) * Add config variables to initialize service worker * Revert back without loadConfig wrapper * Fix "reinjecting content scripts" bug * Add 'event_type' to the events object --- extension/extension/background.js | 49 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/extension/extension/background.js b/extension/extension/background.js index 91caceda0..f08d3cb29 100644 --- a/extension/extension/background.js +++ b/extension/extension/background.js @@ -6,6 +6,8 @@ Background script. This works across all of Google Chrome. // should be a cookie or browser.storage? var RAW_DEBUG = false; +// Manually update this variable before upload to Google store +var WEBSOCKET_SERVER_URL = "wss://observer.csc.ncsu.edu/wsapi/in/" /* TODO: FSM @@ -53,6 +55,11 @@ function add_event_metadata(event_type, event) { */ event['event'] = event_type; + // Add the event_type if not present + if (!event.hasOwnProperty('event_type')) { + event['event_type'] = event_type; + } + event['source'] = 'org.mitros.writing_analytics'; event['version'] = 'alpha'; event['ts'] = Date.now(); @@ -213,13 +220,14 @@ loggers_enabled = [ websocket_logger("wss://localhost/wsapi/in/") ]; */ + let loggers_enabled = [ console_logger(), //ajax_logger("https://writing.learning-observer.org/webapi/")//, + // Adapted to NCSU Setup. - websocket_logger("wss://observer.csc.ncsu.edu/wsapi/in/") - //websocket_logger("wss://writing.learning-observer.org/wsapi/in/") + websocket_logger(WEBSOCKET_SERVER_URL) ]; function log_event(event_type, event) { @@ -406,31 +414,22 @@ chrome.webRequest.onBeforeRequest.addListener( // re-injected scripts when chrome extension is reloaded, upgraded or re-installed // https://stackoverflow.com/questions/10994324/chrome-extension-content-script-re-injection-after-upgrade-or-install - -chrome.runtime.onInstalled.addListener(async () => { - for (const contentScript of chrome.runtime.getManifest().content_scripts) { - for (const tab of await chrome.tabs.query({url: contentScript.matches})) { - // Unload the dead content script by removing its code from the page - chrome.scripting.executeScript({ - target: { tabId: tab.id, allFrames: true }, - func: function() { - var scripts = document.getElementsByTagName('script'); - for(var i = scripts.length - 1; i >= 0; i--) { - if(scripts[i].src === `chrome-extension://${chrome.runtime.id}/writing.js`) { - scripts[i].remove(); - } - } +chrome.runtime.onInstalled.addListener(reinjectContentScripts); +async function reinjectContentScripts() { + for (const contentScript of chrome.runtime.getManifest().content_scripts) { + for (const tab of await chrome.tabs.query({url: contentScript.matches})) { + // re-inject content script + await chrome.scripting.executeScript({ + target: {tabId: tab.id, allFrames: true}, + files: contentScript.js, + }, function () { + if (!chrome.runtime.lastError) { + console.log('Content script re-injected successfully'); + } + }); } - }); - - // re-inject content script - chrome.scripting.executeScript({ - target: {tabId: tab.id, allFrames: true}, - files: contentScript.js, - }); } - } -}); +} // Let the server know we've loaded. log_event("extension_loaded", {}); From 9f0ede7188639ad66eb9ff1c01cba77f854b5055 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Mon, 22 May 2023 20:31:22 -0400 Subject: [PATCH 319/327] Fixing the manifest issue for permissions. (#81) * Fixing the manifest issue for permissions. * Fixing manifest to reflect new version and to remove permissions that we do not make use of. --- extension/extension/background.js | 7 +++++-- extension/extension/manifest.json | 4 +--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/extension/extension/background.js b/extension/extension/background.js index f08d3cb29..c4fa4b91e 100644 --- a/extension/extension/background.js +++ b/extension/extension/background.js @@ -6,8 +6,11 @@ Background script. This works across all of Google Chrome. // should be a cookie or browser.storage? var RAW_DEBUG = false; -// Manually update this variable before upload to Google store -var WEBSOCKET_SERVER_URL = "wss://observer.csc.ncsu.edu/wsapi/in/" +/* This variable must be manually updated to specify the server that + * the data will be sent to. +*/ +var WEBSOCKET_SERVER_URL = "wss://learning-observer.org/wsapi/in/" + /* TODO: FSM diff --git a/extension/extension/manifest.json b/extension/extension/manifest.json index 578ed4f1c..0ebb21523 100644 --- a/extension/extension/manifest.json +++ b/extension/extension/manifest.json @@ -5,7 +5,7 @@ "homepage_url": "https://github.com/ETS-Next-Gen/writing_observer", "incognito": "not_allowed", "offline_enabled": true, - "version": "0.0.0.1", + "version": "1.0.0.2", "description": "Tracks writing in Google Docs, and provides nifty insights to you and your teachers!", "action": { "default_title": "Writing Process", @@ -28,11 +28,9 @@ }, "permissions": [ "webRequest", - "declarativeNetRequest", "identity", "identity.email", "storage", - "nativeMessaging", "scripting", "activeTab" ], From 6b7926ee4c930fb67dd022a475668c1f4c36899e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 25 May 2023 22:56:21 -0400 Subject: [PATCH 320/327] Cleaning up minor differences after rebase. --- .../wo_highlight_dashboard/dashboard/students.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py index fa798188c..0aa405fce 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/dashboard/students.py @@ -120,7 +120,6 @@ def student_dashboard_view(course_id, assignment_id): ), dbc.DropdownMenu( [ - settings.open_btn, dbc.DropdownMenuItem( 'Settings', id=settings.open_btn From 78e33a5c8d930aa7138a9a409291e97df3d58709 Mon Sep 17 00:00:00 2001 From: Sarthak Babbar Date: Thu, 8 Jun 2023 14:46:16 -0400 Subject: [PATCH 321/327] Caching Initial Commit (#80) * Caching Version 0 Initial Commit * Caching Version 0 Initial Commit With Fixes * Caching Version 0 Initial Commit With Fixes * Caching Version 0 Initial Commit With Fixes * Refactoring Caching Code * Modularize Caching function, add helper functions to util.py * Improve modularization and reducing dirty reads. * Renamed functions & variables, added parameter definitions * Reduce gap between cache read and write * Remove blank lines --------- Co-authored-by: Bradley Erickson --- modules/writing_observer/writing_observer/aggregator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 4674f53c4..530b244bd 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -14,6 +14,7 @@ import learning_observer.kvs import learning_observer.settings import learning_observer.stream_analytics.helpers +# import traceback import learning_observer.util pmss.register_field( From 8893b1a574e8a6cffdca230640bce3e9eeb32e7e Mon Sep 17 00:00:00 2001 From: DrLynch Date: Tue, 27 Jun 2023 22:27:04 -0400 Subject: [PATCH 322/327] Lo components fix (#96) * Adding installation for the lo_dash_react_components module. * Fixing minor error in installation script. * Fixing module structure with additional versions. * Fixing doc ID error. * Fixing student/data merge issues and aggregation for WO. --------- Co-authored-by: DrLynch --- .../wo_highlight_dashboard/module.py | 12 ------------ servermanagement/AddWOtoVENV.sh | 2 -- 2 files changed, 14 deletions(-) diff --git a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py index 4a4008990..cbf8b1f8e 100644 --- a/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py +++ b/modules/wo_highlight_dashboard/wo_highlight_dashboard/module.py @@ -23,18 +23,6 @@ } ] -# Third party module tests with helpful messages. -Minty_URL = 'https://cdn.jsdelivr.net/npm/bootswatch@5.1.3/dist/minty/bootstrap.min.css' -if (dbc.themes.MINTY != Minty_URL): - print("WARN:: Unrecognized Minty URL detected: {}".format(dbc.themes.MINTY)) - print("You will need to update dash bootstrap components hash value.\n") - -FontAwesome_URL = "https://use.fontawesome.com/releases/v6.3.0/css/all.css" -if (dbc.icons.FONT_AWESOME != FontAwesome_URL): - print("WARN:: Unrecognized Fontawesome URL detected: {}".format(dbc.icons.FONT_AWESOME)) - print("You will need to update the FontAwesome bootstrap components hash value.\n") - - THIRD_PARTY = { "css/bootstrap.min.css": d.BOOTSTRAP_MIN_CSS, "css/fontawesome_all.css": d.FONTAWESOME_CSS, diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 78d89ee4c..8b345330b 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -61,8 +61,6 @@ cd .. "$PIP_CMD" install -r requirements.txt - - echo -e "\n=== Installing Learning Observer ===" cd learning_observer "$PYTHON_CMD" setup.py develop From 3287211c5e0bd9b3c99d2937d3c16e6550448cd4 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Thu, 11 Jul 2024 00:42:02 -0400 Subject: [PATCH 323/327] Updated with local changes. --- learning_observer/learning_observer/google.py | 4 ++-- learning_observer/learning_observer/main.py | 8 ++++++++ modules/writing_observer/writing_observer/aggregator.py | 4 ---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/learning_observer/learning_observer/google.py b/learning_observer/learning_observer/google.py index 6d9ecded0..2c8fa41c1 100644 --- a/learning_observer/learning_observer/google.py +++ b/learning_observer/learning_observer/google.py @@ -184,8 +184,8 @@ def initialize_and_register_routes(app): # # For now, all of this is behind one big feature flag. In the future, # # we'll want seperate ones for the debugging tools and the production # # staff - # if 'google_routes' not in settings.settings['feature_flags']: - # return + if 'google_routes' not in settings.settings['feature_flags']: + return for key in ['save_google_ajax', 'use_google_ajax', 'save_clean_ajax', 'use_clean_ajax']: if key in settings.settings['feature_flags']: diff --git a/learning_observer/learning_observer/main.py b/learning_observer/learning_observer/main.py index 17486aa21..1af839012 100644 --- a/learning_observer/learning_observer/main.py +++ b/learning_observer/learning_observer/main.py @@ -50,6 +50,14 @@ # Run argparse args = settings.parse_and_validate_arguments() +# This will need to move but for the moment we hack with +# this to prefer the GPU where possible. +import spacy +#spacy.prefer_gpu() +#debug_log("Preferring GPU Use.") +spacy.require_gpu() +debug_log("Preferring GPU Use.") + def configure_event_loop(): ''' diff --git a/modules/writing_observer/writing_observer/aggregator.py b/modules/writing_observer/writing_observer/aggregator.py index 530b244bd..a866d778f 100644 --- a/modules/writing_observer/writing_observer/aggregator.py +++ b/modules/writing_observer/writing_observer/aggregator.py @@ -207,10 +207,6 @@ async def get_latest_student_documents(student_data): # Now insert the student data and pass it along. doc['student'] = student writing_data.append(doc) - - # Now insert the student data and pass it along. - doc['student'] = student - writing_data.append(doc) print(writing_data) From 260e1acaeff4e0e2c7fab05d151e96b0b330b002 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Wed, 24 Jul 2024 02:27:27 -0400 Subject: [PATCH 324/327] Merging in latest upstream --- learning_observer/learning_observer/google.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/learning_observer/learning_observer/google.py b/learning_observer/learning_observer/google.py index 2c8fa41c1..6d9ecded0 100644 --- a/learning_observer/learning_observer/google.py +++ b/learning_observer/learning_observer/google.py @@ -184,8 +184,8 @@ def initialize_and_register_routes(app): # # For now, all of this is behind one big feature flag. In the future, # # we'll want seperate ones for the debugging tools and the production # # staff - if 'google_routes' not in settings.settings['feature_flags']: - return + # if 'google_routes' not in settings.settings['feature_flags']: + # return for key in ['save_google_ajax', 'use_google_ajax', 'save_clean_ajax', 'use_clean_ajax']: if key in settings.settings['feature_flags']: From 4c23fed5693f09597bc5af9937dd171a04c56f46 Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 26 Jul 2024 04:22:15 -0400 Subject: [PATCH 325/327] Adding changes to smooth install for full packages. --- servermanagement/AddWOtoVENV.sh | 36 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/servermanagement/AddWOtoVENV.sh b/servermanagement/AddWOtoVENV.sh index 8b345330b..c01876634 100755 --- a/servermanagement/AddWOtoVENV.sh +++ b/servermanagement/AddWOtoVENV.sh @@ -42,17 +42,17 @@ source "$VIRTUAL_ENV/bin/activate" # # Note that by default we seem to be unable to rely # on spacy to pull the right cuda on its own -echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" -echo -e "\n Using CUDA v. 117" -"$PIP_CMD" install spacy[cuda117] +#echo -e "\n=== Installing Spacy CUDA, comment out if not needed. ===" +#echo -e "\n Using CUDA v. 117" +#"$PIP_CMD" install spacy[cuda117] # If you are using cuda 12.1 as we are on some # systems then spacy's passthrough install will # not work. Therefore you will need a two-step # process. -#echo -e "\n Using CUDA v. 12.x" -#"$PIP_CMD" install cupy-cuda12x -#"$PIP_CMD" install spacy[cuda12x] +echo -e "\n Using CUDA v. 12.x" +"$PIP_CMD" install cupy-cuda12x +"$PIP_CMD" install spacy[cuda12x] # Install basic requirements. @@ -60,10 +60,13 @@ echo -e "\n=== Installing Requirements.txt ===" cd .. "$PIP_CMD" install -r requirements.txt - echo -e "\n=== Installing Learning Observer ===" -cd learning_observer -"$PYTHON_CMD" setup.py develop +make install +#cd learning_observer +#"$PYTHON_CMD" setup.py develop + +pip install --upgrade spacy[cuda12x] +pip install --upgrade pydantic echo -e "\n=== Installing Modules ===" @@ -76,6 +79,9 @@ cd .. echo -e "\n--- Installing lo_dash_react_components. ---" cd ./lo_dash_react_components +nvm install +nvm use +npm install "$PYTHON_CMD" setup.py develop pip install . cd .. @@ -86,6 +92,18 @@ cd ./wo_highlight_dashboard cd .. +echo -e "\n--- Installing common student errors. ---" +cd ./wo_common_student_errors +"$PYTHON_CMD" setup.py develop +cd .. + + +echo -e "\n--- Installing bulk analysius (askGPT). ---" +cd ./wo_bulk_essay_analysis +"$PYTHON_CMD" setup.py develop +cd .. + + From 375ef07ddeb6d68e0c6e93482d29e0a5a8f827fc Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 26 Jul 2024 04:32:25 -0400 Subject: [PATCH 326/327] Making minor change to require GPU. --- learning_observer/learning_observer/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learning_observer/learning_observer/main.py b/learning_observer/learning_observer/main.py index 1af839012..b9dc315c9 100644 --- a/learning_observer/learning_observer/main.py +++ b/learning_observer/learning_observer/main.py @@ -56,7 +56,7 @@ #spacy.prefer_gpu() #debug_log("Preferring GPU Use.") spacy.require_gpu() -debug_log("Preferring GPU Use.") +debug_log("Requiring GPU Use.") def configure_event_loop(): From b6e94ab75ff5ef70725723ea535c783f531d537c Mon Sep 17 00:00:00 2001 From: DrLynch Date: Fri, 25 Oct 2024 00:04:41 -0400 Subject: [PATCH 327/327] Lynch/processorupdate (#122) --- servermanagement/RunLearningObserver.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/servermanagement/RunLearningObserver.sh b/servermanagement/RunLearningObserver.sh index 4a735eec4..a91f46ccd 100755 --- a/servermanagement/RunLearningObserver.sh +++ b/servermanagement/RunLearningObserver.sh @@ -1,4 +1,3 @@ - #!/usr/bin/env bash # =============================== # RunLearningObserver.sh @@ -13,23 +12,32 @@ # System Variables # -------------------------------------- -VIRTUALENV_PATH="/usr/local/share/projects/WritingObserver/VirtualENVs/WOvenv" +VIRTUALENV_PATH="/usr/local/share/projects/WritingObserver/VENV/WOVenv" #VIRTUALENV_PYTHON="/usr/local/share/Projects/WritingObserver/VirtualENVs/learning_observer/bin/python3.9" LEARNING_OBSERVER_LOC="/usr/local/share/projects/WritingObserver/Repositories/ArgLab_writing_observer/learning_observer" LOGFILE_DEST="/usr/local/share/projects/WritingObserver/Repositories/ArgLab_writing_observer/learning_observer/learning_observer/logs" + # Make the logfile name # --------------------------------------- LOG_DATE=$(date "+%m-%d-%Y--%H-%M-%S") LOGFILE_NAME="$LOGFILE_DEST/learning_observer_service_$LOG_DATE.log" echo $LOG_NAME; - +DOC_PROCESSOR_LOG="$LOGFILE_DEST/document_processor_service_$LOG_DATE.log" +echo $DOC_PROCESSOR_LOG; + # Now run the thing. # -------------------------------------- echo "Running Learning Observer Service..." cd $LEARNING_OBSERVER_LOC + source $VIRTUALENV_PATH/bin/activate + +nohup python learning_observer/doc_processor.py > $DOC_PROCESSOR_LOG 2>&1 & +DOC_PROCESS_ID=$! +echo $DOC_PROCESS_ID > $LOGFILE_DEST/doc_run.pid + nohup python learning_observer > $LOGFILE_NAME 2>&1 & PROCESS_ID=$! echo $PROCESS_ID > $LOGFILE_DEST/run.pid