From 227a26f5921caee99deb887bb29e50524a98eae8 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Wed, 26 Jan 2022 20:02:19 +0100 Subject: [PATCH 01/23] Readd launch cancel button Signed-off-by: Paul Bui-Quang --- webapp/src/components/SingleStudy/TaskView.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webapp/src/components/SingleStudy/TaskView.tsx b/webapp/src/components/SingleStudy/TaskView.tsx index da077471f5..4c03b9c98b 100644 --- a/webapp/src/components/SingleStudy/TaskView.tsx +++ b/webapp/src/components/SingleStudy/TaskView.tsx @@ -230,8 +230,7 @@ const TaskView = (props: PropTypes) => { {t('singlestudy:taskStatus')} {item.status} - {/* item.status === 'running' ? : */} - + {item.status === 'running' ? : } From f01fcf835401c33cafa87963bca5449aae62f25e Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Thu, 27 Jan 2022 15:13:22 +0100 Subject: [PATCH 02/23] Fix delete area command apply (delete link property) Signed-off-by: Paul Bui-Quang --- .../study/storage/variantstudy/model/command/remove_area.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/antarest/study/storage/variantstudy/model/command/remove_area.py b/antarest/study/storage/variantstudy/model/command/remove_area.py index 6237318c42..a0d4436399 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_area.py +++ b/antarest/study/storage/variantstudy/model/command/remove_area.py @@ -151,6 +151,9 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: study_data.tree.delete( ["input", "links", area_name, self.id] ) + study_data.tree.delete( + ["input", "links", area_name, "properties", self.id] + ) new_area_data: JSON = { "input": { From f6b55ffa8564acb7bcff7134c75d30e628fab6ed Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 31 Jan 2022 13:24:55 +0100 Subject: [PATCH 03/23] Remove maintenance mode and message init fetch Signed-off-by: Paul Bui-Quang --- webapp/src/services/utils/globalWsListeners.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/webapp/src/services/utils/globalWsListeners.ts b/webapp/src/services/utils/globalWsListeners.ts index 39a5739a2f..0b0b071151 100644 --- a/webapp/src/services/utils/globalWsListeners.ts +++ b/webapp/src/services/utils/globalWsListeners.ts @@ -4,7 +4,7 @@ import { getStudyMetadata } from '../api/study'; import { StudySummary, WSEvent, WSMessage } from '../../common/types'; import { addListenerAction, refreshHandlerAction } from '../../ducks/websockets'; import { AppState } from '../../App/reducers'; -import { getMaintenanceStatus, getInitMessageInfo, isStringEmpty } from '.'; +import { isStringEmpty } from '.'; import { setMaintenanceMode, setMessageInfo } from '../../ducks/global'; const studyListener = (reduxStore: Store) => async (ev: WSMessage): Promise => { @@ -43,12 +43,6 @@ export const addWsListeners = async (reduxStore: Store): Promise reduxStore.dispatch(addListenerAction(studyListener(reduxStore))); reduxStore.dispatch(addListenerAction(maintenanceListener(reduxStore))); reduxStore.dispatch(refreshHandlerAction()); - - const initMaintenanceMode = await getMaintenanceStatus(); - reduxStore.dispatch(setMaintenanceMode(initMaintenanceMode)); - - const initMessageInfo = await getInitMessageInfo(); - reduxStore.dispatch(setMessageInfo(initMessageInfo)); }; export default {}; From f5a957431026d0249e29bf31f9f0cac362baa5c2 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 31 Jan 2022 13:25:17 +0100 Subject: [PATCH 04/23] Update version Signed-off-by: Paul Bui-Quang --- antarest/__init__.py | 2 +- setup.py | 2 +- sonar-project.properties | 2 +- webapp/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/antarest/__init__.py b/antarest/__init__.py index f8ddd53661..7d2de2d731 100644 --- a/antarest/__init__.py +++ b/antarest/__init__.py @@ -1,4 +1,4 @@ -__version__ = "2.2.3" +__version__ = "2.2.4" from pathlib import Path diff --git a/setup.py b/setup.py index 2a0be68fd8..5dfa8622bb 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="AntaREST", - version="2.2.3", + version="2.2.4", description="Antares Server", long_description=long_description, long_description_content_type="text/markdown", diff --git a/sonar-project.properties b/sonar-project.properties index 8405ce4baf..30386dd3c6 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -4,4 +4,4 @@ sonar.sources=antarest sonar.language=python sonar.exclusions=antarest/gui.py,antarest/main.py sonar.python.coverage.reportPaths=coverage.xml -sonar.projectVersion=2.2.3 \ No newline at end of file +sonar.projectVersion=2.2.4 \ No newline at end of file diff --git a/webapp/package.json b/webapp/package.json index 847750e256..3ab5e61aff 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "antares-web", - "version": "2.2.3", + "version": "2.2.4", "private": true, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.36", From 5782cff825512f474843d2774888b4736cd0d508 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 31 Jan 2022 14:51:12 +0100 Subject: [PATCH 05/23] Remove unecessary useEffect dep Signed-off-by: Paul Bui-Quang --- webapp/src/App/MaintenanceWrapper/MessageInfoModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/App/MaintenanceWrapper/MessageInfoModal.tsx b/webapp/src/App/MaintenanceWrapper/MessageInfoModal.tsx index 4eae02dc72..5ee884aa9b 100644 --- a/webapp/src/App/MaintenanceWrapper/MessageInfoModal.tsx +++ b/webapp/src/App/MaintenanceWrapper/MessageInfoModal.tsx @@ -103,7 +103,7 @@ const MessageInfoModal = (props: PropTypes) => { } }; init(); - }, [enqueueSnackbar, setMessage, t, user]); + }, [enqueueSnackbar, setMessage, t]); useEffect(() => { if (messageInfo !== undefined && messageInfo !== '' && (user === undefined || !isUserAdmin(user))) setOpen(true); From 9c3340923996d1ad51b68782f5ced7e897e4f88c Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 31 Jan 2022 16:42:22 +0100 Subject: [PATCH 06/23] Update dependencies (#728) --- antarest/core/requests.py | 2 +- antarest/login/web.py | 2 +- antarest/study/service.py | 2 +- .../filesystem/matrix/input_series_matrix.py | 1 + .../filesystem/matrix/output_series_matrix.py | 8 ++- antarest/study/web/studies_blueprint.py | 2 +- antarest/tools/cli.py | 32 +++++------ pyproject.toml | 7 ++- requirements-dev.txt | 11 ++-- requirements-test.txt | 2 +- requirements.txt | 56 +++++++++---------- setup.cfg | 3 - .../model/command/test_update_comments.py | 19 ++----- 13 files changed, 70 insertions(+), 77 deletions(-) diff --git a/antarest/core/requests.py b/antarest/core/requests.py index 6ba7b879c5..b224b4de4a 100644 --- a/antarest/core/requests.py +++ b/antarest/core/requests.py @@ -2,7 +2,7 @@ from typing import Optional from fastapi import HTTPException -from markupsafe import escape # type: ignore +from markupsafe import escape from antarest.core.jwt import JWTUser diff --git a/antarest/login/web.py b/antarest/login/web.py index e9a92cad6a..fa5a05e540 100644 --- a/antarest/login/web.py +++ b/antarest/login/web.py @@ -5,7 +5,7 @@ from fastapi import Depends, APIRouter, HTTPException from fastapi_jwt_auth import AuthJWT # type: ignore -from markupsafe import escape # type: ignore +from markupsafe import escape from pydantic import BaseModel from antarest.core.config import Config diff --git a/antarest/study/service.py b/antarest/study/service.py index 7e2249a0c7..7e37e8a441 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -10,7 +10,7 @@ from uuid import uuid4 from fastapi import HTTPException -from markupsafe import escape # type: ignore +from markupsafe import escape from antarest.core.config import Config from antarest.core.filetransfer.model import ( diff --git a/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py b/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py index 1ed4b5f1bc..ebd31795e5 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py +++ b/antarest/study/storage/rawstudy/model/filesystem/matrix/input_series_matrix.py @@ -42,6 +42,7 @@ def parse( sep="\t", dtype=float, header=None, + float_precision="legacy", ) matrix.dropna(how="any", axis=1, inplace=True) data: JSON = matrix.to_dict(orient="split") diff --git a/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py b/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py index fab854966b..98cb8a7056 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py +++ b/antarest/study/storage/rawstudy/model/filesystem/matrix/output_series_matrix.py @@ -1,7 +1,7 @@ import logging from typing import List, Optional, cast, Union -import numpy as np # type: ignore +import numpy as np import pandas as pd # type: ignore from antarest.core.model import JSON @@ -57,7 +57,11 @@ def parse( self, ) -> JSON: df = pd.read_csv( - self.config.path, sep="\t", skiprows=4, na_values="N/A" + self.config.path, + sep="\t", + skiprows=4, + na_values="N/A", + float_precision="legacy", ) date, body = self.date_serializer.extract_date(df) diff --git a/antarest/study/web/studies_blueprint.py b/antarest/study/web/studies_blueprint.py index ca53216626..59f4a58ab7 100644 --- a/antarest/study/web/studies_blueprint.py +++ b/antarest/study/web/studies_blueprint.py @@ -5,7 +5,7 @@ from typing import Any, Optional, List, Dict from fastapi import APIRouter, File, Depends, Request, HTTPException -from markupsafe import escape # type: ignore +from markupsafe import escape from starlette.responses import FileResponse from antarest.core.config import Config diff --git a/antarest/tools/cli.py b/antarest/tools/cli.py index bba11b4824..a46cbf5fe1 100644 --- a/antarest/tools/cli.py +++ b/antarest/tools/cli.py @@ -2,7 +2,7 @@ from pathlib import Path from typing import Optional -import click # type: ignore +import click from antarest.study.model import NEW_DEFAULT_STUDY_VERSION from antarest.tools.lib import ( @@ -14,13 +14,13 @@ logging.basicConfig(level=logging.INFO) -@click.group() # type: ignore +@click.group() def commands() -> None: pass -@commands.command() # type: ignore -@click.option( # type: ignore +@commands.command() +@click.option( "--host", "-h", nargs=1, @@ -28,7 +28,7 @@ def commands() -> None: type=str, help="Host URL of the antares web instance", ) -@click.option( # type: ignore +@click.option( "--auth_token", nargs=1, required=False, @@ -36,7 +36,7 @@ def commands() -> None: type=str, help="Authentication token if server needs one", ) -@click.option( # type: ignore +@click.option( "--output", "-o", nargs=1, @@ -44,7 +44,7 @@ def commands() -> None: type=str, help="Output study path", ) -@click.option( # type: ignore +@click.option( "--input", "-i", nargs=1, @@ -52,7 +52,7 @@ def commands() -> None: type=click.Path(exists=True), help="Variant script source path", ) -@click.option( # type: ignore +@click.option( "--study_id", "-s", nargs=1, @@ -82,8 +82,8 @@ def apply_script( print(res) -@commands.command() # type: ignore -@click.option( # type: ignore +@commands.command() +@click.option( "--input", "-i", nargs=1, @@ -91,7 +91,7 @@ def apply_script( type=click.Path(exists=True), help="Study path", ) -@click.option( # type: ignore +@click.option( "--output", "-o", nargs=1, @@ -104,22 +104,22 @@ def generate_script(input: str, output: str) -> None: extract_commands(Path(input), Path(output)) -@commands.command() # type: ignore -@click.option( # type: ignore +@commands.command() +@click.option( "--base", nargs=1, required=True, type=click.Path(exists=True), help="Base study path", ) -@click.option( # type: ignore +@click.option( "--variant", nargs=1, required=True, type=click.Path(exists=True), help="Variant study path", ) -@click.option( # type: ignore +@click.option( "--output", "-o", nargs=1, @@ -127,7 +127,7 @@ def generate_script(input: str, output: str) -> None: type=click.Path(exists=False), help="Script output path", ) -@click.option( # type: ignore +@click.option( "--version", "-v", nargs=1, diff --git a/pyproject.toml b/pyproject.toml index dafe49cb52..4b938bb952 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,7 @@ [tool.black] -target-version = ["py36"] +target-version = ["py38"] line-length = 79 -exclude = "(antares-?launcher/*|alembic/*)" \ No newline at end of file +exclude = "(antares-?launcher/*|alembic/*)" + +[tool.coverage.run] +omit = ["antarest/tools/cli.py"] \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt index cb828b07a7..5eb49eed28 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,7 +1,6 @@ -r requirements-test.txt -pytest==6.1.1 -black==20.8b1 -pylint==2.6.0 -mypy -pyinstaller -checksumdir \ No newline at end of file +pytest~=6.2.5 +black~=22.1.0 +mypy~=0.931 +pyinstaller~=4.8 +checksumdir~=1.2.0 diff --git a/requirements-test.txt b/requirements-test.txt index f280e10b65..a51745b4d3 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,2 +1,2 @@ -r requirements.txt -pytest-cov==2.10.1 \ No newline at end of file +pytest-cov diff --git a/requirements.txt b/requirements.txt index ce3f5e1cb4..05a6ea6a99 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,35 +1,35 @@ -r antares-launcher/requirements.txt # freezed -mistune==0.8.4 -m2r==0.2.1 +mistune~=0.8.4 +m2r~=0.2.1 -jsonref==0.2 -PyYAML==5.3.1 -filelock==3.0.12 -sqlalchemy~=1.4 +jsonref~=0.2 +PyYAML~=5.4.1 +filelock~=3.4.2 +SQLAlchemy~=1.4.31 dataclasses~=0.6 -redis~=3.5.3 -requests~=2.25.1 -pandas~=1.1.5 -numpy~=1.19.5 -fastapi[all]~=0.65.2 -fastapi-jwt-auth -python-multipart -aiofiles -jinja2~=2.11.3 -uvicorn[standard]~=0.13.4 +redis~=4.1.2 +requests~=2.27.1 +pandas~=1.4.0 +numpy~=1.22.1 +fastapi[all]~=0.73.0 +fastapi-jwt-auth~=0.5.0 +python-multipart~=0.0.5 +aiofiles~=0.8.0 +Jinja2~=3.0.3 +uvicorn[standard]~=0.15.0 bcrypt~=3.2.0 contextvars~=2.4 -scandir -starlette~=0.14.2 -locust~=1.5.1 -MarkupSafe~=1.1.1 +scandir~=1.10.0 +starlette~=0.17.1 +locust~=2.7.0 +MarkupSafe~=2.0.1 checksumdir~=1.2.0 -pydantic~=1.8.2 -gunicorn -alembic -psycopg2-binary -python-json-logger -click -pyqt5 -plyer \ No newline at end of file +pydantic~=1.9.0 +gunicorn~=20.1.0 +alembic~=1.7.5 +psycopg2-binary~=2.9.3 +python-json-logger~=2.0.2 +click~=8.0.3 +PyQt5~=5.15.6 +plyer~=2.0.0 diff --git a/setup.cfg b/setup.cfg index 2a71d4f19b..dc0780a6bb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,6 +23,3 @@ testpaths = markers = unit_test integration_test - -[coverage:run] -omit=antarest/tools/cli.py \ No newline at end of file diff --git a/tests/variantstudy/model/command/test_update_comments.py b/tests/variantstudy/model/command/test_update_comments.py index 09be93df2c..27266c4fc6 100644 --- a/tests/variantstudy/model/command/test_update_comments.py +++ b/tests/variantstudy/model/command/test_update_comments.py @@ -57,21 +57,10 @@ def test_revert(command_context: CommandContext, empty_study: FileStudy): base_command.command_context.command_extractor.generate_update_comments.assert_called_with( empty_study.tree ) - assert ( - base_command.revert( - [ - UpdateComments( - comments="comments", command_context=command_context - ) - ], - empty_study, - ) - == [ - UpdateComments( - comments="comments", command_context=command_context - ) - ] - ) + assert base_command.revert( + [UpdateComments(comments="comments", command_context=command_context)], + empty_study, + ) == [UpdateComments(comments="comments", command_context=command_context)] assert base_command.revert([], base=empty_study) == [ UpdateComments( comments='\n\n \n \n \n \n \n\n', From 2580dc9132b4a958f16ca3d57f363aa40f6f480b Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 31 Jan 2022 17:21:39 +0100 Subject: [PATCH 07/23] FIX slurm antares log path Signed-off-by: Paul Bui-Quang --- .../adapters/slurm_launcher/slurm_launcher.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py b/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py index 6f8fd3ddfd..346a8688ad 100644 --- a/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py +++ b/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py @@ -300,6 +300,14 @@ def _get_log_path( log_dir = Path(study.job_log_dir) return SlurmLauncher._get_log_path_from_log_dir(log_dir, log_type) + @staticmethod + def _find_log_dir(base_log_dir: Path, job_id: str) -> Optional[Path]: + if base_log_dir.exists() and base_log_dir.is_dir(): + for fname in os.listdir(base_log_dir): + if fname.startswith(job_id): + return base_log_dir / fname + return None + @staticmethod def _get_log_path_from_log_dir( log_dir: Path, log_type: LogType = LogType.STDOUT @@ -441,15 +449,20 @@ def run_study( return launch_uuid def get_log(self, job_id: str, log_type: LogType) -> Optional[str]: + log_path: Optional[Path] = None for study in self.data_repo_tinydb.get_list_of_studies(): if study.name == job_id: log_path = SlurmLauncher._get_log_path(study, log_type) if log_path: return log_path.read_text() # when this is not the current worker handling this job (found in data_repo_tinydb) - log_path = SlurmLauncher._get_log_path_from_log_dir( - Path(self.launcher_args.log_dir) / "JOB_LOGS" / job_id, log_type + log_dir = SlurmLauncher._find_log_dir( + Path(self.launcher_args.log_dir) / "JOB_LOGS", job_id ) + if log_dir: + log_path = SlurmLauncher._get_log_path_from_log_dir( + log_dir, log_type + ) if log_path: return log_path.read_text() return None From 483a6a4774e5bb7f5bedb4a7f817601871c1cc6c Mon Sep 17 00:00:00 2001 From: Charly Bion <37449809+Hyralc@users.noreply.github.com> Date: Mon, 31 Jan 2022 17:37:15 +0100 Subject: [PATCH 08/23] Add matrices garbage collector (#726) --- antarest/core/config.py | 1 + antarest/main.py | 23 +- antarest/matrixstore/main.py | 2 +- .../matrixstore/matrix_garbage_collector.py | 122 +++++++++ antarest/matrixstore/repository.py | 6 + antarest/study/main.py | 14 +- .../study/storage/variantstudy/repository.py | 10 + resources/application.yaml | 1 + .../test_matrix_garbage_collector.py | 238 ++++++++++++++++++ tests/matrixstore/test_web.py | 4 +- tests/storage/integration/test_STA_mini.py | 8 +- tests/storage/web/test_studies_bp.py | 40 +-- 12 files changed, 430 insertions(+), 39 deletions(-) create mode 100644 antarest/matrixstore/matrix_garbage_collector.py create mode 100644 tests/matrixstore/test_matrix_garbage_collector.py diff --git a/antarest/core/config.py b/antarest/core/config.py index d465421f53..06e3781d59 100644 --- a/antarest/core/config.py +++ b/antarest/core/config.py @@ -112,6 +112,7 @@ class StorageConfig: watcher_lock: bool = True watcher_lock_delay: int = 10 download_default_expiration_timeout_minutes: int = 1440 + matrix_gc_sleeping_time: int = 3600 @staticmethod def from_dict(data: JSON) -> "StorageConfig": diff --git a/antarest/main.py b/antarest/main.py index 570929eec9..c730de8aba 100644 --- a/antarest/main.py +++ b/antarest/main.py @@ -1,8 +1,6 @@ import argparse import logging -import os import sys -from datetime import timezone, datetime from enum import Enum from pathlib import Path from typing import Tuple, Any, Optional, Dict, cast @@ -11,7 +9,7 @@ import uvicorn # type: ignore from fastapi import FastAPI, HTTPException from fastapi_jwt_auth import AuthJWT # type: ignore -from sqlalchemy import create_engine, text +from sqlalchemy import create_engine from starlette.middleware.cors import CORSMiddleware from starlette.requests import Request from starlette.responses import JSONResponse @@ -37,10 +35,13 @@ ) from antarest.core.utils.web import tags_metadata from antarest.eventbus.main import build_eventbus +from antarest.matrixstore.matrix_garbage_collector import ( + MatrixGarbageCollector, +) from antarest.launcher.main import build_launcher from antarest.login.auth import Auth, JwtSettings from antarest.login.main import build_login -from antarest.matrixstore.main import build_matrixstore +from antarest.matrixstore.main import build_matrix_service from antarest.study.main import build_study_service from antarest.study.storage.rawstudy.watcher import Watcher @@ -192,7 +193,7 @@ def create_services( user_service = build_login(application, config, event_bus=event_bus) - matrix_service = build_matrixstore( + matrix_service = build_matrix_service( application, config=config, file_transfer_manager=filetransfer_service, @@ -223,6 +224,14 @@ def create_services( watcher = Watcher(config=config, service=study_service) services["watcher"] = watcher + if Module.MATRIX_GC.value in config.server.services or create_all: + matrix_garbage_collector = MatrixGarbageCollector( + config=config, + study_service=study_service, + matrix_service=matrix_service, + ) + services["matrix_gc"] = matrix_garbage_collector + services["event_bus"] = event_bus services["study"] = study_service services["launcher"] = launcher @@ -362,6 +371,10 @@ def handle_all_exception(request: Request, exc: Exception) -> Any: watcher = cast(Watcher, services["watcher"]) watcher.start() + if Module.MATRIX_GC.value in config.server.services: + matrix_gc = cast(MatrixGarbageCollector, services["matrix_gc"]) + matrix_gc.start() + customize_openapi(application) return application, services diff --git a/antarest/matrixstore/main.py b/antarest/matrixstore/main.py index 50ec051d57..3a2a729905 100644 --- a/antarest/matrixstore/main.py +++ b/antarest/matrixstore/main.py @@ -16,7 +16,7 @@ from antarest.matrixstore.web import create_matrix_api -def build_matrixstore( +def build_matrix_service( application: Optional[FastAPI], config: Config, file_transfer_manager: FileTransferManager, diff --git a/antarest/matrixstore/matrix_garbage_collector.py b/antarest/matrixstore/matrix_garbage_collector.py new file mode 100644 index 0000000000..246f4b1c66 --- /dev/null +++ b/antarest/matrixstore/matrix_garbage_collector.py @@ -0,0 +1,122 @@ +import logging +import threading +import time +from os import listdir +from pathlib import Path +from typing import Set, List + +from antarest.core.config import Config +from antarest.core.utils.fastapi_sqlalchemy import db +from antarest.core.utils.utils import StopWatch +from antarest.matrixstore.repository import MatrixDataSetRepository +from antarest.matrixstore.service import MatrixService +from antarest.study.model import DEFAULT_WORKSPACE_NAME +from antarest.study.service import StudyService +from antarest.study.storage.variantstudy.model.dbmodel import CommandBlock +from antarest.study.storage.variantstudy.variant_study_service import ( + VariantStudyService, +) + +logger = logging.getLogger(__name__) + + +class MatrixGarbageCollector: + def __init__( + self, + config: Config, + study_service: StudyService, + matrix_service: MatrixService, + ): + self.saved_matrices_path: Path = config.storage.matrixstore + self.managed_studies_path: Path = config.storage.workspaces[ + DEFAULT_WORKSPACE_NAME + ].path + self.thread = threading.Thread(target=self._loop, daemon=True) + self.study_service: StudyService = study_service + self.variant_study_service: VariantStudyService = ( + study_service.storage_service.variant_study_service + ) + self.matrix_service = matrix_service + self.dataset_repository: MatrixDataSetRepository = ( + matrix_service.repo_dataset + ) + self.sleeping_time = config.storage.matrix_gc_sleeping_time + + def _get_saved_matrices(self) -> Set[str]: + logging.info("Getting all saved matrices") + return {f.split(".")[0] for f in listdir(self.saved_matrices_path)} + + def _get_raw_studies_matrices(self) -> Set[str]: + logger.info("Getting all matrices used in raw studies") + return { + f.name.split(".")[0] + for f in self.managed_studies_path.rglob("*.link") + } + + def _get_variant_studies_matrices(self) -> Set[str]: + logger.info("Getting all matrices used in variant studies") + command_blocks: List[ + CommandBlock + ] = self.variant_study_service.repository.get_all_commandblocks() + variant_study_commands = [ + icommand + for c in command_blocks + for icommand in self.variant_study_service.command_factory.to_icommand( + c.to_dto() + ) + ] + matrices = { + matrix + for command in variant_study_commands + for matrix in command.get_inner_matrices() + } + return matrices + + def _get_datasets_matrices(self) -> Set[str]: + logger.info("Getting all matrices used in datasets") + datasets = self.dataset_repository.get_all_datasets() + return { + matrix.matrix_id + for dataset in datasets + for matrix in dataset.matrices + } + + def _get_used_matrices(self) -> Set[str]: + """Return all matrices used in raw studies, variant studies and datasets""" + raw_studies_matrices = self._get_raw_studies_matrices() + variant_studies_matrices = self._get_variant_studies_matrices() + datasets_matrices = self._get_datasets_matrices() + return ( + raw_studies_matrices | variant_studies_matrices | datasets_matrices + ) + + def _delete_unused_saved_matrices(self, unused_matrices: Set[str]) -> None: + """Delete all files with the name in unused_matrices""" + logging.info("Deleting unused saved matrices:") + for unused_matrix_id in unused_matrices: + logging.info(f"Deleting {unused_matrix_id}") + self.matrix_service.delete(unused_matrix_id) + + def _clean_matrices(self) -> None: + """Delete all matrices that are not used anymore""" + stopwatch = StopWatch() + logger.info("Beginning of the cleaning process") + saved_matrices = self._get_saved_matrices() + used_matrices = self._get_used_matrices() + unused_matrices = saved_matrices - used_matrices + self._delete_unused_saved_matrices(unused_matrices=unused_matrices) + stopwatch.log_elapsed( + lambda x: logger.info(f"Finished cleaning matrices in {x}s") + ) + + def _loop(self) -> None: + while True: + try: + self._clean_matrices() + except Exception as e: + logging.error(f"Error while cleaning matrices: {e}") + logging.info(f"Sleeping for {self.sleeping_time}s") + time.sleep(self.sleeping_time) + + def start(self) -> None: + self.thread.start() diff --git a/antarest/matrixstore/repository.py b/antarest/matrixstore/repository.py index 899eaeb1ed..69692900e1 100644 --- a/antarest/matrixstore/repository.py +++ b/antarest/matrixstore/repository.py @@ -43,6 +43,12 @@ def get(self, id: str) -> Optional[MatrixDataSet]: matrix: MatrixDataSet = db.session.query(MatrixDataSet).get(id) return matrix + def get_all_datasets(self) -> List[MatrixDataSet]: + matrix_datasets: List[MatrixDataSet] = db.session.query( + MatrixDataSet + ).all() + return matrix_datasets + def query( self, name: Optional[str], diff --git a/antarest/study/main.py b/antarest/study/main.py index dc549c8233..737941757a 100644 --- a/antarest/study/main.py +++ b/antarest/study/main.py @@ -50,7 +50,7 @@ def build_study_service( task_service: ITaskService, metadata_repository: Optional[StudyMetadataRepository] = None, variant_repository: Optional[VariantStudyRepository] = None, - storage_service: Optional[StudyService] = None, + study_service: Optional[StudyService] = None, patch_service: Optional[PatchService] = None, generator_matrix_constants: Optional[GeneratorMatrixConstants] = None, event_bus: IEventBus = DummyEventBusService(), @@ -68,7 +68,7 @@ def build_study_service( task_service: task job service metadata_repository: used by testing to inject mock. Let None to use true instantiation variant_repository: used by testing to inject mock. Let None to use true instantiation - storage_service: used by testing to inject mock. Let None to use true instantiation + study_service: used by testing to inject mock. Let None to use true instantiation patch_service: used by testing to inject mock. Let None to use true instantiation generator_matrix_constants: used by testing to inject mock. Let None to use true instantiation event_bus: used by testing to inject mock. Let None to use true instantiation @@ -116,7 +116,7 @@ def build_study_service( patch_service=patch_service, ) - storage_service = storage_service or StudyService( + study_service = study_service or StudyService( raw_study_service=raw_study_service, variant_study_service=variant_study_service, user_service=user_service, @@ -130,13 +130,13 @@ def build_study_service( if application: application.include_router( - create_study_routes(storage_service, file_transfer_manager, config) + create_study_routes(study_service, file_transfer_manager, config) ) application.include_router( - create_raw_study_routes(storage_service, config) + create_raw_study_routes(study_service, config) ) application.include_router( - create_study_data_routes(storage_service, config) + create_study_data_routes(study_service, config) ) application.include_router( create_study_variant_routes( @@ -145,4 +145,4 @@ def build_study_service( ) ) - return storage_service + return study_service diff --git a/antarest/study/storage/variantstudy/repository.py b/antarest/study/storage/variantstudy/repository.py index 905640503d..7fe6d324f1 100644 --- a/antarest/study/storage/variantstudy/repository.py +++ b/antarest/study/storage/variantstudy/repository.py @@ -25,3 +25,13 @@ def get_children(self, parent_id: str) -> List[VariantStudy]: .all() ) return studies + + def get_all_commandblocks(self) -> List[CommandBlock]: + outputs = db.session.query(CommandBlock).all() + + # for mypy + assert isinstance(outputs, list) + for output in outputs: + assert isinstance(output, CommandBlock) + + return outputs diff --git a/resources/application.yaml b/resources/application.yaml index 04ce76c0fd..0382d7851e 100644 --- a/resources/application.yaml +++ b/resources/application.yaml @@ -23,6 +23,7 @@ storage: matrixstore: ./matrices archive_dir: examples/archives allow_deletion: false # indicate if studies found in non default workspace can be deleted by the application + matrix_gc_sleeping_time: 3600 # time in seconds to sleep between two garbage collection workspaces: default: # required, no filters applied, this folder is not watched path: examples/internal_studies/ diff --git a/tests/matrixstore/test_matrix_garbage_collector.py b/tests/matrixstore/test_matrix_garbage_collector.py new file mode 100644 index 0000000000..363386d72f --- /dev/null +++ b/tests/matrixstore/test_matrix_garbage_collector.py @@ -0,0 +1,238 @@ +from datetime import datetime +from pathlib import Path +from unittest.mock import Mock + +import pytest +from sqlalchemy import create_engine + +from antarest.core.utils.fastapi_sqlalchemy import DBSessionMiddleware, db +from antarest.dbmodel import Base +from antarest.matrixstore.matrix_garbage_collector import ( + MatrixGarbageCollector, +) +from antarest.matrixstore.model import MatrixDataSet, MatrixDataSetRelation +from antarest.matrixstore.repository import MatrixDataSetRepository +from antarest.matrixstore.service import MatrixService +from antarest.study.storage.variantstudy.business.matrix_constants_generator import ( + GeneratorMatrixConstants, +) +from antarest.study.storage.variantstudy.command_factory import CommandFactory +from antarest.study.storage.variantstudy.model.command.common import ( + CommandName, +) +from antarest.study.storage.variantstudy.model.dbmodel import CommandBlock +from antarest.study.storage.variantstudy.repository import ( + VariantStudyRepository, +) + + +@pytest.fixture +def matrix_garbage_collector(tmp_path: Path): + """ + Fixture for creating a MatrixGarbageCollector object. + """ + matrix_store = tmp_path / "matrix_store" + matrix_store.mkdir() + default_workspace = tmp_path / "default_workspace" + default_workspace.mkdir() + mock_workspace_config = Mock() + mock_workspace_config.path = default_workspace + + mock_config = Mock() + mock_config.storage.matrixstore = matrix_store + mock_config.storage.workspaces = {"default": mock_workspace_config} + + command_factory = CommandFactory( + generator_matrix_constants=Mock(spec=GeneratorMatrixConstants), + matrix_service=Mock(spec=MatrixService), + ) + study_service = Mock() + study_service.storage_service.variant_study_service.command_factory = ( + command_factory + ) + study_service.storage_service.variant_study_service.repository = ( + VariantStudyRepository(cache_service=Mock()) + ) + + matrix_garbage_collector = MatrixGarbageCollector( + config=mock_config, study_service=study_service, matrix_service=Mock() + ) + + return matrix_garbage_collector + + +@pytest.mark.unit_test +def test_get_saved_matrices( + matrix_garbage_collector: MatrixGarbageCollector, +): + """ + Test that the get_all_saved_matrices function returns a list of all saved + matrices. + """ + matrix_name1 = "matrix_name1" + matrix_name2 = "matrix_name2" + ( + matrix_garbage_collector.saved_matrices_path / f"{matrix_name1}.txt" + ).touch() + ( + matrix_garbage_collector.saved_matrices_path / f"{matrix_name2}.txt" + ).touch() + + # Get all saved matrices + saved_matrices = matrix_garbage_collector._get_saved_matrices() + assert saved_matrices == {matrix_name1, matrix_name2} + + +@pytest.mark.unit_test +def test_get_matrices_used_in_raw_studies( + matrix_garbage_collector: MatrixGarbageCollector, +): + """ + Test that the get_matrices_used_in_raw_studies function returns a list of + all matrices used in raw studies. + """ + matrix_name1 = "matrix_name1" + matrix_name2 = "matrix_name2" + matrix_name3 = "matrix_name3" + matrix_name4 = "matrix_name4" + + raw_study_path = ( + matrix_garbage_collector.managed_studies_path / "raw_study" + ) + raw_study_path.mkdir() + (raw_study_path / f"{matrix_name1}.link").touch() + (raw_study_path / f"{matrix_name2}.link").touch() + (raw_study_path / f"{matrix_name3}.link").touch() + (raw_study_path / f"{matrix_name4}.txt").touch() + + output = matrix_garbage_collector._get_raw_studies_matrices() + + assert len(output) == 3 + assert matrix_name1 in output + assert matrix_name2 in output + assert matrix_name3 in output + assert matrix_name4 not in output + + +@pytest.mark.unit_test +def test_get_matrices_used_in_variant_studies( + matrix_garbage_collector: MatrixGarbageCollector, +): + engine = create_engine("sqlite:///:memory:", echo=True) + Base.metadata.create_all(engine) + DBSessionMiddleware( + Mock(), + custom_engine=engine, + session_args={"autocommit": False, "autoflush": False}, + ) + matrix_garbage_collector.study_service.storage_service.variant_study_service.command_factory.command_context.generator_matrix_constants.get_link = Mock( + side_effect=["matrix1", "matrix2"] + ) + with db(): + study_id = "study_id" + command_block1 = CommandBlock( + study_id=study_id, + command=CommandName.CREATE_LINK.value, + args='{"area1": "area1", "area2": "area2"}', + index=0, + version=7, + ) + command_block2 = CommandBlock( + study_id=study_id, + command=CommandName.CREATE_LINK.value, + args='{"area1": "area2", "area2": "area3"}', + index=0, + version=7, + ) + db.session.add(command_block1) + db.session.add(command_block2) + db.session.commit() + matrices = matrix_garbage_collector._get_variant_studies_matrices() + assert len(matrices) == 2 + assert "matrix1" in matrices + assert "matrix2" in matrices + + +@pytest.mark.unit_test +def test_get_matrices_used_in_dataset( + matrix_garbage_collector: MatrixGarbageCollector, +): + matrix_garbage_collector.dataset_repository = MatrixDataSetRepository() + engine = create_engine("sqlite:///:memory:", echo=True) + Base.metadata.create_all(engine) + DBSessionMiddleware( + Mock(), + custom_engine=engine, + session_args={"autocommit": False, "autoflush": False}, + ) + + dataset = MatrixDataSet( + name="name", + public=True, + owner_id="owner_id", + groups=[], + created_at=datetime.utcnow(), + updated_at=datetime.utcnow(), + ) + matrix_relation1 = MatrixDataSetRelation(name="matrix_name1") + matrix_relation1.matrix_id = "matrix_id1" + dataset.matrices.append(matrix_relation1) + matrix_relation2 = MatrixDataSetRelation(name="matrix_name2") + matrix_relation2.matrix_id = "matrix_id2" + dataset.matrices.append(matrix_relation2) + with db(): + db.session.add(dataset) + db.session.commit() + matrices = matrix_garbage_collector._get_datasets_matrices() + assert len(matrices) == 2 + assert "matrix_id1" in matrices + assert "matrix_id2" in matrices + + +@pytest.mark.unit_test +def test_get_used_matrices(matrix_garbage_collector: MatrixGarbageCollector): + matrix_garbage_collector._get_raw_studies_matrices = Mock( + return_value={"matrix1", "matrix2"} + ) + matrix_garbage_collector._get_variant_studies_matrices = Mock( + return_value={"matrix3", "matrix4"} + ) + matrix_garbage_collector._get_datasets_matrices = Mock( + return_value={"matrix4", "matrix6"} + ) + assert matrix_garbage_collector._get_used_matrices() == { + "matrix1", + "matrix2", + "matrix3", + "matrix4", + "matrix6", + } + + +@pytest.mark.unit_test +def test_delete_unused_saved_matrices( + matrix_garbage_collector: MatrixGarbageCollector, +): + unused_matrices = {"matrix1", "matrix2"} + matrix_garbage_collector.matrix_service.delete = Mock() + matrix_garbage_collector._delete_unused_saved_matrices(unused_matrices) + + matrix_garbage_collector.matrix_service.delete.assert_any_call("matrix1") + matrix_garbage_collector.matrix_service.delete.assert_any_call("matrix2") + + +@pytest.mark.unit_test +def test_clean_matrices(matrix_garbage_collector: MatrixGarbageCollector): + matrix_garbage_collector._get_saved_matrices = Mock( + return_value={"matrix1", "matrix2"} + ) + matrix_garbage_collector._get_used_matrices = Mock( + return_value={"matrix1"} + ) + matrix_garbage_collector._delete_unused_saved_matrices = Mock() + + matrix_garbage_collector._clean_matrices() + + matrix_garbage_collector._delete_unused_saved_matrices.assert_called_once_with( + unused_matrices={"matrix2"} + ) diff --git a/tests/matrixstore/test_web.py b/tests/matrixstore/test_web.py index 112ffdbcfa..2734fe257b 100644 --- a/tests/matrixstore/test_web.py +++ b/tests/matrixstore/test_web.py @@ -8,7 +8,7 @@ from antarest.core.config import Config, SecurityConfig from antarest.main import JwtSettings -from antarest.matrixstore.main import build_matrixstore +from antarest.matrixstore.main import build_matrix_service from antarest.matrixstore.model import MatrixDTO, MatrixInfoDTO from tests.login.test_web import create_auth_token @@ -24,7 +24,7 @@ def get_config(): authjwt_denylist_enabled=False, ) - build_matrixstore( + build_matrix_service( app, user_service=Mock(), file_transfer_manager=Mock(), diff --git a/tests/storage/integration/test_STA_mini.py b/tests/storage/integration/test_STA_mini.py index badabb1b73..cebafbf8a7 100644 --- a/tests/storage/integration/test_STA_mini.py +++ b/tests/storage/integration/test_STA_mini.py @@ -44,7 +44,7 @@ def assert_url_content( user_service=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, matrix_service=Mock(spec=MatrixService), config=storage_service.storage_service.raw_study_service.config, ) @@ -409,7 +409,7 @@ def test_sta_mini_copy(storage_service) -> None: user_service=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, matrix_service=Mock(spec=MatrixService), config=storage_service.storage_service.raw_study_service.config, ) @@ -511,7 +511,7 @@ def test_sta_mini_import(tmp_path: Path, storage_service) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, user_service=Mock(), matrix_service=Mock(spec=MatrixService), config=storage_service.storage_service.raw_study_service.config, @@ -547,7 +547,7 @@ def test_sta_mini_import_output(tmp_path: Path, storage_service) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, user_service=Mock(), matrix_service=Mock(spec=MatrixService), config=storage_service.storage_service.raw_study_service.config, diff --git a/tests/storage/web/test_studies_bp.py b/tests/storage/web/test_studies_bp.py index a5ec4246d8..8f472719e7 100644 --- a/tests/storage/web/test_studies_bp.py +++ b/tests/storage/web/test_studies_bp.py @@ -74,7 +74,7 @@ def test_server() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_service, + study_service=mock_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -98,7 +98,7 @@ def test_404() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -122,7 +122,7 @@ def test_server_with_parameters() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -165,7 +165,7 @@ def test_create_study(tmp_path: str, project_path) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -203,7 +203,7 @@ def test_import_study_zipped(tmp_path: Path, project_path) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -233,7 +233,7 @@ def test_copy_study(tmp_path: Path) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -295,7 +295,7 @@ def test_list_studies(tmp_path: str) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -332,7 +332,7 @@ def test_study_metadata(tmp_path: str) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -364,7 +364,7 @@ def test_export_files(tmp_path: Path) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -401,7 +401,7 @@ def test_export_params(tmp_path: Path) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -427,7 +427,7 @@ def test_delete_study() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -449,7 +449,7 @@ def test_edit_study() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -474,7 +474,7 @@ def test_edit_study_fail() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_storage_service, + study_service=mock_storage_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -498,7 +498,7 @@ def test_validate() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_service, + study_service=mock_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -541,7 +541,7 @@ def test_output_download(tmp_path: Path) -> None: file_transfer_manager=SimpleFileTransferManager( Config(storage=StorageConfig(tmp_dir=tmp_path)) ), - storage_service=mock_service, + study_service=mock_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -579,7 +579,7 @@ def test_output_whole_download(tmp_path: Path) -> None: file_transfer_manager=SimpleFileTransferManager( Config(storage=StorageConfig(tmp_dir=tmp_path)) ), - storage_service=mock_service, + study_service=mock_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -603,7 +603,7 @@ def test_sim_reference() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_service, + study_service=mock_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -648,7 +648,7 @@ def test_sim_result() -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=mock_service, + study_service=mock_service, config=CONFIG, user_service=Mock(), matrix_service=Mock(spec=MatrixService), @@ -668,7 +668,7 @@ def test_study_permission_management(tmp_path: Path) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=storage_service, + study_service=storage_service, user_service=Mock(), matrix_service=Mock(spec=MatrixService), config=CONFIG, @@ -720,7 +720,7 @@ def test_get_study_versions(tmp_path: Path) -> None: cache=Mock(), task_service=Mock(), file_transfer_manager=Mock(), - storage_service=Mock(), + study_service=Mock(), user_service=Mock(), matrix_service=Mock(spec=MatrixService), config=CONFIG, From 2cdf89738609bd487ac06fd6d7a98cca2063fac3 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 31 Jan 2022 17:47:59 +0100 Subject: [PATCH 09/23] Temporary fix of pip Signed-off-by: Paul Bui-Quang --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ee2825af17..71a47742ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN cp /antares-launcher/requirements.txt /conf/antares-launcher/requirements.tx RUN ./scripts/install-debug.sh -RUN pip3 install --upgrade pip \ +RUN pip3 install --upgrade pip==21.3.1 \ && pip3 install -r /conf/requirements.txt From ecf374d1c72101ef9e971d4eec9e4da5b6ecb666 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Tue, 1 Feb 2022 11:25:50 +0100 Subject: [PATCH 10/23] Add launcher adequacy patch extension (#722) --- .../launcher/adapters/abstractlauncher.py | 30 +++ .../launcher/adapters/factory_launcher.py | 2 +- .../adapters/local_launcher/local_launcher.py | 190 ++++++++++++++++-- antarest/launcher/adapters/log_manager.py | 58 +++--- .../adapters/slurm_launcher/slurm_launcher.py | 77 ++++--- antarest/launcher/extensions/__init__.py | 0 .../extensions/adequacy_patch/__init__.py | 0 .../extensions/adequacy_patch/extension.py | 54 +++++ .../resources/post-processing.R | 20 ++ antarest/launcher/extensions/interface.py | 21 ++ antarest/launcher/service.py | 44 +++- antarest/study/service.py | 9 + .../launcher/test_extension_adequacy_patch.py | 36 ++++ tests/launcher/test_local_launcher.py | 28 ++- tests/launcher/test_service.py | 4 +- tests/launcher/test_slurm_launcher.py | 6 + webapp/src/components/ui/LauncherModal.tsx | 4 +- webapp/src/services/api/study.ts | 2 + 18 files changed, 496 insertions(+), 89 deletions(-) create mode 100644 antarest/launcher/extensions/__init__.py create mode 100644 antarest/launcher/extensions/adequacy_patch/__init__.py create mode 100644 antarest/launcher/extensions/adequacy_patch/extension.py create mode 100644 antarest/launcher/extensions/adequacy_patch/resources/post-processing.R create mode 100644 antarest/launcher/extensions/interface.py create mode 100644 tests/launcher/test_extension_adequacy_patch.py diff --git a/antarest/launcher/adapters/abstractlauncher.py b/antarest/launcher/adapters/abstractlauncher.py index df3f48b8ba..d420116458 100644 --- a/antarest/launcher/adapters/abstractlauncher.py +++ b/antarest/launcher/adapters/abstractlauncher.py @@ -1,8 +1,15 @@ from abc import ABC, abstractmethod +from pathlib import Path from typing import Callable, NamedTuple, Optional, Any from uuid import UUID from antarest.core.config import Config +from antarest.core.interfaces.eventbus import ( + Event, + EventType, + EventChannelDirectory, + IEventBus, +) from antarest.core.model import JSON from antarest.core.requests import RequestParameters from antarest.launcher.model import JobStatus, LogType @@ -14,9 +21,12 @@ class LauncherInitException(Exception): class LauncherCallbacks(NamedTuple): + # args: job_id, job status, message, output_id update_status: Callable[ [str, JobStatus, Optional[str], Optional[str]], None ] + # args: job_id, study_id, study_export_path, launcher_params + after_export_flat: Callable[[str, str, Path, Optional[JSON]], None] class AbstractLauncher(ABC): @@ -25,10 +35,12 @@ def __init__( config: Config, storage_service: StudyService, callbacks: LauncherCallbacks, + event_bus: IEventBus, ): self.config = config self.storage_service = storage_service self.callbacks = callbacks + self.event_bus = event_bus @abstractmethod def run_study( @@ -47,3 +59,21 @@ def get_log(self, job_id: str, log_type: LogType) -> Optional[str]: @abstractmethod def kill_job(self, job_id: str) -> None: raise NotImplementedError() + + def create_update_log( + self, job_id: str, study_id: str + ) -> Callable[[str], None]: + def update_log(log_line: str) -> None: + self.event_bus.push( + Event( + type=EventType.STUDY_JOB_LOG_UPDATE, + payload={ + "log": log_line, + "job_id": job_id, + "study_id": study_id, + }, + channel=EventChannelDirectory.JOB_LOGS + job_id, + ) + ) + + return update_log diff --git a/antarest/launcher/adapters/factory_launcher.py b/antarest/launcher/adapters/factory_launcher.py index b39e5ca4f3..f3d539fd60 100644 --- a/antarest/launcher/adapters/factory_launcher.py +++ b/antarest/launcher/adapters/factory_launcher.py @@ -29,7 +29,7 @@ def build_launcher( dict_launchers: Dict[str, AbstractLauncher] = dict() if config.launcher.local is not None: dict_launchers["local"] = LocalLauncher( - config, storage_service, callbacks + config, storage_service, callbacks, event_bus ) if config.launcher.slurm is not None: dict_launchers["slurm"] = SlurmLauncher( diff --git a/antarest/launcher/adapters/local_launcher/local_launcher.py b/antarest/launcher/adapters/local_launcher/local_launcher.py index b91b3f10f7..67dd5a532e 100644 --- a/antarest/launcher/adapters/local_launcher/local_launcher.py +++ b/antarest/launcher/adapters/local_launcher/local_launcher.py @@ -1,10 +1,18 @@ +import logging +import shutil +import signal import subprocess +import tempfile import threading +import time +from multiprocessing import Process from pathlib import Path -from typing import Dict, Optional +from typing import Dict, Optional, Tuple, Callable, cast, IO from uuid import UUID, uuid4 from antarest.core.config import Config +from antarest.core.interfaces.eventbus import IEventBus +from antarest.core.jwt import DEFAULT_ADMIN_USER from antarest.core.model import JSON from antarest.core.requests import RequestParameters from antarest.core.utils.fastapi_sqlalchemy import db @@ -13,23 +21,35 @@ LauncherInitException, LauncherCallbacks, ) +from antarest.launcher.adapters.log_manager import LogTailManager from antarest.launcher.model import JobStatus, LogType from antarest.study.service import StudyService +logger = logging.getLogger(__name__) + class StudyVersionNotSupported(Exception): pass class LocalLauncher(AbstractLauncher): + """ + This local launcher is meant to work when using AntaresWeb on a single worker process in local mode + """ + def __init__( self, config: Config, storage_service: StudyService, callbacks: LauncherCallbacks, + event_bus: IEventBus, ) -> None: - super().__init__(config, storage_service, callbacks) - self.job_id_to_study_id: Dict[str, str] = {} + super().__init__(config, storage_service, callbacks, event_bus) + self.tmpdir = config.storage.tmp_dir + self.job_id_to_study_id: Dict[ # type: ignore + str, Tuple[str, Path, subprocess.Popen] + ] = {} + self.logs: Dict[str, str] = {} def run_study( self, @@ -46,38 +66,166 @@ def run_study( raise StudyVersionNotSupported() else: uuid = uuid4() - self.job_id_to_study_id[str(uuid)] = study_uuid - study_path = self.storage_service.get_study_path( - study_uuid, params - ) job = threading.Thread( target=LocalLauncher._compute, - args=(self, antares_solver_path, study_path, uuid), + args=( + self, + antares_solver_path, + study_uuid, + uuid, + launcher_parameters, + ), ) job.start() return uuid def _compute( - self, antares_solver_path: Path, study_path: Path, uuid: UUID + self, + antares_solver_path: Path, + study_uuid: str, + uuid: UUID, + launcher_parameters: Optional[JSON], ) -> None: - process = subprocess.run( - [antares_solver_path, study_path], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, + end = False + + def stop_reading_output() -> bool: + if end and str(uuid) in self.logs: + del self.logs[str(uuid)] + return end + + tmp_path = tempfile.mkdtemp( + prefix="local_launch_", dir=str(self.tmpdir) ) - del self.job_id_to_study_id[str(uuid)] - with db(): + export_path = Path(tmp_path) / "export" + try: + with db(): + self.storage_service.export_study_flat( + study_uuid, + RequestParameters(DEFAULT_ADMIN_USER), + export_path, + outputs=False, + ) + self.callbacks.after_export_flat( + str(uuid), study_uuid, export_path, launcher_parameters + ) + + process = subprocess.Popen( + [antares_solver_path, export_path], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + encoding="utf-8", + ) + self.job_id_to_study_id[str(uuid)] = ( + study_uuid, + export_path, + process, + ) + with db(): + self.callbacks.update_status( + str(uuid), + JobStatus.RUNNING, + None, + None, + ) + + thread = threading.Thread( + target=lambda: LogTailManager.follow( + cast(IO[str], process.stdout), + self.create_update_log(str(uuid), study_uuid), + stop_reading_output, + None, + ), + daemon=True, + ) + thread.start() + + while True: + if process.poll() is not None: + break + time.sleep(1) + + if launcher_parameters is not None: + post_processing = launcher_parameters.get( + "post_processing", False + ) + if ( + isinstance(post_processing, bool) and post_processing + ) or launcher_parameters.get( + "adequacy_patch", None + ) is not None: + subprocess.run( + ["Rscript", "post-processing.R"], cwd=export_path + ) + + try: + with db(): + output_id = self._import_output(study_uuid, export_path) + except Exception as e: + logger.error( + f"Failed to import output for study {study_uuid} located at {export_path}", + exc_info=e, + ) + del self.job_id_to_study_id[str(uuid)] + with db(): + self.callbacks.update_status( + str(uuid), + JobStatus.FAILED + if (not process.returncode == 0) or not output_id + else JobStatus.SUCCESS, + None, + output_id, + ) + except Exception as e: + logger.error( + f"Unexpected error happend during launch {uuid}", exc_info=e + ) self.callbacks.update_status( str(uuid), - JobStatus.FAILED - if (not process.returncode == 0) - else JobStatus.SUCCESS, - None, + JobStatus.FAILED, + str(e), None, ) + finally: + logger.info(f"Removing launch {uuid} export path at {tmp_path}") + end = True + shutil.rmtree(tmp_path) + + def _import_output( + self, study_id: str, study_launch_path: Path + ) -> Optional[str]: + return self.storage_service.import_output( + study_id, + study_launch_path / "output", + params=RequestParameters(DEFAULT_ADMIN_USER), + ) + + def create_update_log( + self, job_id: str, study_id: str + ) -> Callable[[str], None]: + base_func = super().create_update_log(job_id, study_id) + self.logs[job_id] = "" + + def append_to_log(log_line: str) -> None: + base_func(log_line) + self.logs[job_id] += log_line + "\n" + + return append_to_log def get_log(self, job_id: str, log_type: LogType) -> Optional[str]: - raise NotImplementedError() + if job_id in self.job_id_to_study_id and job_id in self.logs: + return self.logs[job_id] + return None def kill_job(self, job_id: str) -> None: - raise NotImplementedError() + if job_id in self.job_id_to_study_id: + return self.job_id_to_study_id[job_id][2].send_signal( + signal.SIGTERM + ) + else: + self.callbacks.update_status( + job_id, + JobStatus.FAILED, + None, + None, + ) diff --git a/antarest/launcher/adapters/log_manager.py b/antarest/launcher/adapters/log_manager.py index 0bbf4a9d96..50c1589d72 100644 --- a/antarest/launcher/adapters/log_manager.py +++ b/antarest/launcher/adapters/log_manager.py @@ -2,7 +2,7 @@ import time from pathlib import Path from threading import Thread -from typing import Callable, Dict, Optional +from typing import Callable, Dict, Optional, IO, AnyStr, TextIO logger = logging.getLogger(__name__) @@ -26,7 +26,7 @@ def track( logger.info(f"Adding log {log_path} track") thread = Thread( - target=lambda: self.follow( + target=lambda: self._follow( log_path, handler, self._stop_tracking(str(log_path)) ), daemon=True, @@ -47,7 +47,38 @@ def stop_tracking(self, log_path: Optional[Path]) -> None: if log_path_key in self.tracked_logs: del self.tracked_logs[log_path_key] + @staticmethod def follow( + io: IO[str], + handler: Callable[[str], None], + stop: Callable[[], bool], + log_file: Optional[str], + ) -> None: + line = "" + line_count = 0 + + while True: + if stop(): + break + tmp = io.readline() + if not tmp: + if line: + logger.debug(f"Calling handler for {log_file}") + handler(line) + line = "" + line_count = 0 + time.sleep(0.1) + else: + line += tmp + if line.endswith("\n"): + line_count += 1 + if line_count >= LogTailManager.BATCH_SIZE: + logger.debug(f"Calling handler for {log_file}") + handler(line) + line = "" + line_count = 0 + + def _follow( self, log_file: Optional[Path], handler: Callable[[str], None], @@ -59,26 +90,5 @@ def follow( return with open(log_file, "r") as fh: - line = "" - line_count = 0 logger.info(f"Scanning {log_file}") - while True: - if stop(): - break - tmp = fh.readline() - if not tmp: - if line: - logger.info(f"Calling handler for {log_file}") - handler(line) - line = "" - line_count = 0 - time.sleep(0.1) - else: - line += tmp - if line.endswith("\n"): - line_count += 1 - if line_count >= LogTailManager.BATCH_SIZE: - logger.info(f"Calling handler for {log_file}") - handler(line) - line = "" - line_count = 0 + LogTailManager.follow(fh, handler, stop, str(log_file)) diff --git a/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py b/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py index 346a8688ad..49f7448cf7 100644 --- a/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py +++ b/antarest/launcher/adapters/slurm_launcher/slurm_launcher.py @@ -7,7 +7,7 @@ import time from copy import deepcopy from pathlib import Path -from typing import Callable, Optional, Dict, Awaitable +from typing import Callable, Optional, Dict, Awaitable, List from uuid import UUID, uuid4 from antareslauncher.data_repo.data_repo_tinydb import DataRepoTinydb @@ -40,7 +40,6 @@ logger = logging.getLogger(__name__) logging.getLogger("paramiko").setLevel("WARN") - MAX_NB_CPU = 24 MAX_TIME_LIMIT = 604800 MIN_TIME_LIMIT = 3600 @@ -63,7 +62,7 @@ def __init__( event_bus: IEventBus, use_private_workspace: bool = True, ) -> None: - super().__init__(config, study_service, callbacks) + super().__init__(config, study_service, callbacks, event_bus) if config.launcher.slurm is None: raise LauncherInitException() @@ -186,15 +185,34 @@ def _delete_study(self, study_path: Path) -> None: shutil.rmtree(study_path) def _import_study_output( - self, job_id: str, xpansion_mode: Optional[str] = None + self, + job_id: str, + xpansion_mode: Optional[str] = None, + log_dir: Optional[str] = None, ) -> Optional[str]: study_id = self.job_id_to_study_id[job_id] if xpansion_mode is not None: self._import_xpansion_result(job_id, xpansion_mode) + + launcher_logs: List[Path] = [] + if log_dir is not None: + launcher_logs = [ + log_path + for log_path in [ + SlurmLauncher._get_log_path_from_log_dir( + Path(log_dir), LogType.STDOUT + ), + SlurmLauncher._get_log_path_from_log_dir( + Path(log_dir), LogType.STDERR + ), + ] + if log_path + ] return self.storage_service.import_output( study_id, self.local_workspace / "OUTPUT" / job_id / "output", params=RequestParameters(DEFAULT_ADMIN_USER), + additional_logs=launcher_logs, ) def _import_xpansion_result(self, job_id: str, xpansion_mode: str) -> None: @@ -245,18 +263,22 @@ def _check_studies_state(self) -> None: ) with db(): output_id: Optional[str] = None - if not study.with_error: - output_id = self._import_study_output( - study.name, study.xpansion_mode + try: + if not study.with_error: + output_id = self._import_study_output( + study.name, + study.xpansion_mode, + study.job_log_dir, + ) + finally: + self.callbacks.update_status( + study.name, + JobStatus.FAILED + if study.with_error or output_id is None + else JobStatus.SUCCESS, + None, + output_id, ) - self.callbacks.update_status( - study.name, - JobStatus.FAILED - if study.with_error or output_id is None - else JobStatus.SUCCESS, - None, - output_id, - ) except Exception as e: logger.error( f"Failed to finalize study {study.name} launch", @@ -275,24 +297,6 @@ def _check_studies_state(self) -> None: if all_done: self.stop() - def create_update_log( - self, job_id: str, study_id: str - ) -> Callable[[str], None]: - def update_log(log_line: str) -> None: - self.event_bus.push( - Event( - type=EventType.STUDY_JOB_LOG_UPDATE, - payload={ - "log": log_line, - "job_id": job_id, - "study_id": study_id, - }, - channel=EventChannelDirectory.JOB_LOGS + job_id, - ) - ) - - return update_log - @staticmethod def _get_log_path( study: StudyDTO, log_type: LogType = LogType.STDOUT @@ -370,6 +374,9 @@ def _run_study( self.storage_service.export_study_flat( study_uuid, params, study_path, outputs=False ) + self.callbacks.after_export_flat( + launch_uuid, study_uuid, study_path, launcher_params + ) self._assert_study_version_is_supported(study_uuid, params) @@ -428,6 +435,10 @@ def _check_and_apply_launcher_params( logger.warning( f"Invalid slurm launcher nb_cpu ({nb_cpu}), should be between 1 and 24" ) + if ( + launcher_params.get("adequacy_patch", None) is not None + ): # the adequacy patch can be an empty object + launcher_args.post_processing = True return launcher_args return self.launcher_args diff --git a/antarest/launcher/extensions/__init__.py b/antarest/launcher/extensions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/antarest/launcher/extensions/adequacy_patch/__init__.py b/antarest/launcher/extensions/adequacy_patch/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/antarest/launcher/extensions/adequacy_patch/extension.py b/antarest/launcher/extensions/adequacy_patch/extension.py new file mode 100644 index 0000000000..c57a10fe03 --- /dev/null +++ b/antarest/launcher/extensions/adequacy_patch/extension.py @@ -0,0 +1,54 @@ +import logging +import shutil +from pathlib import Path +from typing import Optional, Any, cast + +import yaml + +from antarest.core.model import JSON +from antarest.launcher.extensions.interface import ILauncherExtension +from antarest.study.storage.storage_service import StudyStorageService + +logger = logging.getLogger(__name__) + + +class AdequacyPatchExtension(ILauncherExtension): + EXTENSION_NAME = "adequacy_patch" + + def __init__(self, storage_service: StudyStorageService): + self.storage_service = storage_service + + def get_name(self) -> str: + return AdequacyPatchExtension.EXTENSION_NAME + + def after_export_flat_hook( + self, + job_id: str, + study_id: str, + study_export_path: Path, + launcher_opts: Any, + ) -> None: + logger.info("Applying adequacy patch postprocessing script") + post_processing_file = ( + Path(__file__).parent / "resources" / "post-processing.R" + ) + shutil.copy( + post_processing_file, study_export_path / "post-processing.R" + ) + self._check_config(study_id, study_export_path) + + def _check_config(self, study_id: str, study_export_path: Path) -> None: + ( + study_config, + study_tree, + ) = self.storage_service.raw_study_service.study_factory.create_from_fs( + study_export_path, study_id + ) + user_config = study_tree.get(["user"]) + assert "flowbased" in user_config or "Flowbased" in user_config + adequacy_patch_config = yaml.safe_load( + cast( + bytes, study_tree.get(["user", "adequacypatch", "config.yml"]) + ) + ) + assert "areas" in adequacy_patch_config diff --git a/antarest/launcher/extensions/adequacy_patch/resources/post-processing.R b/antarest/launcher/extensions/adequacy_patch/resources/post-processing.R new file mode 100644 index 0000000000..9dfd125e55 --- /dev/null +++ b/antarest/launcher/extensions/adequacy_patch/resources/post-processing.R @@ -0,0 +1,20 @@ +library(AdequacyPatch) +library(antaresRead) +library(yaml) + +opts <- setSimulationPath(".") + +print(readLayout(opts = opts)) + +config <- read_yaml("user/adequacypatch/config.yml", fileEncoding = "UTF-8", text) + +run_adq(opts = opts, + areas = config$areas, + virtual_areas = config$areas, + mcYears = config$mcYears, + antaresfbzone = config$antaresfbzone, + ext = NULL, + nbcl = 1, thresholdFilter = config$thresholdFilter, + core_ahc = config$core_ahc, + calculate_mc_all = config$calculate_mc_all, + log_detail = TRUE) \ No newline at end of file diff --git a/antarest/launcher/extensions/interface.py b/antarest/launcher/extensions/interface.py new file mode 100644 index 0000000000..97803a3080 --- /dev/null +++ b/antarest/launcher/extensions/interface.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Optional, Any + +from antarest.core.model import JSON + + +class ILauncherExtension(ABC): + @abstractmethod + def get_name(self) -> str: + raise NotImplementedError() + + @abstractmethod + def after_export_flat_hook( + self, + job_id: str, + study_id: str, + study_export_path: Path, + ext_opts: Any, + ) -> None: + pass diff --git a/antarest/launcher/service.py b/antarest/launcher/service.py index b4e1bb383f..fc425dbcff 100644 --- a/antarest/launcher/service.py +++ b/antarest/launcher/service.py @@ -1,6 +1,7 @@ import logging from datetime import datetime from http import HTTPStatus +from pathlib import Path from typing import List, Optional, cast, Dict from uuid import UUID @@ -20,6 +21,10 @@ ) from antarest.launcher.adapters.abstractlauncher import LauncherCallbacks from antarest.launcher.adapters.factory_launcher import FactoryLauncher +from antarest.launcher.extensions.adequacy_patch.extension import ( + AdequacyPatchExtension, +) +from antarest.launcher.extensions.interface import ILauncherExtension from antarest.launcher.model import JobResult, JobStatus, LogType from antarest.launcher.repository import JobResultRepository from antarest.study.service import StudyService @@ -67,14 +72,46 @@ def __init__( LauncherCallbacks( update_status=lambda jobid, status, msg, output_id: self.update( jobid, status, msg, output_id - ) + ), + after_export_flat=lambda job_id, study_id, study_path, launcher_opts: self.after_export_flat_hooks( + job_id, study_id, study_path, launcher_opts + ), ), event_bus, ) + self.extensions = self._init_extensions() + + def _init_extensions(self) -> Dict[str, ILauncherExtension]: + adequacy_patch_ext = AdequacyPatchExtension( + self.study_service.storage_service + ) + return {adequacy_patch_ext.get_name(): adequacy_patch_ext} def get_launchers(self) -> List[str]: return list(self.launchers.keys()) + def after_export_flat_hooks( + self, + job_id: str, + study_id: str, + study_exported_path: Path, + launcher_opts: Optional[JSON], + ) -> None: + for ext in self.extensions: + if ( + launcher_opts is not None + and launcher_opts.get(ext, None) is not None + ): + logger.info( + f"Applying extension {ext} after_export_flat_hook on job {job_id}" + ) + self.extensions[ext].after_export_flat_hook( + job_id, + study_id, + study_exported_path, + launcher_opts.get(ext), + ) + def update( self, job_uuid: str, @@ -120,6 +157,11 @@ def run_study( study_version = study_info.version self._assert_launcher_is_initialized(launcher) + assert_permission( + user=params.user, + study=study_info, + permission_type=StudyPermissionType.RUN, + ) job_uuid: UUID = self.launchers[launcher].run_study( study_uuid, str(study_version), launcher_parameters, params diff --git a/antarest/study/service.py b/antarest/study/service.py index 7e37e8a441..a1564d6c0b 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -2,6 +2,7 @@ import io import logging import os +import shutil from datetime import datetime from http import HTTPStatus from pathlib import Path @@ -792,6 +793,7 @@ def export_study_flat( dest: Path, outputs: bool = True, ) -> None: + logger.info(f"Flat exporting study {uuid}") study = self.get_study(uuid) assert_permission(params.user, study, StudyPermissionType.READ) self._assert_study_unarchived(study) @@ -1025,6 +1027,7 @@ def import_output( uuid: str, output: Union[IO[bytes], Path], params: RequestParameters, + additional_logs: Optional[List[Path]] = None, ) -> Optional[str]: """ Import specific output simulation inside study @@ -1032,6 +1035,7 @@ def import_output( uuid: study uuid output: zip file with simulation folder or simulation folder path params: request parameters + additional_logs: path to the simulation log Returns: output simulation json formatted @@ -1043,6 +1047,11 @@ def import_output( res = self.storage_service.get_storage(study).import_output( study, output ) + if res is not None and additional_logs: + for log_path in additional_logs: + shutil.copyfile( + log_path, Path(study.path) / "output" / res / log_path.name + ) remove_from_cache(cache=self.cache_service, root_id=study.id) logger.info( "output added to study %s by user %s", uuid, params.get_user_id() diff --git a/tests/launcher/test_extension_adequacy_patch.py b/tests/launcher/test_extension_adequacy_patch.py new file mode 100644 index 0000000000..ec8e3eed84 --- /dev/null +++ b/tests/launcher/test_extension_adequacy_patch.py @@ -0,0 +1,36 @@ +from pathlib import Path +from unittest.mock import Mock + +import pytest + +from antarest.launcher.extensions.adequacy_patch.extension import ( + AdequacyPatchExtension, +) + + +def test_hooks(tmp_path: Path): + storage_service = Mock() + adq_ext = AdequacyPatchExtension(storage_service) + assert adq_ext.get_name() == AdequacyPatchExtension.EXTENSION_NAME + + study_export_path = tmp_path / "study" + study_export_path.mkdir() + + study_tree = Mock() + study_config = Mock() + storage_service.raw_study_service.study_factory.create_from_fs.return_value = ( + study_config, + study_tree, + ) + + study_tree.get.side_effect = [{}, {"flowbased": {}}, '{"areas": []}'] + + with pytest.raises(AssertionError): + adq_ext.after_export_flat_hook( + "some-job", "some-study-id", study_export_path, {} + ) + + adq_ext.after_export_flat_hook( + "some-job", "some-study-id", study_export_path, {} + ) + assert (study_export_path / "post-processing.R").exists() diff --git a/tests/launcher/test_local_launcher.py b/tests/launcher/test_local_launcher.py index ef30cb0011..7a7aaf9995 100644 --- a/tests/launcher/test_local_launcher.py +++ b/tests/launcher/test_local_launcher.py @@ -1,4 +1,5 @@ -from unittest.mock import Mock +from pathlib import Path +from unittest.mock import Mock, call from uuid import uuid4 import pytest @@ -14,7 +15,7 @@ @pytest.mark.unit_test -def test_compute(): +def test_compute(tmp_path: Path): engine = create_engine("sqlite:///:memory:", echo=True) Base.metadata.create_all(engine) DBSessionMiddleware( @@ -22,16 +23,29 @@ def test_compute(): custom_engine=engine, session_args={"autocommit": False, "autoflush": False}, ) + storage_service = Mock() local_launcher = LocalLauncher( - Config(), storage_service=Mock(), callbacks=Mock() + Config(), + storage_service=storage_service, + callbacks=Mock(), + event_bus=Mock(), ) uuid = uuid4() - local_launcher.job_id_to_study_id = {str(uuid): "study-id"} + local_launcher.job_id_to_study_id = { + str(uuid): ("study-id", tmp_path / "run", Mock()) + } + storage_service.import_output.return_value = "some output" local_launcher._compute( - antares_solver_path="echo", study_path="Hello, World!", uuid=uuid + antares_solver_path="echo", + study_uuid="study-id", + uuid=uuid, + launcher_parameters=None, ) - local_launcher.callbacks.update_status.assert_called_once_with( - str(uuid), JobStatus.SUCCESS, None, None + local_launcher.callbacks.update_status.assert_has_calls( + [ + call(str(uuid), JobStatus.RUNNING, None, None), + call(str(uuid), JobStatus.SUCCESS, None, "some output"), + ] ) diff --git a/tests/launcher/test_service.py b/tests/launcher/test_service.py index 699112f956..c787840b7a 100644 --- a/tests/launcher/test_service.py +++ b/tests/launcher/test_service.py @@ -12,6 +12,7 @@ ) from antarest.core.interfaces.eventbus import Event, EventType from antarest.core.jwt import JWTUser, DEFAULT_ADMIN_USER +from antarest.core.model import PermissionInfo from antarest.core.requests import RequestParameters from antarest.launcher.model import JobResult, JobStatus from antarest.launcher.service import LauncherService @@ -30,7 +31,7 @@ def test_service_run_study(get_current_user_mock): created=1, updated=1, type="rawstudy", - owner=OwnerInfo(name="author"), + owner=OwnerInfo(id=0, name="author"), groups=[], public_mode=PublicMode.NONE, version=42, @@ -86,6 +87,7 @@ def test_service_run_study(get_current_user_mock): Event( type=EventType.STUDY_JOB_STARTED, payload=pending.to_dto().dict(), + permissions=PermissionInfo(owner=0), ) ) diff --git a/tests/launcher/test_slurm_launcher.py b/tests/launcher/test_slurm_launcher.py index 177ee59d99..9230097244 100644 --- a/tests/launcher/test_slurm_launcher.py +++ b/tests/launcher/test_slurm_launcher.py @@ -203,6 +203,11 @@ def test_extra_parameters(launcher_config: Config): ) assert launcher_params.post_processing + launcher_params = slurm_launcher._check_and_apply_launcher_params( + {"adequacy_patch": {}} + ) + assert launcher_params.post_processing + @pytest.mark.parametrize( "version,job_status", [(42, JobStatus.RUNNING), (99, JobStatus.FAILED)] @@ -356,6 +361,7 @@ def test_import_study_output(launcher_config): / "1" / "output", params=ANY, + additional_logs=[], ) assert res == "output" diff --git a/webapp/src/components/ui/LauncherModal.tsx b/webapp/src/components/ui/LauncherModal.tsx index 825d5d617f..c6c6251aed 100644 --- a/webapp/src/components/ui/LauncherModal.tsx +++ b/webapp/src/components/ui/LauncherModal.tsx @@ -106,9 +106,10 @@ const LauncherModal = (props: PropTypes) => { }; const handleChange = (field: string, value: number | string | boolean) => { + const val = field === 'adequacy_patch' ? {} : value; setOptions({ ...options, - [field]: value, + [field]: val, }); }; @@ -176,6 +177,7 @@ const LauncherModal = (props: PropTypes) => { { handleChange('xpansion', checked); }} />} label={t('singlestudy:xpansionMode')} /> handleChange('xpansion_r_version', checked)} />} label={t('singlestudy:useXpansionVersionR')} /> + handleChange('adequacy_patch', checked)} />} label="Mode adequacy" />
diff --git a/webapp/src/services/api/study.ts b/webapp/src/services/api/study.ts index 35f0603580..e3d9ba6675 100644 --- a/webapp/src/services/api/study.ts +++ b/webapp/src/services/api/study.ts @@ -142,6 +142,8 @@ export interface LaunchOptions { time_limit?: number; // eslint-disable-next-line camelcase post_processing?: boolean; + // eslint-disable-next-line camelcase + adequacy_patch?: object; } export const launchStudy = async (sid: string, options: LaunchOptions = {}): Promise => { From c08f79f68efb8d972f2f4338360b4b02b9b0e264 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Tue, 1 Feb 2022 17:13:43 +0100 Subject: [PATCH 11/23] Fix websocket channel resubscription Signed-off-by: Paul Bui-Quang --- webapp/src/ducks/websockets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/ducks/websockets.ts b/webapp/src/ducks/websockets.ts index 653a82cbf1..988b680da5 100644 --- a/webapp/src/ducks/websockets.ts +++ b/webapp/src/ducks/websockets.ts @@ -169,7 +169,7 @@ export const connectWebsocket = (user?: UserInfo): ThunkAction { From 6c6c9e555ac28c92d92312fab8bc2eb5cb3fec72 Mon Sep 17 00:00:00 2001 From: Charly Bion <37449809+Hyralc@users.noreply.github.com> Date: Fri, 4 Feb 2022 09:05:58 +0100 Subject: [PATCH 12/23] Create only needed services (#735) --- antarest/main.py | 113 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 90 insertions(+), 23 deletions(-) diff --git a/antarest/main.py b/antarest/main.py index c730de8aba..9ad889b6de 100644 --- a/antarest/main.py +++ b/antarest/main.py @@ -22,6 +22,8 @@ from antarest.core.core_blueprint import create_utils_routes from antarest.core.exceptions import UnknownModuleError from antarest.core.filetransfer.main import build_filetransfer_service +from antarest.core.interfaces.cache import ICache +from antarest.core.interfaces.eventbus import IEventBus from antarest.core.logging.utils import configure_logger, LoggingMiddleware from antarest.core.maintenance.main import build_maintenance_manager from antarest.core.persistence import upgrade_db @@ -35,14 +37,17 @@ ) from antarest.core.utils.web import tags_metadata from antarest.eventbus.main import build_eventbus -from antarest.matrixstore.matrix_garbage_collector import ( - MatrixGarbageCollector, -) from antarest.launcher.main import build_launcher from antarest.login.auth import Auth, JwtSettings from antarest.login.main import build_login +from antarest.login.service import LoginService from antarest.matrixstore.main import build_matrix_service +from antarest.matrixstore.matrix_garbage_collector import ( + MatrixGarbageCollector, +) +from antarest.matrixstore.service import MatrixService from antarest.study.main import build_study_service +from antarest.study.service import StudyService from antarest.study.storage.rawstudy.watcher import Watcher logger = logging.getLogger(__name__) @@ -171,37 +176,27 @@ def init_db( ) -def create_services( - config: Config, application: Optional[FastAPI], create_all: bool = False -) -> Dict[str, Any]: - services: Dict[str, Any] = {} - +def create_core_services( + application: Optional[FastAPI], config: Config +) -> Tuple[ICache, IEventBus, LoginService, MatrixService, StudyService]: redis_client = ( new_redis_instance(config.redis) if config.redis is not None else None ) event_bus = build_eventbus(application, config, True, redis_client) cache = build_cache(config=config, redis_client=redis_client) - - maintenance_service = build_maintenance_manager( - application, config=config, cache=cache, event_bus=event_bus - ) - filetransfer_service = build_filetransfer_service( application, event_bus, config ) task_service = build_taskjob_manager(application, config, event_bus) - - user_service = build_login(application, config, event_bus=event_bus) - + login_service = build_login(application, config, event_bus=event_bus) matrix_service = build_matrix_service( application, config=config, file_transfer_manager=filetransfer_service, task_service=task_service, - user_service=user_service, + user_service=login_service, service=None, ) - study_service = build_study_service( application, config, @@ -209,9 +204,71 @@ def create_services( cache=cache, file_transfer_manager=filetransfer_service, task_service=task_service, - user_service=user_service, + user_service=login_service, event_bus=event_bus, ) + return ( + cache, + event_bus, + login_service, + matrix_service, + study_service, + ) + + +def create_watcher( + config: Config, + application: Optional[FastAPI], + study_service: Optional[StudyService] = None, +) -> Watcher: + if study_service: + return Watcher(config=config, service=study_service) + else: + _, _, _, _, study_service = create_core_services(application, config) + + return Watcher(config=config, service=study_service) + + +def create_matrix_gc( + config: Config, + application: Optional[FastAPI], + study_service: Optional[StudyService] = None, + matrix_service: Optional[MatrixService] = None, +) -> MatrixGarbageCollector: + + if study_service and matrix_service: + return MatrixGarbageCollector( + config=config, + study_service=study_service, + matrix_service=matrix_service, + ) + else: + _, _, _, matrix_service, study_service = create_core_services( + application, config + ) + return MatrixGarbageCollector( + config=config, + study_service=study_service, + matrix_service=matrix_service, + ) + + +def create_services( + config: Config, application: Optional[FastAPI], create_all: bool = False +) -> Dict[str, Any]: + services: Dict[str, Any] = {} + + ( + cache, + event_bus, + user_service, + matrix_service, + study_service, + ) = create_core_services(application, config) + + maintenance_service = build_maintenance_manager( + application, config=config, cache=cache, event_bus=event_bus + ) launcher = build_launcher( application, @@ -221,12 +278,15 @@ def create_services( ) if Module.WATCHER.value in config.server.services or create_all: - watcher = Watcher(config=config, service=study_service) + watcher = create_watcher( + config=config, application=application, study_service=study_service + ) services["watcher"] = watcher if Module.MATRIX_GC.value in config.server.services or create_all: - matrix_garbage_collector = MatrixGarbageCollector( + matrix_garbage_collector = create_matrix_gc( config=config, + application=application, study_service=study_service, matrix_service=matrix_service, ) @@ -404,7 +464,14 @@ def handle_all_exception(request: Request, exc: Exception) -> Any: config = Config.from_yaml_file(res=res, file=config_file) configure_logger(config) init_db(config_file, config, False, None) - services = create_services(config, None, True) - cast(Watcher, services["watcher"]).start(threaded=False) + watcher = create_watcher(config=config, application=None) + watcher.start(threaded=False) + elif module == Module.MATRIX_GC: + res = get_local_path() / "resources" + config = Config.from_yaml_file(res=res, file=config_file) + configure_logger(config) + init_db(config_file, config, False, None) + matrix_gc = create_matrix_gc(config=config, application=None) + matrix_gc.start() else: raise UnknownModuleError(module) From 5228eb5332bb37282b5ee218cfd300a39dc57b9e Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 31 Jan 2022 17:47:59 +0100 Subject: [PATCH 13/23] Revert "Temporary fix of pip" This reverts commit 2cdf89738609bd487ac06fd6d7a98cca2063fac3. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 71a47742ad..ee2825af17 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN cp /antares-launcher/requirements.txt /conf/antares-launcher/requirements.tx RUN ./scripts/install-debug.sh -RUN pip3 install --upgrade pip==21.3.1 \ +RUN pip3 install --upgrade pip \ && pip3 install -r /conf/requirements.txt From fff10c5875f7c77f0e364bb2c1b8c35c493d9854 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Tue, 8 Feb 2022 10:58:40 +0100 Subject: [PATCH 14/23] Add task system to archive method (#737) --- antarest/core/tasks/model.py | 1 + antarest/core/tasks/repository.py | 19 ++- antarest/study/service.py | 111 +++++++++++++----- antarest/study/web/studies_blueprint.py | 6 +- tests/integration/test_integration.py | 35 ++++++ webapp/public/locales/en/studymanager.json | 2 + webapp/public/locales/fr/studymanager.json | 2 + .../DownloadsListing/DownloadBadge.tsx | 4 + .../SingleStudy/InformationView.tsx | 2 - webapp/src/components/StudyListing/index.tsx | 2 - webapp/src/services/api/tasks.ts | 2 +- 11 files changed, 147 insertions(+), 39 deletions(-) diff --git a/antarest/core/tasks/model.py b/antarest/core/tasks/model.py index 7f75f7ff52..53ada976bc 100644 --- a/antarest/core/tasks/model.py +++ b/antarest/core/tasks/model.py @@ -15,6 +15,7 @@ class TaskType(str, Enum): VARIANT_GENERATION = "VARIANT_GENERATION" COPY = "COPY" ARCHIVE = "ARCHIVE" + UNARCHIVE = "UNARCHIVE" class TaskStatus(Enum): diff --git a/antarest/core/tasks/repository.py b/antarest/core/tasks/repository.py index 32d2687ecf..46a3d3da51 100644 --- a/antarest/core/tasks/repository.py +++ b/antarest/core/tasks/repository.py @@ -1,7 +1,7 @@ import datetime from http import HTTPStatus from operator import and_ -from typing import Optional, List +from typing import Optional, List, Any from fastapi import HTTPException @@ -28,11 +28,22 @@ def get_or_raise(self, id: str) -> TaskJob: raise HTTPException(HTTPStatus.NOT_FOUND, f"Task {id} not found") return task + @staticmethod + def _combine_clauses(where_clauses: List[Any]) -> Any: + assert len(where_clauses) > 0 + if len(where_clauses) > 1: + return and_( + where_clauses[0], + TaskJobRepository._combine_clauses(where_clauses[1:]), + ) + else: + return where_clauses[0] + def list( self, filter: TaskListFilter, user: Optional[int] = None ) -> List[TaskJob]: query = db.session.query(TaskJob) - where_clauses = [] + where_clauses: List[Any] = [] if user: where_clauses.append(TaskJob.owner_id == user) if len(filter.status) > 0: @@ -82,7 +93,9 @@ def list( ) ) if len(where_clauses) > 1: - query = query.where(and_(*where_clauses)) + query = query.where( + TaskJobRepository._combine_clauses(where_clauses) + ) elif len(where_clauses) == 1: query = query.where(*where_clauses) diff --git a/antarest/study/service.py b/antarest/study/service.py index a1564d6c0b..ff15434bfe 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -34,7 +34,12 @@ UserHasNotPermissionError, ) from antarest.core.roles import RoleType -from antarest.core.tasks.model import TaskResult, TaskType +from antarest.core.tasks.model import ( + TaskResult, + TaskType, + TaskListFilter, + TaskStatus, +) from antarest.core.tasks.service import ( ITaskService, TaskUpdateNotifier, @@ -1442,7 +1447,7 @@ def delete_link( self._assert_study_unarchived(study) return self.links.delete_link(study, area_from, area_to) - def archive(self, uuid: str, params: RequestParameters) -> None: + def archive(self, uuid: str, params: RequestParameters) -> str: study = self.get_study(uuid) assert_permission(params.user, study, StudyPermissionType.DELETE) @@ -1454,47 +1459,99 @@ def archive(self, uuid: str, params: RequestParameters) -> None: if not is_managed(study): raise NotAManagedStudyException(study.id) - self.storage_service.raw_study_service.archive(study) - study.archived = True - self.repository.save(study) - self.event_bus.push( - Event( - type=EventType.STUDY_EDITED, - payload=study.to_json_summary(), - permissions=create_permission_from_study(study), + if self.task_service.list_tasks( + TaskListFilter( + ref_id=uuid, + type=[TaskType.ARCHIVE], + status=[TaskStatus.RUNNING, TaskStatus.PENDING], + ), + RequestParameters(user=DEFAULT_ADMIN_USER), + ): + raise HTTPException( + HTTPStatus.BAD_REQUEST, "Study is already archiving" + ) + + def archive_task(notifier: TaskUpdateNotifier) -> TaskResult: + study_to_archive = self.get_study(uuid) + self.storage_service.raw_study_service.archive(study_to_archive) + study_to_archive.archived = True + self.repository.save(study_to_archive) + self.event_bus.push( + Event( + type=EventType.STUDY_EDITED, + payload=study_to_archive.to_json_summary(), + permissions=create_permission_from_study(study_to_archive), + ) ) + return TaskResult(success=True, message="ok") + + return self.task_service.add_task( + archive_task, + f"Study {study.name} archiving", + task_type=TaskType.ARCHIVE, + ref_id=study.id, + custom_event_messages=None, + request_params=params, ) - def unarchive(self, uuid: str, params: RequestParameters) -> None: + def unarchive(self, uuid: str, params: RequestParameters) -> str: study = self.get_study(uuid) if not study.archived: raise HTTPException( HTTPStatus.BAD_REQUEST, "Study is not archived" ) + if self.task_service.list_tasks( + TaskListFilter( + ref_id=uuid, + type=[TaskType.UNARCHIVE], + status=[TaskStatus.RUNNING, TaskStatus.PENDING], + ), + RequestParameters(user=DEFAULT_ADMIN_USER), + ): + raise HTTPException( + HTTPStatus.BAD_REQUEST, "Study is already unarchiving" + ) + assert_permission(params.user, study, StudyPermissionType.DELETE) if not isinstance(study, RawStudy): raise StudyTypeUnsupported(study.id, study.type) - with open( - self.storage_service.raw_study_service.get_archive_path(study), - "rb", - ) as fh: - self.storage_service.raw_study_service.import_study( - study, io.BytesIO(fh.read()) + def unarchive_task(notifier: TaskUpdateNotifier) -> TaskResult: + study_to_archive = self.get_study(uuid) + with open( + self.storage_service.raw_study_service.get_archive_path( + study_to_archive + ), + "rb", + ) as fh: + self.storage_service.raw_study_service.import_study( + study_to_archive, io.BytesIO(fh.read()) + ) + study_to_archive.archived = False + os.unlink( + self.storage_service.raw_study_service.get_archive_path( + study_to_archive + ) ) - study.archived = False - os.unlink( - self.storage_service.raw_study_service.get_archive_path(study) - ) - self.repository.save(study) - self.event_bus.push( - Event( - type=EventType.STUDY_EDITED, - payload=study.to_json_summary(), - permissions=create_permission_from_study(study), + self.repository.save(study_to_archive) + self.event_bus.push( + Event( + type=EventType.STUDY_EDITED, + payload=study.to_json_summary(), + permissions=create_permission_from_study(study), + ) ) + return TaskResult(success=True, message="ok") + + return self.task_service.add_task( + unarchive_task, + f"Study {study.name} unarchiving", + task_type=TaskType.UNARCHIVE, + ref_id=study.id, + custom_event_messages=None, + request_params=params, ) def _save_study( diff --git a/antarest/study/web/studies_blueprint.py b/antarest/study/web/studies_blueprint.py index 59f4a58ab7..0088945147 100644 --- a/antarest/study/web/studies_blueprint.py +++ b/antarest/study/web/studies_blueprint.py @@ -541,8 +541,7 @@ def archive_study( ) study_id = sanitize_uuid(study_id) params = RequestParameters(user=current_user) - study_service.archive(study_id, params) - return "" + return study_service.archive(study_id, params) @bp.put( "/studies/{study_id}/unarchive", @@ -558,7 +557,6 @@ def unarchive_study( ) study_id = sanitize_uuid(study_id) params = RequestParameters(user=current_user) - study_service.unarchive(study_id, params) - return "" + return study_service.unarchive(study_id, params) return bp diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 70a279bba8..8ce7bb2a2d 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -1,4 +1,5 @@ import time +from typing import Callable from pathlib import Path from unittest.mock import ANY @@ -10,6 +11,18 @@ from antarest.study.model import MatrixIndex, StudyDownloadLevelDTO +def wait_for(predicate: Callable[[], bool], timeout=10): + end = time.time() + timeout + while time.time() < end: + try: + if predicate(): + return + except Exception as e: + pass + time.sleep(1) + raise TimeoutError() + + def init_test(app: FastAPI): client = TestClient(app, raise_server_exceptions=False) @@ -619,6 +632,16 @@ def test_archive(app: FastAPI, tmp_path: Path): }, ) assert res.status_code == 200 + task_id = res.json() + wait_for( + lambda: client.get( + f"/v1/tasks/{task_id}", + headers={ + "Authorization": f'Bearer {admin_credentials["access_token"]}' + }, + ).json()["status"] + == 3 + ) res = client.get( f"/v1/studies/{study_id}", @@ -635,6 +658,18 @@ def test_archive(app: FastAPI, tmp_path: Path): "Authorization": f'Bearer {admin_credentials["access_token"]}' }, ) + + task_id = res.json() + wait_for( + lambda: client.get( + f"/v1/tasks/{task_id}", + headers={ + "Authorization": f'Bearer {admin_credentials["access_token"]}' + }, + ).json()["status"] + == 3 + ) + res = client.get( f"/v1/studies/{study_id}", headers={ diff --git a/webapp/public/locales/en/studymanager.json b/webapp/public/locales/en/studymanager.json index 7f37dc704c..befac9b041 100644 --- a/webapp/public/locales/en/studymanager.json +++ b/webapp/public/locales/en/studymanager.json @@ -14,6 +14,8 @@ "failtocopystudy": "Failed to copy study", "studycopiedsuccess": "Success copying study", "studycopying": "Copying study...", + "studyarchiving": "Archiving study...", + "studyunarchiving": "Unarchiving study...", "archive": "Archive", "unarchive": "Unarchive", "archivesuccess": "Study {{studyname}} archived", diff --git a/webapp/public/locales/fr/studymanager.json b/webapp/public/locales/fr/studymanager.json index ef22554e40..b9e313a1e8 100644 --- a/webapp/public/locales/fr/studymanager.json +++ b/webapp/public/locales/fr/studymanager.json @@ -14,6 +14,8 @@ "failtocopystudy": "Erreur lors de la copie de l'étude", "studycopiedsuccess": "Etude copiée avec succès", "studycopying": "Etude en cours de copie...", + "studyarchiving": "Etude en cours d'archivage...", + "studyunarchiving": "Etude en cours de désarchivage...", "archive": "Archiver", "unarchive": "Désarchiver", "archivesuccess": "Etude {{studyname}} archivée", diff --git a/webapp/src/components/DownloadsListing/DownloadBadge.tsx b/webapp/src/components/DownloadsListing/DownloadBadge.tsx index 1418f1dada..62a5b57ebd 100644 --- a/webapp/src/components/DownloadsListing/DownloadBadge.tsx +++ b/webapp/src/components/DownloadsListing/DownloadBadge.tsx @@ -70,6 +70,10 @@ const DownloadBadge = (props: PropTypes) => { const task = await getTask(taskId); if (task.type === 'COPY') { setNotificationMessage('studymanager:studycopying'); + } else if (task.type === 'ARCHIVE') { + setNotificationMessage('studymanager:studyarchiving'); + } else if (task.type === 'UNARCHIVE') { + setNotificationMessage('studymanager:studyunarchiving'); } } catch (error) { logError(error); diff --git a/webapp/src/components/SingleStudy/InformationView.tsx b/webapp/src/components/SingleStudy/InformationView.tsx index 47134e5868..78ad414baf 100644 --- a/webapp/src/components/SingleStudy/InformationView.tsx +++ b/webapp/src/components/SingleStudy/InformationView.tsx @@ -257,7 +257,6 @@ const InformationView = (props: PropTypes) => { const archiveStudy = async () => { try { await callArchiveStudy(study.id); - enqueueSnackbar(t('studymanager:archivesuccess', { studyname: study.name }), { variant: 'success' }); } catch (e) { enqueueErrorSnackbar(enqueueSnackbar, t('studymanager:archivefailure', { studyname: study.name }), e as AxiosError); } @@ -266,7 +265,6 @@ const InformationView = (props: PropTypes) => { const unarchiveStudy = async () => { try { await callUnarchiveStudy(study.id); - enqueueSnackbar(t('studymanager:unarchivesuccess', { studyname: study.name }), { variant: 'success' }); } catch (e) { enqueueErrorSnackbar(enqueueSnackbar, t('studymanager:unarchivefailure', { studyname: study.name }), e as AxiosError); } diff --git a/webapp/src/components/StudyListing/index.tsx b/webapp/src/components/StudyListing/index.tsx index 7a2e84f6cf..24f4ab9874 100644 --- a/webapp/src/components/StudyListing/index.tsx +++ b/webapp/src/components/StudyListing/index.tsx @@ -105,7 +105,6 @@ const StudyListing = (props: PropTypes) => { const archiveStudy = async (study: StudyMetadata) => { try { await callArchiveStudy(study.id); - enqueueSnackbar(t('studymanager:archivesuccess', { studyname: study.name }), { variant: 'success' }); } catch (e) { enqueueErrorSnackbar(enqueueSnackbar, t('studymanager:archivefailure', { studyname: study.name }), e as AxiosError); } @@ -114,7 +113,6 @@ const StudyListing = (props: PropTypes) => { const unarchiveStudy = async (study: StudyMetadata) => { try { await callUnarchiveStudy(study.id); - enqueueSnackbar(t('studymanager:unarchivesuccess', { studyname: study.name }), { variant: 'success' }); } catch (e) { enqueueErrorSnackbar(enqueueSnackbar, t('studymanager:unarchivefailure', { studyname: study.name }), e as AxiosError); } diff --git a/webapp/src/services/api/tasks.ts b/webapp/src/services/api/tasks.ts index 7206549c20..dbac111ec6 100644 --- a/webapp/src/services/api/tasks.ts +++ b/webapp/src/services/api/tasks.ts @@ -20,7 +20,7 @@ export const getAllRunningTasks = async (): Promise> => { export const getAllMiscRunningTasks = async (): Promise> => { const res = await client.post('/v1/tasks', { status: [TaskStatus.RUNNING, TaskStatus.PENDING, TaskStatus.FAILED, TaskStatus.COMPLETED], - type: ['COPY', 'ARCHIVE'], + type: ['COPY', 'ARCHIVE', 'UNARCHIVE'], }); return res.data; }; From 9102ef328028bf4f5fe59373fc7dc202b6457e6b Mon Sep 17 00:00:00 2001 From: Charly Bion <37449809+Hyralc@users.noreply.github.com> Date: Tue, 8 Feb 2022 11:51:25 +0100 Subject: [PATCH 15/23] Add xpansion model into filestudytree #730 (#736) --- .../storage/rawstudy/io/reader/ini_reader.py | 43 +++++++++++++ .../rawstudy/model/filesystem/bucket_node.py | 44 +++++++++++-- .../model/filesystem/ini_file_node.py | 4 +- .../model/filesystem/root/filestudytree.py | 4 +- .../model/filesystem/root/user/__init__.py | 0 .../root/user/expansion/__init__.py | 0 .../root/user/expansion/candidates.py | 23 +++++++ .../root/{user.py => user/expansion/capa.py} | 2 +- .../root/user/expansion/expansion.py | 27 ++++++++ .../root/user/expansion/settings.py | 60 ++++++++++++++++++ .../model/filesystem/root/user/user.py | 18 ++++++ examples/studies/STA-mini.zip | Bin 434178 -> 435114 bytes tests/storage/integration/test_STA_mini.py | 38 +++++++++++ .../repository/filesystem/test_bucket_node.py | 19 ++++++ 14 files changed, 272 insertions(+), 10 deletions(-) create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/user/__init__.py create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/__init__.py create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/candidates.py rename antarest/study/storage/rawstudy/model/filesystem/root/{user.py => user/expansion/capa.py} (75%) create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/expansion.py create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/settings.py create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/user/user.py diff --git a/antarest/study/storage/rawstudy/io/reader/ini_reader.py b/antarest/study/storage/rawstudy/io/reader/ini_reader.py index 2a077ed6e0..f60ce25a7d 100644 --- a/antarest/study/storage/rawstudy/io/reader/ini_reader.py +++ b/antarest/study/storage/rawstudy/io/reader/ini_reader.py @@ -77,6 +77,49 @@ def read(self, path: Path) -> JSON: } +class SimpleKeyValueReader(IReader): + """ + Standard .ini file reader. Use for general purpose. + """ + + @staticmethod + def _parse_inf(value: str) -> Optional[str]: + try: + return "inf" if float(value) == float("inf") else None + except ValueError: + return None + + @staticmethod + def parse_value(value: str) -> ELEMENT: + parsed: Union[ + str, int, float, bool, None + ] = SimpleKeyValueReader._parse_inf(value) + parsed = parsed if parsed is not None else IniReader._parse_bool(value) + parsed = parsed if parsed is not None else IniReader._parse_int(value) + parsed = ( + parsed if parsed is not None else IniReader._parse_float(value) + ) + return parsed if parsed is not None else value + + @staticmethod + def _parse_json(json: JSON) -> JSON: + return { + key: SimpleKeyValueReader.parse_value(value) + for key, value in json.items() + } + + def read(self, path: Path) -> JSON: + with open(path, "r") as f: + json = {} + for line in f.readlines(): + line = line.strip() + if line and not line.startswith("#"): + key, value = line.split("=") + json[key] = value + + return self._parse_json(json) + + class IniConfigParser(configparser.RawConfigParser): def optionxform(self, optionstr: str) -> str: return optionstr diff --git a/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py b/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py index f9b6db0071..fe911a4d8c 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/bucket_node.py @@ -1,13 +1,16 @@ -from typing import Optional, List, Union, Dict +from typing import Optional, List, Union, Dict, Callable, Any, Mapping from antarest.core.model import JSON from antarest.study.storage.rawstudy.model.filesystem.config.model import ( FileStudyTreeConfig, ) +from antarest.study.storage.rawstudy.model.filesystem.context import ( + ContextServer, +) from antarest.study.storage.rawstudy.model.filesystem.folder_node import ( FolderNode, ) -from antarest.study.storage.rawstudy.model.filesystem.inode import TREE +from antarest.study.storage.rawstudy.model.filesystem.inode import TREE, INode from antarest.study.storage.rawstudy.model.filesystem.raw_file_node import ( RawFileNode, ) @@ -18,6 +21,22 @@ class BucketNode(FolderNode): Node to handle structure free, user purpose folder. BucketNode accept any file or sub folder as children. """ + def __init__( + self, + context: ContextServer, + config: FileStudyTreeConfig, + registered_files: Optional[ + Mapping[ + str, + Callable[ + [ContextServer, FileStudyTreeConfig], INode[Any, Any, Any] + ], + ] + ] = None, + ): + super().__init__(context, config) + self.registered_files = registered_files or {} + def save( self, data: Union[str, int, bool, float, bytes, JSON], @@ -30,15 +49,24 @@ def save( else: key = url[0] if len(url) > 1: - BucketNode(self.context, self.config.next_file(key)).save( - data, url[1:] - ) + if key in self.registered_files: + self.registered_files[key]( + self.context, self.config.next_file(key) + ).save(data, url[1:]) + else: + BucketNode(self.context, self.config.next_file(key)).save( + data, url[1:] + ) else: self._save(data, key) def _save( self, data: Union[str, int, bool, float, bytes, JSON], key: str ) -> None: + if key in self.registered_files: + self.registered_files[key]( + self.context, self.config.next_file(key) + ).save(data) if isinstance(data, (str, bytes)): RawFileNode(self.context, self.config.next_file(key)).save(data) elif isinstance(data, dict): @@ -50,7 +78,11 @@ def build(self) -> TREE: children: TREE = {} for item in sorted(self.config.path.iterdir()): - if item.is_file(): + if item.name in self.registered_files: + children[item.name.split(".")[0]] = self.registered_files[ + item.name + ](self.context, self.config.next_file(item.name)) + elif item.is_file(): children[item.name] = RawFileNode( self.context, self.config.next_file(item.name) ) diff --git a/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py b/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py index 66d7fc10e7..4f68efbdd7 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py +++ b/antarest/study/storage/rawstudy/model/filesystem/ini_file_node.py @@ -32,14 +32,14 @@ def __init__( self, context: ContextServer, config: FileStudyTreeConfig, - types: Dict[str, Any], + types: Optional[Dict[str, Any]] = None, reader: Optional[IReader] = None, writer: Optional[IniWriter] = None, ): super().__init__(config) self.context = context self.path = config.path - self.types = types + self.types = types or {} self.reader = reader or IniReader() self.writer = writer or IniWriter() diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py b/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py index b695653ae5..bb0e56e154 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/filestudytree.py @@ -21,7 +21,9 @@ from antarest.study.storage.rawstudy.model.filesystem.root.study_antares import ( StudyAntares, ) -from antarest.study.storage.rawstudy.model.filesystem.root.user import User +from antarest.study.storage.rawstudy.model.filesystem.root.user.user import ( + User, +) class FileStudyTree(FolderNode): diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user/__init__.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/__init__.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/candidates.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/candidates.py new file mode 100644 index 0000000000..771274273d --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/candidates.py @@ -0,0 +1,23 @@ +from antarest.study.storage.rawstudy.io.reader import IniReader +from antarest.study.storage.rawstudy.io.writer.ini_writer import IniWriter +from antarest.study.storage.rawstudy.model.filesystem.config.model import ( + FileStudyTreeConfig, +) +from antarest.study.storage.rawstudy.model.filesystem.context import ( + ContextServer, +) +from antarest.study.storage.rawstudy.model.filesystem.ini_file_node import ( + IniFileNode, +) + + +class ExpansionCandidates(IniFileNode): + def __init__(self, context: ContextServer, config: FileStudyTreeConfig): + IniFileNode.__init__( + self, + context, + config, + types={}, + reader=IniReader(), + writer=IniWriter(), + ) diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/capa.py similarity index 75% rename from antarest/study/storage/rawstudy/model/filesystem/root/user.py rename to antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/capa.py index 80e91f6acb..83c7fb2cff 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/user.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/capa.py @@ -3,5 +3,5 @@ ) -class User(BucketNode): +class ExpansionCapa(BucketNode): pass diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/expansion.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/expansion.py new file mode 100644 index 0000000000..40bd273b56 --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/expansion.py @@ -0,0 +1,27 @@ +from antarest.study.storage.rawstudy.model.filesystem.folder_node import ( + FolderNode, +) +from antarest.study.storage.rawstudy.model.filesystem.inode import TREE +from antarest.study.storage.rawstudy.model.filesystem.root.user.expansion.candidates import ( + ExpansionCandidates, +) +from antarest.study.storage.rawstudy.model.filesystem.root.user.expansion.capa import ( + ExpansionCapa, +) +from antarest.study.storage.rawstudy.model.filesystem.root.user.expansion.settings import ( + ExpansionSettings, +) + + +class Expansion(FolderNode): + def build(self) -> TREE: + children: TREE = { + "candidates": ExpansionCandidates( + self.context, self.config.next_file("candidates.ini") + ), + "settings": ExpansionSettings( + self.context, self.config.next_file("settings.ini") + ), + "capa": ExpansionCapa(self.context, self.config.next_file("capa")), + } + return children diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/settings.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/settings.py new file mode 100644 index 0000000000..5f04d8db33 --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/root/user/expansion/settings.py @@ -0,0 +1,60 @@ +from antarest.study.storage.rawstudy.io.reader import IniReader +from antarest.study.storage.rawstudy.io.reader.ini_reader import ( + SimpleKeyValueReader, +) +from antarest.study.storage.rawstudy.io.writer.ini_writer import IniWriter +from antarest.study.storage.rawstudy.model.filesystem.config.model import ( + FileStudyTreeConfig, +) +from antarest.study.storage.rawstudy.model.filesystem.context import ( + ContextServer, +) +from antarest.study.storage.rawstudy.model.filesystem.ini_file_node import ( + IniFileNode, +) + + +class ExpansionSettings(IniFileNode): + # /!\ The name of all the parameters is correct. Especially the differences of "_" and "-" in parameter names. + """ + Common: + optimality_gap:float = 1 + max_iteration:int = inf + uc_type:str = "expansion_fast" or "expansion_accurate". default="expansion_fast" + master:str = "integer" or "relaxed". default="integer" + yearly-weights:str = filename. default = None + additional-constraints:str = filename. default = None + version < 800 only: + relaxed-optimality-gap:float = 1e6 + cut-type:str = "average", "yearly" or "weekly". default="yearly" + ampl.solver:str = "cbc" + ampl.presolve:int = 0 + ampl.solve_bounds_frequency:int = 1000000 + version >= 800 only: + relative_gap:float = 1e-12 + solver:str = "Cbc" or "Coin". default="Cbc" + """ + + def __init__(self, context: ContextServer, config: FileStudyTreeConfig): + super().__init__(context, config, reader=SimpleKeyValueReader()) + types = { + "optimality_gap": float, + "max_iteration": int, + "uc_type": str, + "master": str, + "yearly-weights": str, + "relaxed-optimality-gap": float, + "cut-type": str, + "additional_constraints": str, + "ampl.solver": str, + "ampl.presolve": int, + "ampl.solve_bounds_frequency": int, + } + if self.config.version > 800: + types["relative-gap"] = float + types["solver"] = str + del types["relaxed-optimality-gap"] + del types["cut-type"] + del types["ampl.solver"] + del types["ampl.presolve"] + del types["ampl.solve_bounds_frequency"] diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/user/user.py b/antarest/study/storage/rawstudy/model/filesystem/root/user/user.py new file mode 100644 index 0000000000..1a7df78eb0 --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/root/user/user.py @@ -0,0 +1,18 @@ +from antarest.study.storage.rawstudy.model.filesystem.bucket_node import ( + BucketNode, +) +from antarest.study.storage.rawstudy.model.filesystem.config.model import ( + FileStudyTreeConfig, +) +from antarest.study.storage.rawstudy.model.filesystem.context import ( + ContextServer, +) +from antarest.study.storage.rawstudy.model.filesystem.root.user.expansion.expansion import ( + Expansion, +) + + +class User(BucketNode): + def __init__(self, context: ContextServer, config: FileStudyTreeConfig): + planned_files = {"expansion": Expansion} + super().__init__(context, config, planned_files) diff --git a/examples/studies/STA-mini.zip b/examples/studies/STA-mini.zip index 60f9d9eb45c2237bfd8ccce89aea0ef3c25c2f2a..4fd278fe7673c4649693b6135f3fd9af73fd9fc4 100644 GIT binary patch delta 995 zcmZoVAhqhaR6`463sVd87M6ld^~@|>3?LBO=^g@RKnYm}8HV5xN8Q}ayiEPl;?yGj z)QW<{yyDFKJpJUvf<*n$5Kac>i7t#uAY59(&A`aA`t#vTFcIJlGj;-+v1(|>)}xx6 zmy(&1Sdv<-2ecJz!F!r88H7c#I4TDrgoUn_rw-Qj(dM zjxgQFtDZ4wsTYRvzI~2DhZJ~Rzt358+1Bswj?Y|ijh>3GX&MSGQF-}M*~i~}y6^w5 zzw-{yy})3xpz`XWs{O&v9QuCTOLZ4)=kKf>zNy;Gc5 z@weLj7jGtWEq3S8I3TfoFN=PCDNn1>hl8HRRS_3YRESM-SKPxH>-q0f;=?SlYR2ME z(}n(i^1Z&;Zp)Oy>5;PkVzPQnXDnLQv%br5``e!z`UT_>K@AECpyY$qGF*uVVizzS0qs)V4E9ew);xfkmVj1)LKCZ1kf6hi m9hkR3L8rR~chKpDhTt-ul?@d9Q< None: input_link = "input/links/de/fr.txt" diff --git a/tests/storage/repository/filesystem/test_bucket_node.py b/tests/storage/repository/filesystem/test_bucket_node.py index f87d451ee6..dae9c5df5f 100644 --- a/tests/storage/repository/filesystem/test_bucket_node.py +++ b/tests/storage/repository/filesystem/test_bucket_node.py @@ -10,6 +10,12 @@ from antarest.study.storage.rawstudy.model.filesystem.context import ( ContextServer, ) +from antarest.study.storage.rawstudy.model.filesystem.folder_node import ( + FolderNode, +) +from antarest.study.storage.rawstudy.model.filesystem.ini_file_node import ( + IniFileNode, +) def build_bucket(tmp: Path) -> Path: @@ -19,11 +25,18 @@ def build_bucket(tmp: Path) -> Path: (bucket / "fileB.txt").touch() (bucket / "folder").mkdir() (bucket / "folder/fileC.txt").touch() + (bucket / "registered_file.ini").touch() + (bucket / "registered_folder_node").mkdir() return bucket def test_get_bucket(tmp_path: Path): + registered_files = { + "registered_file.ini": IniFileNode, + # "registered_folder_node": FolderNode, + } + file = build_bucket(tmp_path) resolver = Mock() @@ -40,6 +53,7 @@ def test_get_bucket(tmp_path: Path): study_path=file, path=file, study_id="id", version=-1 ), context=context, + registered_files=registered_files, ) assert node.get(["fileA.txt"]) == b"Content A" @@ -47,6 +61,11 @@ def test_get_bucket(tmp_path: Path): assert "fileA.txt" in bucket["fileA.txt"] assert "fileB.txt" in bucket["fileB.txt"] assert "fileC.txt" in bucket["folder"]["fileC.txt"] + for file_name, node_type in registered_files.items(): + assert ( + type(node._get([file_name.split(".")[0]], get_node=True)) + == node_type + ) def test_save_bucket(tmp_path: Path): From 59e910580d1a96325b000f89fcc532f605dd669c Mon Sep 17 00:00:00 2001 From: 3lbanna <76211863+3lbanna@users.noreply.github.com> Date: Wed, 9 Feb 2022 11:10:49 +0100 Subject: [PATCH 16/23] add export outputs filter (#727) --- antarest/core/filetransfer/service.py | 1 - antarest/study/model.py | 19 +- antarest/study/service.py | 68 +++++- .../study/storage/study_download_utils.py | 15 +- antarest/study/web/studies_blueprint.py | 30 ++- .../business/test_study_service_utils.py | 14 +- tests/storage/test_service.py | 47 +++- .../model/command/test_update_comments.py | 7 +- webapp/public/locales/en/singlestudy.json | 22 +- webapp/public/locales/fr/singlestudy.json | 22 +- webapp/src/common/types.ts | 44 ++++ webapp/src/components/Data/DataModal.tsx | 2 +- .../components/Settings/Groups/GroupModal.tsx | 2 +- .../components/Settings/Groups/RoleModal.tsx | 2 +- .../Tokens/Modals/TokenCreationModal.tsx | 2 +- .../components/Settings/Users/UserModal.tsx | 2 +- .../ExportFilterModal/CustomSelect.tsx | 47 ++++ .../ExportFilterModal/ExportFilter.tsx | 228 ++++++++++++++++++ .../ExportFilterModal/TagSelect.tsx | 86 +++++++ .../SingleStudy/ExportFilterModal/index.tsx | 165 +++++++++++++ .../SingleStudy/InformationView.tsx | 37 ++- .../SingleStudy/PermissionModal.tsx | 2 +- .../components/SingleStudy/RenameModal.tsx | 2 +- .../Variants/CreateVariantModal.tsx | 2 +- .../Variants/Edition/AddCommandModal.tsx | 2 +- webapp/src/components/ui/GenericModal.tsx | 18 +- webapp/src/services/api/study.ts | 19 +- webapp/src/services/api/variant.ts | 7 +- 28 files changed, 846 insertions(+), 68 deletions(-) create mode 100644 webapp/src/components/SingleStudy/ExportFilterModal/CustomSelect.tsx create mode 100644 webapp/src/components/SingleStudy/ExportFilterModal/ExportFilter.tsx create mode 100644 webapp/src/components/SingleStudy/ExportFilterModal/TagSelect.tsx create mode 100644 webapp/src/components/SingleStudy/ExportFilterModal/index.tsx diff --git a/antarest/core/filetransfer/service.py b/antarest/core/filetransfer/service.py index b74c80bebd..c0cec421bf 100644 --- a/antarest/core/filetransfer/service.py +++ b/antarest/core/filetransfer/service.py @@ -25,7 +25,6 @@ UserHasNotPermissionError, ) - logger = logging.getLogger(__name__) diff --git a/antarest/study/model.py b/antarest/study/model.py index de95921ce7..ac1446e24d 100644 --- a/antarest/study/model.py +++ b/antarest/study/model.py @@ -1,11 +1,10 @@ import enum import uuid -from copy import deepcopy +from dataclasses import dataclass from datetime import timedelta, datetime from pathlib import Path -from typing import Any, Dict, List, Optional, TypeVar +from typing import Any, Dict, List, Optional -from dataclasses import dataclass from pydantic import BaseModel from sqlalchemy import Column, String, Integer, DateTime, Table, ForeignKey, Enum, Boolean # type: ignore from sqlalchemy.orm import relationship # type: ignore @@ -235,6 +234,20 @@ def inc_date(self, date: datetime) -> datetime: raise ShouldNotHappenException() +class ExportFormat(str, enum.Enum): + ZIP = "application/zip" + TAR_GZ = "application/tar+gz" + JSON = "application/json" + + @staticmethod + def from_dto(data: str) -> "ExportFormat": + if data == "application/zip": + return ExportFormat.ZIP + if data == "application/tar+gz": + return ExportFormat.TAR_GZ + return ExportFormat.JSON + + class StudyDownloadDTO(BaseModel): """ DTO used to download outputs diff --git a/antarest/study/service.py b/antarest/study/service.py index ff15434bfe..d941f93986 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -12,12 +12,9 @@ from fastapi import HTTPException from markupsafe import escape +from starlette.responses import FileResponse from antarest.core.config import Config -from antarest.core.filetransfer.model import ( - FileDownloadTaskDTO, -) -from antarest.core.filetransfer.service import FileTransferManager from antarest.core.exceptions import ( StudyNotFoundError, StudyTypeUnsupported, @@ -25,6 +22,10 @@ NotAManagedStudyException, CommandApplicationError, ) +from antarest.core.filetransfer.model import ( + FileDownloadTaskDTO, +) +from antarest.core.filetransfer.service import FileTransferManager from antarest.core.interfaces.cache import ICache, CacheConstants from antarest.core.interfaces.eventbus import IEventBus, Event, EventType from antarest.core.jwt import JWTUser, DEFAULT_ADMIN_USER @@ -74,6 +75,7 @@ MatrixIndex, PatchCluster, PatchArea, + ExportFormat, ) from antarest.study.repository import StudyMetadataRepository from antarest.study.storage.rawstudy.model.filesystem.config.model import ( @@ -891,14 +893,20 @@ def download_outputs( study_id: str, output_id: str, data: StudyDownloadDTO, + use_task: bool, + filetype: ExportFormat, params: RequestParameters, - ) -> MatrixAggregationResult: + tmp_export_file: Optional[Path] = None, + ) -> Union[MatrixAggregationResult, FileDownloadTaskDTO, FileResponse]: """ Download outputs Args: study_id: study Id output_id: output id data: Json parameters + use_task: use task or not + filetype: type of returning file, + tmp_export_file: temporary file (if use_task is false), params: request parameters Returns: CSV content file @@ -919,6 +927,56 @@ def download_outputs( output_id, data, ) + + if filetype != ExportFormat.JSON: + if use_task: + logger.info(f"Exporting {output_id} from study {study_id}") + export_name = ( + f"Study filtered output {study.name}/{output_id} export" + ) + export_file_download = self.file_transfer_manager.request_download( + f"{study.name}-{study_id}-{output_id}_filtered.{'tar.gz' if filetype == ExportFormat.TAR_GZ else 'zip'}", + export_name, + params.user, + ) + export_path = Path(export_file_download.path) + export_id = export_file_download.id + + def export_task(notifier: TaskUpdateNotifier) -> TaskResult: + try: + StudyDownloader.export(matrix, filetype, export_path) + self.file_transfer_manager.set_ready(export_id) + return TaskResult( + success=True, + message=f"Study filtered output {study_id}/{output_id} successfully exported", + ) + except Exception as e: + self.file_transfer_manager.fail(export_id, str(e)) + raise e + + task_id = self.task_service.add_task( + export_task, + export_name, + task_type=TaskType.EXPORT, + ref_id=study.id, + custom_event_messages=None, + request_params=params, + ) + + return FileDownloadTaskDTO( + file=export_file_download.to_dto(), task=task_id + ) + else: + if tmp_export_file is not None: + StudyDownloader.export(matrix, filetype, tmp_export_file) + return FileResponse( + tmp_export_file, + headers={ + "Content-Disposition": f'attachment; filename="output-{output_id}.{"tar.gz" if filetype == ExportFormat.TAR_GZ else "zip"}' + }, + media_type=filetype, + ) + return matrix def get_study_sim_result( diff --git a/antarest/study/storage/study_download_utils.py b/antarest/study/storage/study_download_utils.py index 1438d6252b..9883e911f4 100644 --- a/antarest/study/storage/study_download_utils.py +++ b/antarest/study/storage/study_download_utils.py @@ -1,16 +1,12 @@ -import calendar import csv import logging import os import re import tarfile -import time from datetime import datetime, timedelta from io import BytesIO, StringIO -from math import ceil from pathlib import Path -from time import strptime -from typing import Any, Callable, Dict, List, Optional, Tuple, cast, Union +from typing import Any, Callable, Dict, List, Optional, Tuple, Union from zipfile import ZipFile, ZIP_DEFLATED from antarest.study.model import ( @@ -18,7 +14,7 @@ StudyDownloadDTO, StudyDownloadLevelDTO, StudyDownloadType, - MatrixIndex, + ExportFormat, ) from antarest.study.storage.rawstudy.model.filesystem.config.model import ( FileStudyTreeConfig, @@ -363,13 +359,14 @@ def export_infos( @staticmethod def export( - matrix: MatrixAggregationResult, type: str, target_file: Path + matrix: MatrixAggregationResult, + filetype: ExportFormat, + target_file: Path, ) -> None: - # 1- Zip/tar+gz container with ( ZipFile(target_file, "w", ZIP_DEFLATED) # type: ignore - if type == "application/zip" + if filetype == ExportFormat.ZIP else tarfile.open(target_file, mode="w:gz") ) as output_data: diff --git a/antarest/study/web/studies_blueprint.py b/antarest/study/web/studies_blueprint.py index 0088945147..555f968642 100644 --- a/antarest/study/web/studies_blueprint.py +++ b/antarest/study/web/studies_blueprint.py @@ -6,18 +6,17 @@ from fastapi import APIRouter, File, Depends, Request, HTTPException from markupsafe import escape -from starlette.responses import FileResponse from antarest.core.config import Config from antarest.core.filetransfer.model import ( FileDownloadTaskDTO, ) +from antarest.core.filetransfer.service import FileTransferManager from antarest.core.jwt import JWTUser from antarest.core.model import PublicMode from antarest.core.requests import ( RequestParameters, ) -from antarest.core.filetransfer.service import FileTransferManager from antarest.core.utils.utils import sanitize_uuid from antarest.core.utils.web import APITag from antarest.login.auth import Auth @@ -25,16 +24,15 @@ StudyMetadataPatchDTO, StudySimResultDTO, StudyMetadataDTO, - MatrixAggregationResult, CommentsDto, StudyDownloadDTO, MatrixIndex, + ExportFormat, ) from antarest.study.service import StudyService from antarest.study.storage.rawstudy.model.filesystem.config.model import ( FileStudyTreeConfigDTO, ) -from antarest.study.storage.study_download_utils import StudyDownloader logger = logging.getLogger(__name__) @@ -460,8 +458,9 @@ def output_export( def output_download( study_id: str, output_id: str, - request: Request, data: StudyDownloadDTO, + request: Request, + use_task: bool = False, tmp_export_file: Path = Depends(ftm.request_tmp_file), current_user: JWTUser = Depends(auth.get_current_user), ) -> Any: @@ -472,19 +471,18 @@ def output_download( extra={"user": current_user.id}, ) params = RequestParameters(user=current_user) + accept = request.headers.get("Accept") + filetype = ExportFormat.from_dto(accept) + content = study_service.download_outputs( - study_id, output_id, data, params + study_id, + output_id, + data, + use_task, + filetype, + params, + tmp_export_file, ) - accept = request.headers.get("Accept") - if accept == "application/zip" or accept == "application/tar+gz": - StudyDownloader.export(content, accept, tmp_export_file) - return FileResponse( - tmp_export_file, - headers={ - "Content-Disposition": f'attachment; filename="output-{output_id}.zip' - }, - media_type=accept, - ) return content @bp.get( diff --git a/tests/storage/business/test_study_service_utils.py b/tests/storage/business/test_study_service_utils.py index 2471bb0691..a4f74c2fd5 100644 --- a/tests/storage/business/test_study_service_utils.py +++ b/tests/storage/business/test_study_service_utils.py @@ -1,4 +1,5 @@ import datetime +import tarfile from hashlib import md5 from pathlib import Path from typing import Any, Dict @@ -7,11 +8,11 @@ import pytest -from antarest.core.model import JSON from antarest.study.model import ( MatrixAggregationResult, MatrixIndex, StudyDownloadLevelDTO, + ExportFormat, ) from antarest.study.storage.study_download_utils import StudyDownloader from antarest.study.storage.utils import get_start_date @@ -45,7 +46,7 @@ def test_output_downloads_export(tmp_path: Path): warnings=[], ) zip_file = tmp_path / "output.zip" - StudyDownloader.export(matrix, "application/zip", zip_file) + StudyDownloader.export(matrix, ExportFormat.ZIP, zip_file) with ZipFile(zip_file) as zip_input: assert zip_input.namelist() == ["a1.csv", "a2.csv"] assert ( @@ -57,6 +58,15 @@ def test_output_downloads_export(tmp_path: Path): == "c007db83f2769e6128e0f8c6b04d43eb" ) + tar_file = tmp_path / "output.tar.gz" + StudyDownloader.export(matrix, ExportFormat.TAR_GZ, tar_file) + with tarfile.open(tar_file, mode="r:gz") as tar_input: + assert tar_input.getnames() == ["a1.csv", "a2.csv"] + data = tar_input.extractfile("a1.csv").read() + assert md5(data).hexdigest() == "e183e79f2184d6f6dacb8ad215cb056c" + data = tar_input.extractfile("a2.csv").read() + assert md5(data).hexdigest() == "c007db83f2769e6128e0f8c6b04d43eb" + @pytest.mark.parametrize( "config,level,expected", diff --git a/tests/storage/test_service.py b/tests/storage/test_service.py index 1dc25e743a..faa0c92b0a 100644 --- a/tests/storage/test_service.py +++ b/tests/storage/test_service.py @@ -7,6 +7,7 @@ import pytest from antarest.core.config import Config, StorageConfig, WorkspaceConfig +from antarest.core.filetransfer.model import FileDownloadTaskDTO, FileDownload from antarest.core.interfaces.cache import ICache from antarest.core.jwt import JWTUser, JWTGroup, DEFAULT_ADMIN_USER from antarest.core.model import JSON, SUB_JSON @@ -34,6 +35,7 @@ StudyMetadataDTO, OwnerInfo, StudyDownloadLevelDTO, + ExportFormat, ) from antarest.study.repository import StudyMetadataRepository from antarest.study.service import StudyService, UserHasNotPermissionError @@ -503,6 +505,9 @@ def test_download_output() -> None: output_config, res_study, res_study, + output_config, + res_study, + res_study, ] # AREA TYPE @@ -520,10 +525,42 @@ def test_download_output() -> None: "study-id", "output-id", input_data, - RequestParameters(JWTUser(id=0, impersonator=0, type="users")), + use_task=False, + filetype=ExportFormat.JSON, + params=RequestParameters(JWTUser(id=0, impersonator=0, type="users")), ) assert result == res_matrix + # AREA TYPE - ZIP & TASK + export_file_download = FileDownload( + id="download-id", + filename="filename", + name="name", + ready=False, + path="path", + owner=None, + expiration_date=datetime.utcnow(), + ) + service.file_transfer_manager.request_download.return_value = ( + export_file_download + ) + task_id = "task-id" + service.task_service.add_task.return_value = task_id + + result = service.download_outputs( + "study-id", + "output-id", + input_data, + use_task=True, + filetype=ExportFormat.ZIP, + params=RequestParameters(JWTUser(id=0, impersonator=0, type="users")), + ) + + res_file_download = FileDownloadTaskDTO( + file=export_file_download.to_dto(), task=task_id + ) + assert result == res_file_download + # LINK TYPE input_data.type = StudyDownloadType.LINK input_data.filter = ["east>west"] @@ -541,7 +578,9 @@ def test_download_output() -> None: "study-id", "output-id", input_data, - RequestParameters(JWTUser(id=0, impersonator=0, type="users")), + use_task=False, + filetype=ExportFormat.JSON, + params=RequestParameters(JWTUser(id=0, impersonator=0, type="users")), ) assert result == res_matrix @@ -563,7 +602,9 @@ def test_download_output() -> None: "study-id", "output-id", input_data, - RequestParameters(JWTUser(id=0, impersonator=0, type="users")), + use_task=False, + filetype=ExportFormat.JSON, + params=RequestParameters(JWTUser(id=0, impersonator=0, type="users")), ) assert result == res_matrix diff --git a/tests/variantstudy/model/command/test_update_comments.py b/tests/variantstudy/model/command/test_update_comments.py index 27266c4fc6..4123d4cfee 100644 --- a/tests/variantstudy/model/command/test_update_comments.py +++ b/tests/variantstudy/model/command/test_update_comments.py @@ -63,7 +63,12 @@ def test_revert(command_context: CommandContext, empty_study: FileStudy): ) == [UpdateComments(comments="comments", command_context=command_context)] assert base_command.revert([], base=empty_study) == [ UpdateComments( - comments='\n\n \n \n \n \n \n\n', + comments='\n\n \n \n ' + "\n \n \n\n", command_context=command_context, ) ] diff --git a/webapp/public/locales/en/singlestudy.json b/webapp/public/locales/en/singlestudy.json index 7a85c78fbd..0167aa0bfc 100644 --- a/webapp/public/locales/en/singlestudy.json +++ b/webapp/public/locales/en/singlestudy.json @@ -9,6 +9,19 @@ "timeLimit": "Time limit", "timeLimitHelper": "Time limit (in hours)", "nbCpu": "Number of core", + "synthesis": "Synthesis", + "level": "Level", + "years": "Years", + "type": "Type", + "includeClusters": "Include clusters", + "area": "Areas", + "link": "Links", + "district": "Districts", + "hourly": "Hourly", + "daily": "Daily", + "weekly": "Weekly", + "monthly": "Monthly", + "annual": "Annual", "currentTask": "Current tasks", "failtoloadjobs": "Failed to load jobs", "taskId": "Id", @@ -54,5 +67,12 @@ "onStudyIdCopySucces": "Study id copied !", "onStudyIdCopyError": "Failed to copy study id", "copyId": "Copy the study id", - "copyIdDir": "Copy id" + "copyIdDir": "Copy id", + "exportAll": "Export all outputs", + "outputExportSuccess": "Outputs exported successfully", + "outputExportInProgress": "Downloading study outputs...", + "columns": "Columns", + "filter": "Filter", + "filterIn": "Filter In", + "filterOut": "Filter Out" } diff --git a/webapp/public/locales/fr/singlestudy.json b/webapp/public/locales/fr/singlestudy.json index 2e31f34b51..13355e2e60 100644 --- a/webapp/public/locales/fr/singlestudy.json +++ b/webapp/public/locales/fr/singlestudy.json @@ -9,6 +9,19 @@ "timeLimit": "Limite de temps", "timeLimitHelper": "Limite de temps (en heures)", "nbCpu": "Nombre de coeurs", + "synthesis": "Synthèse", + "level": "Niveau", + "years": "Années", + "type": "Type", + "includeClusters": "Inclure les clusters", + "area": "Zones", + "link": "Liens", + "district": "Districts", + "hourly": "Horaire", + "daily": "Journalier", + "weekly": "Hebdomadaire", + "monthly": "Mensuel", + "annual": "Annuel", "currentTask": "Tâches", "failtoloadjobs": "Echec du chargement des jobs", "taskId": "Id", @@ -54,5 +67,12 @@ "onStudyIdCopySuccess": "Identifiant de l'étude copié", "onStudyIdCopyError": "Erreur lors de la copie de l'identifiant de l'étude", "copyId": "Copie l'identifiant de l'étude", - "copyIdDir": "Copier l'ID" + "copyIdDir": "Copier l'ID", + "exportAll": "Exporter toutes les sorties", + "outputExportSuccess": "Sorties exportées avec succès", + "outputExportInProgress": "Téléchargement des sorties en cours...", + "columns": "Colonnes", + "filter": "Filtre", + "filterIn": "Filtre d'inclusion (Regex)", + "filterOut": "Filtre d'exclusion (Regex)" } \ No newline at end of file diff --git a/webapp/src/common/types.ts b/webapp/src/common/types.ts index 164d800c33..30014d6c36 100644 --- a/webapp/src/common/types.ts +++ b/webapp/src/common/types.ts @@ -374,4 +374,48 @@ export interface FileStudyTreeConfigDTO { enr_modelling: string; } +export enum StudyOutputDownloadType { + LINK = 'LINK', + DISTRICT = 'DISTRICT', + AREA = 'AREA', +} + +export enum StudyOutputDownloadLevelDTO { + ANNUAL = 'annual', + MONTHLY = 'monthly', + WEEKLY = 'weekly', + DAILY = 'daily', + HOURLY = 'hourly', +} + +export interface StudyOutputDownloadDTO { + type: StudyOutputDownloadType; + years?: Array; + level: StudyOutputDownloadLevelDTO; + filterIn?: string; + filterOut?: string; + filter?: Array; + columns?: Array; + synthesis: boolean; + includeClusters: boolean; +} + +export interface MatrixIndex { + start_date: string; + steps: number; + first_week_size: number; + level: StudyOutputDownloadLevelDTO; +} + +export interface MatrixAggregationResult { + index: MatrixIndex; + data: { + [id: string]: { + [elm: string]: { + [item: string]: Array; + }; + }; + }; + warnings: Array; +} export default {}; diff --git a/webapp/src/components/Data/DataModal.tsx b/webapp/src/components/Data/DataModal.tsx index dad1bb2b5d..a92f0e70e0 100644 --- a/webapp/src/components/Data/DataModal.tsx +++ b/webapp/src/components/Data/DataModal.tsx @@ -198,7 +198,7 @@ const DataModal = (props: PropTypes) => {
diff --git a/webapp/src/components/Settings/Groups/GroupModal.tsx b/webapp/src/components/Settings/Groups/GroupModal.tsx index 5246463a19..2f7cd54c19 100644 --- a/webapp/src/components/Settings/Groups/GroupModal.tsx +++ b/webapp/src/components/Settings/Groups/GroupModal.tsx @@ -142,7 +142,7 @@ const GroupModal = (props: PropTypes) => { onSave(text, addedUser)} + handleAction={() => onSave(text, addedUser)} title={group ? `${t('settings:group')} - ${group.group.name}` : t('settings:newGroupTitle')} > {(isAdmin || group === undefined) && ( diff --git a/webapp/src/components/Settings/Groups/RoleModal.tsx b/webapp/src/components/Settings/Groups/RoleModal.tsx index 4e902f77a5..dac3a131aa 100644 --- a/webapp/src/components/Settings/Groups/RoleModal.tsx +++ b/webapp/src/components/Settings/Groups/RoleModal.tsx @@ -64,7 +64,7 @@ const RoleModal = (props: PropTypes) => { onSave(group?.id as string, user.id, selection)} + handleAction={() => onSave(group?.id as string, user.id, selection)} title={`${user?.name} in "${group?.name}"`} >
diff --git a/webapp/src/components/Settings/Tokens/Modals/TokenCreationModal.tsx b/webapp/src/components/Settings/Tokens/Modals/TokenCreationModal.tsx index 3089e049b5..5537941b7a 100644 --- a/webapp/src/components/Settings/Tokens/Modals/TokenCreationModal.tsx +++ b/webapp/src/components/Settings/Tokens/Modals/TokenCreationModal.tsx @@ -126,7 +126,7 @@ const TokenCreationModal = (props: PropTypes) => {
diff --git a/webapp/src/components/Settings/Users/UserModal.tsx b/webapp/src/components/Settings/Users/UserModal.tsx index 00c892da03..44b21cbb67 100644 --- a/webapp/src/components/Settings/Users/UserModal.tsx +++ b/webapp/src/components/Settings/Users/UserModal.tsx @@ -127,7 +127,7 @@ const UserModal = (props: PropTypes) => { { diff --git a/webapp/src/components/SingleStudy/ExportFilterModal/CustomSelect.tsx b/webapp/src/components/SingleStudy/ExportFilterModal/CustomSelect.tsx new file mode 100644 index 0000000000..0a99a69a07 --- /dev/null +++ b/webapp/src/components/SingleStudy/ExportFilterModal/CustomSelect.tsx @@ -0,0 +1,47 @@ +/* eslint-disable @typescript-eslint/camelcase */ +import React from 'react'; +import { Select, MenuItem, InputLabel, FormControl, Input } from '@material-ui/core'; +import { CSSProperties } from '@material-ui/core/styles/withStyles'; + +interface PropTypes { + style?: CSSProperties; + fullWidth?: boolean; + list: Array<{key: string; value: string}>; + value: Array | string; + label: string; + multiple?: boolean; + onChange: (value: Array | string) => void; +} + +const CustomSelect = (props: PropTypes) => { + const { list, label, style, fullWidth, value, multiple, onChange } = props; + + return ( + + {label} + } + > + {list.map((elm) => ( + + {elm.value} + + ))} + + + + ); +}; + +CustomSelect.defaultProps = { + style: undefined, + fullWidth: false, + multiple: undefined, +}; + +export default CustomSelect; diff --git a/webapp/src/components/SingleStudy/ExportFilterModal/ExportFilter.tsx b/webapp/src/components/SingleStudy/ExportFilterModal/ExportFilter.tsx new file mode 100644 index 0000000000..1f0f1a872f --- /dev/null +++ b/webapp/src/components/SingleStudy/ExportFilterModal/ExportFilter.tsx @@ -0,0 +1,228 @@ +/* eslint-disable @typescript-eslint/camelcase */ +import React, { useEffect, useState } from 'react'; +import { Chip, createStyles, makeStyles, TextField, Theme, Typography } from '@material-ui/core'; +import { useTranslation } from 'react-i18next'; +import clsx from 'clsx'; +import AddCircleOutlinedIcon from '@material-ui/icons/AddCircleOutlined'; +import { Area, Set, StudyOutputDownloadType } from '../../../common/types'; +import CustomSelect from './CustomSelect'; + +const useStyles = makeStyles((theme: Theme) => createStyles({ + root: { + width: '100%', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'flex-start', + alignItems: 'flex-start', + padding: 0, + }, + linkContainer: { + width: '100%', + display: 'flex', + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + boxSizing: 'border-box', + }, + singleLink: { + alignItems: 'flex-end', + marginBottom: theme.spacing(2), + }, + linkFilter: { + display: 'flex', + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + alignItems: 'center', + boxSizing: 'border-box', + padding: 0, + width: '250px', + overflow: 'hidden', + }, + linkLabel: { + height: '100%', + marginRight: '5px', + }, + filterLinkContainer: { + display: 'flex', + border: 0, + backgroundColor: '#00000000', + justifyContent: 'center', + flexWrap: 'wrap', + listStyle: 'none', + padding: theme.spacing(0.5), + marginTop: theme.spacing(1), + margin: 0, + }, + chip: { + margin: theme.spacing(0.5), + }, + addIcon: { + color: theme.palette.primary.main, + margin: theme.spacing(0, 1), + cursor: 'pointer', + '&:hover': { + color: theme.palette.secondary.main, + }, + }, +})); + +interface FilterLink { + area1: string; + area2: string; +} + +interface PropTypes { + type: StudyOutputDownloadType; + areas: {[elm: string]: Area}; + sets: {[elm: string]: Set}; + filterValue: Array; + setFilterValue: (elm: Array) => void; + filterInValue: string; + setFilterInValue: (elm: string) => void; + filterOutValue: string; + setFilterOutValue: (elm: string) => void; +} + +const SingleLinkElement = (props: {globalFilter?: boolean; label: string; areas: Array; onChange: (value: string) => void}) => { + const classes = useStyles(); + const [t] = useTranslation(); + const { globalFilter, label, areas, onChange } = props; + const [link, setLink] = useState({ area1: '', area2: '' }); + + const onSelectChange = (id: number, elm: string): void => { + let { area1, area2 } = link; + if (id === 0) { + area1 = elm; + setLink({ ...link, area1: elm }); + } else { + area2 = elm; + setLink({ ...link, area2: elm }); + } + onChange(`${area1}^${area2}`); + }; + return ( +
+ + {label} + : + + { + globalFilter === true ? ( +
+ ({ key: elm, value: elm }))} + value={link.area1} + onChange={(elm: Array | string) => onSelectChange(0, elm as string)} + style={{ marginLeft: '5px', marginRight: '5px', width: '50%' }} + /> + ({ key: elm, value: elm }))} + value={link.area2} + onChange={(elm: Array | string) => onSelectChange(1, elm as string)} + /> +
+ ) : ( +
+ onSelectChange(0, event.target.value)} style={{ marginLeft: '5px', marginRight: '5px', width: '100%' }} /> + onSelectChange(1, event.target.value)} style={{ width: '100%' }} /> +
+ )} +
+ ); +}; + +SingleLinkElement.defaultProps = { + globalFilter: false, +}; + +const MultipleLinkElement = (props: {label: string; areas: Array; values: Array; onChange: (value: Array) => void}) => { + const classes = useStyles(); + const { label, areas, values, onChange } = props; + const [currentLink, setCurrentLink] = useState(''); + + const onAddLink = (): void => { + if (values.findIndex((elm) => elm === currentLink) < 0 && currentLink !== '') { + onChange(values.concat(currentLink)); + } + }; + + return ( +
+
+ + +
+ {values.length > 0 && ( +
    + {values.map((elm) => ( +
  • + onChange(values.filter((link) => link !== elm))} + className={classes.chip} + /> +
  • + ))} +
+ )} +
+ ); +}; + +const ExportFilter = (props: PropTypes) => { + const classes = useStyles(); + const [t] = useTranslation(); + const { type, areas, sets, filterValue, filterInValue, filterOutValue, setFilterValue, setFilterInValue, setFilterOutValue } = props; + const [areasOrDistrictsList, setAreasOrDistrictsList] = useState>([]); + + useEffect(() => { + const getAreasOrDistrictsList = (): Array => { + let res: Array = []; + switch (type) { + case StudyOutputDownloadType.AREA: + res = Object.keys(areas); + break; + + case StudyOutputDownloadType.DISTRICT: + res = Object.keys(sets); + break; + + default: + break; + } + return res; + }; + setAreasOrDistrictsList(getAreasOrDistrictsList()); + }, [areas, sets, type]); + + return ( + <> + {type !== StudyOutputDownloadType.LINK ? ( +
+ ({ key: elm, value: elm }))} + value={filterValue} + onChange={(elm: Array | string) => setFilterValue(elm as Array)} + style={{ marginBottom: '16px' }} + /> + setFilterInValue(event.target.value)} style={{ marginBottom: '16px', width: '100%' }} /> + setFilterOutValue(event.target.value)} style={{ marginBottom: '16px', width: '100%' }} /> +
+ ) : ( +
+ + + +
+ )} + + + ); +}; + +export default ExportFilter; diff --git a/webapp/src/components/SingleStudy/ExportFilterModal/TagSelect.tsx b/webapp/src/components/SingleStudy/ExportFilterModal/TagSelect.tsx new file mode 100644 index 0000000000..b8729f13fd --- /dev/null +++ b/webapp/src/components/SingleStudy/ExportFilterModal/TagSelect.tsx @@ -0,0 +1,86 @@ +/* eslint-disable @typescript-eslint/camelcase */ +import React, { useState } from 'react'; +import { Chip, createStyles, makeStyles, TextField, Theme } from '@material-ui/core'; +import AddCircleOutlinedIcon from '@material-ui/icons/AddCircleOutlined'; + +const useStyles = makeStyles((theme: Theme) => createStyles({ + root: { + width: '100%', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'flex-start', + alignItems: 'flex-start', + padding: 0, + }, + inputContainer: { + width: '100%', + display: 'flex', + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + alignItems: 'flex-end', + padding: 0, + marginBottom: theme.spacing(1), + }, + tagContainer: { + display: 'flex', + border: 0, + backgroundColor: '#00000000', + justifyContent: 'center', + flexWrap: 'wrap', + listStyle: 'none', + padding: theme.spacing(0.5), + margin: 0, + }, + chip: { + margin: theme.spacing(0.5), + }, + addIcon: { + color: theme.palette.primary.main, + margin: theme.spacing(0, 1), + cursor: 'pointer', + '&:hover': { + color: theme.palette.secondary.main, + }, + }, +})); + +interface PropTypes { + label: string; + values: Array; + onChange: (value: Array) => void; +} + +const TagSelect = (props: PropTypes) => { + const classes = useStyles(); + const { label, values, onChange } = props; + const [value, setValue] = useState(''); + + const onAddTag = (): void => { + if (values.findIndex((elm) => elm === value) < 0 && value !== '') { + onChange(values.concat(value)); + setValue(''); + } + }; + + return ( +
+
+ setValue(event.target.value)} style={{ marginLeft: '5px', marginRight: '5px', flex: 1 }} /> + +
+
    + {values.map((elm) => ( +
  • + onChange(values.filter((item) => item !== elm))} + className={classes.chip} + /> +
  • + ))} +
+
+ ); +}; + +export default TagSelect; diff --git a/webapp/src/components/SingleStudy/ExportFilterModal/index.tsx b/webapp/src/components/SingleStudy/ExportFilterModal/index.tsx new file mode 100644 index 0000000000..eb94304a13 --- /dev/null +++ b/webapp/src/components/SingleStudy/ExportFilterModal/index.tsx @@ -0,0 +1,165 @@ +/* eslint-disable camelcase */ +/* eslint-disable @typescript-eslint/camelcase */ +import React, { useEffect, useState } from 'react'; +import { createStyles, makeStyles, Theme, FormControlLabel, Checkbox, Divider } from '@material-ui/core'; +import { useTranslation } from 'react-i18next'; +import _ from 'lodash'; +import GenericModal from '../../ui/GenericModal'; +import { Area, Set as District, FileStudyTreeConfigDTO, StudyOutputDownloadDTO, StudyOutputDownloadLevelDTO, StudyOutputDownloadType } from '../../../common/types'; +import ExportFilter from './ExportFilter'; +import CustomSelect from './CustomSelect'; +import TagSelect from './TagSelect'; + +const useStyles = makeStyles((theme: Theme) => createStyles({ + infos: { + flex: '1', + width: '350px', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'flex-start', + alignItems: 'flex-start', + padding: theme.spacing(2), + overflowX: 'hidden', + overflowY: 'auto', + }, + divider: { + width: '100%', + height: '1px', + backgroundColor: theme.palette.grey[400], + margin: theme.spacing(5, 0), + }, +})); + +interface PropTypes { + open: boolean; + onClose: () => void; + output: string; + synthesis: FileStudyTreeConfigDTO | undefined; + onExportFiltered: (output: string, filter: StudyOutputDownloadDTO) => void; + onExport: (output: string) => void; +} + +const ExportFilterModal = (props: PropTypes) => { + const classes = useStyles(); + const [t] = useTranslation(); + const { open, onClose, output, synthesis, onExportFiltered, onExport } = props; + const [exportChecked, setExportChecked] = useState(false); + const [year, setCurrentYear] = useState>([]); + const [byYear, setByYear] = useState<{isByYear: boolean; nbYear: number}>({ isByYear: false, nbYear: -1 }); + const [areaList, setAreaList] = useState<{[elm: string]: Area}>({}); + const [districtList, setDistrictList] = useState<{[elm: string]: District}>({}); + const [filter, setFilter] = useState({ + type: StudyOutputDownloadType.AREA, + level: StudyOutputDownloadLevelDTO.WEEKLY, + synthesis: false, + includeClusters: false, + }); + + const typeList: Array = [StudyOutputDownloadType.AREA, StudyOutputDownloadType.LINK, StudyOutputDownloadType.DISTRICT]; + const levelList: Array = [StudyOutputDownloadLevelDTO.HOURLY, + StudyOutputDownloadLevelDTO.DAILY, + StudyOutputDownloadLevelDTO.WEEKLY, + StudyOutputDownloadLevelDTO.MONTHLY, + StudyOutputDownloadLevelDTO.ANNUAL]; + + const onSave = async () => { + if (exportChecked) { + onExport(output); + } else { + onExportFiltered(output, filter); + } + onClose(); + }; + + const onTypeChange = (value: Array | string): void => { + setFilter({ ...filter, type: value as StudyOutputDownloadType }); + }; + + const onLevelChange = (value: Array | string): void => { + setFilter({ ...filter, level: value as StudyOutputDownloadLevelDTO }); + }; + + useEffect(() => { + if (synthesis && output in synthesis?.outputs) { + const outputs = synthesis.outputs[output]; + setByYear({ isByYear: outputs?.by_year, nbYear: outputs?.nbyears }); + setAreaList(synthesis.areas); + setDistrictList(synthesis.sets); + } + }, [synthesis, output]); + + return ( + +
+ setExportChecked(checked)} name={t('singlestudy:exportAll')} />} + label={t('singlestudy:exportAll')} + /> + {!exportChecked && ( + <> + + ({ key: elm, value: t(`singlestudy:${elm.toLowerCase()}`) }))} + value={filter.type} + onChange={onTypeChange} + /> + {byYear.isByYear && byYear.nbYear > 0 && ( + ({ key: elm.toString(), value: elm.toString() }))} + value={year.map((elm) => elm.toString())} + onChange={(value: Array | string) => setCurrentYear((value as Array).map((elm) => parseInt(elm, 10)))} + /> + )} + ({ key: elm, value: t(`singlestudy:${elm.toLowerCase()}`) }))} + value={filter.level} + onChange={onLevelChange} + /> + ) => setFilter({ ...filter, columns: value })} + /> + ) => setFilter({ ...filter, filter: elm })} + filterInValue={filter.filterIn ? filter.filterIn : ''} + setFilterInValue={(elm: string) => setFilter({ ...filter, filterIn: elm })} + filterOutValue={filter.filterOut ? filter.filterOut : ''} + setFilterOutValue={(elm: string) => setFilter({ ...filter, filterOut: elm })} + /> + setFilter({ ...filter, synthesis: checked })} name={t('singlestudy:synthesis')} />} + label={t('singlestudy:synthesis')} + /> + setFilter({ ...filter, includeClusters: checked })} name={t('singlestudy:includeClusters')} />} + label={t('singlestudy:includeClusters')} + /> + + )} +
+
+ ); +}; + +export default ExportFilterModal; diff --git a/webapp/src/components/SingleStudy/InformationView.tsx b/webapp/src/components/SingleStudy/InformationView.tsx index 78ad414baf..1f9b85b7a9 100644 --- a/webapp/src/components/SingleStudy/InformationView.tsx +++ b/webapp/src/components/SingleStudy/InformationView.tsx @@ -23,7 +23,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import _ from 'lodash'; import { AppState } from '../../App/reducers'; import { + FileStudyTreeConfigDTO, RoleType, + StudyOutputDownloadDTO, StudyMetadata, StudyOutput, } from '../../common/types'; @@ -35,6 +37,8 @@ import { exportStudy, exportOuput as callExportOutput, getStudyOutputs, + getStudySynthesis, + downloadOutput, } from '../../services/api/study'; import { removeStudies } from '../../ducks/study'; import { hasAuthorization, getStudyExtendedName, convertUTCToLocalTime } from '../../services/utils'; @@ -45,6 +49,7 @@ import RenameModal from './RenameModal'; import { CopyIcon } from '../Data/utils'; import enqueueErrorSnackbar from '../ui/ErrorSnackBar'; import LauncherModal from '../ui/LauncherModal'; +import ExportFilterModal from './ExportFilterModal'; const logError = debug('antares:singlestudyview:error'); @@ -244,9 +249,12 @@ const InformationView = (props: PropTypes) => { const [openConfirmationModal, setOpenConfirmationModal] = useState(false); const [openPermissionModal, setOpenPermissionModal] = useState(false); const [openRenameModal, setOpenRenameModal] = useState(false); + const [openFilterModal, setOpenFilterModal] = useState(false); + const [currentOutput, setCurrentOutput] = useState(''); const [outputList, setOutputList] = useState>(); const [outputExportButtonAnchor, setOutputExportButtonAnchor] = React.useState(null); const [anchorEl, setAnchorEl] = React.useState(null); + const [synthesis, setStudySynthesis] = useState(); const openStudyLauncher = (): void => { if (study) { @@ -297,7 +305,6 @@ const InformationView = (props: PropTypes) => { }; const exportOutput = _.debounce(async (output: string) => { - setOutputExportButtonAnchor(null); if (study) { try { await callExportOutput(study.id, output); @@ -307,6 +314,23 @@ const InformationView = (props: PropTypes) => { } }, 2000, { leading: true, trailing: false }); + const onExportFiltered = async (output: string, filter: StudyOutputDownloadDTO): Promise => { + setOpenFilterModal(false); + if (study) { + try { + await downloadOutput(study.id, output, filter); + enqueueSnackbar(t('singlestudy:outputExportInProgress'), { variant: 'info' }); + } catch (e) { + enqueueErrorSnackbar(enqueueSnackbar, t('singlestudy:failedToExportOutput'), e as AxiosError); + } + } + }; + + const onExport = (output: string): void => { + setOpenFilterModal(false); + exportOutput(output); + }; + const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; @@ -315,11 +339,19 @@ const InformationView = (props: PropTypes) => { setAnchorEl(null); }; + const handleExportFilter = (output: string): void => { + setOutputExportButtonAnchor(null); + setCurrentOutput(output); + setOpenFilterModal(true); + }; + useEffect(() => { (async () => { try { const res = await getStudyOutputs(study.id); + const tmpSynth = await getStudySynthesis(study.id); setOutputList(res.map((o: StudyOutput) => o.name)); + setStudySynthesis(tmpSynth); } catch (e) { logError(t('singlestudy:failedToListOutputs'), study, e); } @@ -482,11 +514,12 @@ const InformationView = (props: PropTypes) => { onClose={() => setOutputExportButtonAnchor(null)} > {outputList.map((output) => ( - exportOutput(output)}> + handleExportFilter(output)}> {output} ))} + {openFilterModal && setOpenFilterModal(false)} />} )} {study.managed && ( diff --git a/webapp/src/components/SingleStudy/PermissionModal.tsx b/webapp/src/components/SingleStudy/PermissionModal.tsx index 00e6218b24..7c60037a3c 100644 --- a/webapp/src/components/SingleStudy/PermissionModal.tsx +++ b/webapp/src/components/SingleStudy/PermissionModal.tsx @@ -146,7 +146,7 @@ const PermissionModal = (props: PropTypes) => {
diff --git a/webapp/src/components/SingleStudy/RenameModal.tsx b/webapp/src/components/SingleStudy/RenameModal.tsx index da9bf7ed49..db09990ce7 100644 --- a/webapp/src/components/SingleStudy/RenameModal.tsx +++ b/webapp/src/components/SingleStudy/RenameModal.tsx @@ -41,7 +41,7 @@ const RenameModal = (props: PropTypes) => {
diff --git a/webapp/src/components/Variants/CreateVariantModal.tsx b/webapp/src/components/Variants/CreateVariantModal.tsx index 107eb8127f..a96a4e4b41 100644 --- a/webapp/src/components/Variants/CreateVariantModal.tsx +++ b/webapp/src/components/Variants/CreateVariantModal.tsx @@ -60,7 +60,7 @@ const CreateVariantModal = (props: PropTypes) => {
diff --git a/webapp/src/components/Variants/Edition/AddCommandModal.tsx b/webapp/src/components/Variants/Edition/AddCommandModal.tsx index 4c3eb666c2..23e7e7cf97 100644 --- a/webapp/src/components/Variants/Edition/AddCommandModal.tsx +++ b/webapp/src/components/Variants/Edition/AddCommandModal.tsx @@ -50,7 +50,7 @@ const AddCommandModal = (props: PropTypes) => {
diff --git a/webapp/src/components/ui/GenericModal.tsx b/webapp/src/components/ui/GenericModal.tsx index e7ebcb9769..c923b045cc 100644 --- a/webapp/src/components/ui/GenericModal.tsx +++ b/webapp/src/components/ui/GenericModal.tsx @@ -64,18 +64,19 @@ const useStyles = makeStyles((theme: Theme) => createStyles({ interface PropTypes { open: boolean; title: string; + actionName?: string; handleClose?: () => void; - handleSave?: () => void; + handleAction?: () => void; } const GenericModal = (props: PropsWithChildren) => { - const { title, open, handleClose, handleSave, children } = props; + const { title, open, handleClose, actionName, handleAction, children } = props; const classes = useStyles(); const [t] = useTranslation(); const handleGlobalKeyDown = (keyboardEvent: React.KeyboardEvent) => { - if (keyboardEvent.key === 'Enter' && handleSave) { - handleSave(); + if (keyboardEvent.key === 'Enter' && handleAction) { + handleAction(); } else if (keyboardEvent.key === 'Escape' && handleClose) { handleClose(); } @@ -113,14 +114,14 @@ const GenericModal = (props: PropsWithChildren) => { {t('settings:cancelButton')} )} - {handleSave && ( + {handleAction && ( )}
@@ -132,7 +133,8 @@ const GenericModal = (props: PropsWithChildren) => { GenericModal.defaultProps = { handleClose: undefined, - handleSave: undefined, + handleAction: undefined, + actionName: undefined, }; export default GenericModal; diff --git a/webapp/src/services/api/study.ts b/webapp/src/services/api/study.ts index e3d9ba6675..159d14f7e6 100644 --- a/webapp/src/services/api/study.ts +++ b/webapp/src/services/api/study.ts @@ -1,6 +1,6 @@ import { AxiosRequestConfig } from 'axios'; import client from './client'; -import { LaunchJob, StudyMetadata, StudyMetadataDTO, StudyOutput, StudyPublicMode } from '../../common/types'; +import { FileStudyTreeConfigDTO, LaunchJob, MatrixAggregationResult, StudyOutputDownloadDTO, StudyMetadata, StudyMetadataDTO, StudyOutput, StudyPublicMode } from '../../common/types'; import { getConfig } from '../config'; import { convertStudyDtoToMetadata } from '../utils'; import { FileDownloadTask } from './downloads'; @@ -43,6 +43,23 @@ export const getStudyOutputs = async (sid: string): Promise> return res.data; }; +export const getStudySynthesis = async (sid: string): Promise => { + const res = await client.get(`/v1/studies/${sid}/synthesis`); + return res.data; +}; + +export const downloadOutput = async (sid: string, output: string, data: StudyOutputDownloadDTO, jsonFormat = false, useTask = true): Promise => { + const restconfig = { + headers: { + Accept: 'application/zip', + responseType: 'blob', + 'Access-Control-Allow-Origin': '*', + }, + }; + const res = await client.post(`/v1/studies/${sid}/outputs/${output}/download?use_task=${useTask}`, data, jsonFormat ? {} : restconfig); + return res.data; +}; + export const createStudy = async (name: string, version: number): Promise => { const res = await client.post(`/v1/studies?name=${encodeURIComponent(name)}&version=${version}`); return res.data; diff --git a/webapp/src/services/api/variant.ts b/webapp/src/services/api/variant.ts index 2f8d686140..852767cdee 100644 --- a/webapp/src/services/api/variant.ts +++ b/webapp/src/services/api/variant.ts @@ -1,5 +1,5 @@ import client from './client'; -import { CommandDTO, FileStudyTreeConfigDTO, StudyMetadata, StudyMetadataDTO, TaskDTO, VariantTree } from '../../common/types'; +import { CommandDTO, StudyMetadata, StudyMetadataDTO, TaskDTO, VariantTree } from '../../common/types'; import { convertStudyDtoToMetadata, convertVariantTreeDTO } from '../utils'; export const getVariantChildren = async (id: string): Promise => { @@ -72,9 +72,4 @@ export const getStudyTask = async (studyId: string): Promise => { return res.data; }; -export const getStudySynthesis = async (studyId: string): Promise => { - const res = await client.get(`/v1/studies/${studyId}/synthesis`); - return res.data; -}; - export default {}; From 43dae365ab7ae5e2b20ba0cabaf957f7a704e3da Mon Sep 17 00:00:00 2001 From: Wintxer <47366828+Wintxer@users.noreply.github.com> Date: Thu, 10 Feb 2022 15:50:35 +0100 Subject: [PATCH 17/23] issue 520 add a map view of the study areas (#688) --- antarest/study/web/study_data_blueprint.py | 2 +- webapp/package-lock.json | 3238 +++++++++-------- webapp/package.json | 6 +- webapp/public/locales/en/main.json | 3 +- webapp/public/locales/en/singlestudy.json | 20 +- webapp/public/locales/fr/main.json | 3 +- webapp/public/locales/fr/singlestudy.json | 20 +- webapp/src/App/Pages/SingleStudy.tsx | 5 +- .../SingleStudy/MapView/CreateAreaModal.tsx | 80 + .../SingleStudy/MapView/GraphView.tsx | 74 + .../SingleStudy/MapView/LinksView.tsx | 119 + .../SingleStudy/MapView/NodeListing.tsx | 84 + .../SingleStudy/MapView/NodeView.tsx | 103 + .../SingleStudy/MapView/PanelView.tsx | 195 + .../SingleStudy/MapView/PropertiesView.tsx | 131 + .../components/SingleStudy/MapView/index.tsx | 363 ++ .../components/SingleStudy/MapView/types.ts | 108 + webapp/src/services/api/study.ts | 11 + webapp/src/services/api/studydata.ts | 29 + webapp/src/services/utils/index.ts | 38 + 20 files changed, 3025 insertions(+), 1607 deletions(-) create mode 100644 webapp/src/components/SingleStudy/MapView/CreateAreaModal.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/GraphView.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/LinksView.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/NodeListing.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/NodeView.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/PanelView.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/PropertiesView.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/index.tsx create mode 100644 webapp/src/components/SingleStudy/MapView/types.ts create mode 100644 webapp/src/services/api/studydata.ts diff --git a/antarest/study/web/study_data_blueprint.py b/antarest/study/web/study_data_blueprint.py index a2051efe06..86204512c6 100644 --- a/antarest/study/web/study_data_blueprint.py +++ b/antarest/study/web/study_data_blueprint.py @@ -97,7 +97,7 @@ def create_area( "/studies/{uuid}/links", tags=[APITag.study_data], summary="Create a link", - response_model=AreaInfoDTO, + response_model=LinkInfoDTO, ) def create_link( uuid: str, diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 525c538f47..d72f95b822 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -1,108 +1,131 @@ { "name": "antares-web", - "version": "2.2.1", + "version": "2.2.4", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", - "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "requires": { - "@babel/highlight": "^7.16.0" + "@babel/highlight": "^7.16.7" } }, "@babel/compat-data": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.0.tgz", - "integrity": "sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew==" + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==" }, "@babel/core": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz", - "integrity": "sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==", - "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helpers": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", + "gensync": "^1.0.0-beta.1", "json5": "^2.1.2", - "semver": "^6.3.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } } }, "@babel/generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", - "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", + "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", "requires": { - "@babel/types": "^7.16.0", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } } }, "@babel/helper-annotate-as-pure": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz", - "integrity": "sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz", - "integrity": "sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-compilation-targets": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.0.tgz", - "integrity": "sha512-S7iaOT1SYlqK0sQaCi21RX4+13hmdmnxIEAnQUB/eh7GeAnRjOUgTYpLkUOiRXzD+yog1JxP0qyAQZ7ZxVxLVg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "@babel/helper-create-class-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz", - "integrity": "sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", + "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-member-expression-to-functions": "^7.16.0", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz", - "integrity": "sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" } }, "@babel/helper-define-polyfill-provider": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.4.tgz", - "integrity": "sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "requires": { "@babel/helper-compilation-targets": "^7.13.0", "@babel/helper-module-imports": "^7.12.13", @@ -112,113 +135,129 @@ "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "requires": { + "@babel/types": "^7.16.7" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz", - "integrity": "sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", - "integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "requires": { - "@babel/helper-get-function-arity": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-get-function-arity": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz", - "integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-hoist-variables": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz", - "integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz", - "integrity": "sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-imports": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", - "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz", - "integrity": "sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==", - "requires": { - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.0", - "@babel/helper-simple-access": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-optimise-call-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz", - "integrity": "sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==" }, "@babel/helper-remap-async-to-generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.0.tgz", - "integrity": "sha512-MLM1IOMe9aQBqMWxcRw8dcb9jlM86NIw7KA0Wri91Xkfied+dE0QuBFSBjMNvqzmS0OSIDsMNC24dBEkPUi7ew==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-wrap-function": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helper-replace-supers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz", - "integrity": "sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "requires": { - "@babel/helper-member-expression-to-functions": "^7.16.0", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz", - "integrity": "sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-skip-transparent-expression-wrappers": { @@ -230,103 +269,103 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz", - "integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" }, "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" }, "@babel/helper-wrap-function": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz", - "integrity": "sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "requires": { - "@babel/helper-function-name": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helpers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.0.tgz", - "integrity": "sha512-dVRM0StFMdKlkt7cVcGgwD8UMaBfWJHl3A83Yfs8GQ3MO0LHIIIMvK7Fa0RGOGUQ10qikLaX6D7o5htcQWgTMQ==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", "requires": { - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" } }, "@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", - "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==" + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", + "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.2", - "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.16.2.tgz", - "integrity": "sha512-h37CvpLSf8gb2lIJ2CgC3t+EjFbi0t8qS7LCS1xcJIlEXE4czlofwaW7W1HA8zpgOCzI9C1nmoqNR1zWkk0pQg==", + "version": "7.16.7", + "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.16.7.tgz", + "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz", - "integrity": "sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0" + "@babel/plugin-proposal-optional-chaining": "^7.16.7" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.0.tgz", - "integrity": "sha512-nyYmIo7ZqKsY6P4lnVmBlxp9B3a96CscbLotlsNuktMHahkDwoPYEjXrZHU0Tj844Z9f1IthVxQln57mhkcExw==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", + "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.0", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz", - "integrity": "sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz", - "integrity": "sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", + "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, @@ -341,117 +380,117 @@ } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz", - "integrity": "sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz", - "integrity": "sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz", - "integrity": "sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz", - "integrity": "sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz", - "integrity": "sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz", - "integrity": "sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz", - "integrity": "sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", + "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.0" + "@babel/plugin-transform-parameters": "^7.16.7" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz", - "integrity": "sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz", - "integrity": "sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz", - "integrity": "sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz", - "integrity": "sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz", - "integrity": "sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-async-generators": { @@ -479,11 +518,11 @@ } }, "@babel/plugin-syntax-decorators": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.0.tgz", - "integrity": "sha512-nxnnngZClvlY13nHJAIDow0S7Qzhq64fQ/NlqS+VER3kjW/4F0jLhXjeL8jcwSwz6Ca3rotT5NJD2T9I7lcv7g==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", + "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-dynamic-import": { @@ -503,11 +542,11 @@ } }, "@babel/plugin-syntax-flow": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.0.tgz", - "integrity": "sha512-dH91yCo0RyqfzWgoM5Ji9ir8fQ+uFbt9KHM3d2x4jZOuHS6wNA+CRmRUP/BWCsHG2bjc7A2Way6AvH1eQk0wig==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz", + "integrity": "sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-json-strings": { @@ -519,11 +558,11 @@ } }, "@babel/plugin-syntax-jsx": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz", - "integrity": "sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", + "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-logical-assignment-operators": { @@ -591,101 +630,102 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz", - "integrity": "sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz", - "integrity": "sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz", - "integrity": "sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", "requires": { - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.0" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz", - "integrity": "sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz", - "integrity": "sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-classes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz", - "integrity": "sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz", - "integrity": "sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-destructuring": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz", - "integrity": "sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", + "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz", - "integrity": "sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz", - "integrity": "sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz", - "integrity": "sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-flow-strip-types": { @@ -698,196 +738,197 @@ } }, "@babel/plugin-transform-for-of": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz", - "integrity": "sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz", - "integrity": "sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "requires": { - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz", - "integrity": "sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz", - "integrity": "sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz", - "integrity": "sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz", - "integrity": "sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", + "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.16.0", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz", - "integrity": "sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg==", - "requires": { - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.15.7", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", + "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "requires": { + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz", - "integrity": "sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz", - "integrity": "sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", + "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" } }, "@babel/plugin-transform-new-target": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz", - "integrity": "sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-object-super": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz", - "integrity": "sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, "@babel/plugin-transform-parameters": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.0.tgz", - "integrity": "sha512-XgnQEm1CevKROPx+udOi/8f8TiGhrUWiHiaUCIp47tE0tpFDjzXNTZc9E5CmCwxNjXTWEVqvRfWZYOTFvMa/ZQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-property-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz", - "integrity": "sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-react-constant-elements": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.16.0.tgz", - "integrity": "sha512-OgtklS+p9t1X37eWA4XdvvbZG/3gqzX569gqmo3q4/Ui6qjfTQmOs5UTSrfdD9nVByHhX6Gbm/Pyc4KbwUXGWA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.16.7.tgz", + "integrity": "sha512-lF+cfsyTgwWkcw715J88JhMYJ5GpysYNLhLP1PkvkhTRN7B3e74R/1KsDxFxhRpSn0UUD3IWM4GvdBR2PEbbQQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-react-display-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz", - "integrity": "sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", + "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-react-jsx": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz", - "integrity": "sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", + "integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/plugin-transform-react-jsx-development": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz", - "integrity": "sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", + "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.0" + "@babel/plugin-transform-react-jsx": "^7.16.7" } }, "@babel/plugin-transform-react-jsx-self": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.0.tgz", - "integrity": "sha512-97yCFY+2GvniqOThOSjPor8xUoDiQ0STVWAQMl3pjhJoFVe5DuXDLZCRSZxu9clx+oRCbTiXGgKEG/Yoyo6Y+w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.7.tgz", + "integrity": "sha512-oe5VuWs7J9ilH3BCCApGoYjHoSO48vkjX2CbA5bFVhIuO2HKxA3vyF7rleA4o6/4rTDbk6r8hBW7Ul8E+UZrpA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-react-jsx-source": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.0.tgz", - "integrity": "sha512-8yvbGGrHOeb/oyPc9tzNoe9/lmIjz3HLa9Nc5dMGDyNpGjfFrk8D2KdEq9NRkftZzeoQEW6yPQ29TMZtrLiUUA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.7.tgz", + "integrity": "sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz", - "integrity": "sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", + "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz", - "integrity": "sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", + "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz", - "integrity": "sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-runtime": { @@ -899,109 +940,102 @@ "@babel/helper-plugin-utils": "^7.8.3", "resolve": "^1.8.1", "semver": "^5.5.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz", - "integrity": "sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz", - "integrity": "sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz", - "integrity": "sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz", - "integrity": "sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz", - "integrity": "sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typescript": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz", - "integrity": "sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-typescript": "^7.16.0" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-typescript": "^7.16.7" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz", - "integrity": "sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz", - "integrity": "sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/preset-env": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.0.tgz", - "integrity": "sha512-cdTu/W0IrviamtnZiTfixPfIncr2M1VqRrkjzZWlr1B4TVYimCFK5jkyOdP4qw2MrlKHi+b3ORj6x8GoCew8Dg==", - "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.0", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-async-generator-functions": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-class-static-block": "^7.16.0", - "@babel/plugin-proposal-dynamic-import": "^7.16.0", - "@babel/plugin-proposal-export-namespace-from": "^7.16.0", - "@babel/plugin-proposal-json-strings": "^7.16.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-object-rest-spread": "^7.16.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-proposal-private-property-in-object": "^7.16.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.0", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", + "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "requires": { + "@babel/compat-data": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", "@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", @@ -1016,45 +1050,52 @@ "@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.16.0", - "@babel/plugin-transform-async-to-generator": "^7.16.0", - "@babel/plugin-transform-block-scoped-functions": "^7.16.0", - "@babel/plugin-transform-block-scoping": "^7.16.0", - "@babel/plugin-transform-classes": "^7.16.0", - "@babel/plugin-transform-computed-properties": "^7.16.0", - "@babel/plugin-transform-destructuring": "^7.16.0", - "@babel/plugin-transform-dotall-regex": "^7.16.0", - "@babel/plugin-transform-duplicate-keys": "^7.16.0", - "@babel/plugin-transform-exponentiation-operator": "^7.16.0", - "@babel/plugin-transform-for-of": "^7.16.0", - "@babel/plugin-transform-function-name": "^7.16.0", - "@babel/plugin-transform-literals": "^7.16.0", - "@babel/plugin-transform-member-expression-literals": "^7.16.0", - "@babel/plugin-transform-modules-amd": "^7.16.0", - "@babel/plugin-transform-modules-commonjs": "^7.16.0", - "@babel/plugin-transform-modules-systemjs": "^7.16.0", - "@babel/plugin-transform-modules-umd": "^7.16.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.0", - "@babel/plugin-transform-new-target": "^7.16.0", - "@babel/plugin-transform-object-super": "^7.16.0", - "@babel/plugin-transform-parameters": "^7.16.0", - "@babel/plugin-transform-property-literals": "^7.16.0", - "@babel/plugin-transform-regenerator": "^7.16.0", - "@babel/plugin-transform-reserved-words": "^7.16.0", - "@babel/plugin-transform-shorthand-properties": "^7.16.0", - "@babel/plugin-transform-spread": "^7.16.0", - "@babel/plugin-transform-sticky-regex": "^7.16.0", - "@babel/plugin-transform-template-literals": "^7.16.0", - "@babel/plugin-transform-typeof-symbol": "^7.16.0", - "@babel/plugin-transform-unicode-escapes": "^7.16.0", - "@babel/plugin-transform-unicode-regex": "^7.16.0", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.16.8", + "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.0", - "babel-plugin-polyfill-corejs2": "^0.2.3", - "babel-plugin-polyfill-corejs3": "^0.3.0", - "babel-plugin-polyfill-regenerator": "^0.2.3", - "core-js-compat": "^3.19.0", + "@babel/types": "^7.16.8", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.20.2", "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "@babel/preset-modules": { @@ -1070,16 +1111,16 @@ } }, "@babel/preset-react": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.0.tgz", - "integrity": "sha512-d31IFW2bLRB28uL1WoElyro8RH5l6531XfxMtCeCmp6RVAF1uTfxxUA0LH1tXl+psZdwfmIbwoG4U5VwgbhtLw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", + "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-react-jsx": "^7.16.0", - "@babel/plugin-transform-react-jsx-development": "^7.16.0", - "@babel/plugin-transform-react-pure-annotations": "^7.16.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-transform-react-display-name": "^7.16.7", + "@babel/plugin-transform-react-jsx": "^7.16.7", + "@babel/plugin-transform-react-jsx-development": "^7.16.7", + "@babel/plugin-transform-react-pure-annotations": "^7.16.7" } }, "@babel/preset-typescript": { @@ -1092,54 +1133,55 @@ } }, "@babel/runtime": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.0.tgz", - "integrity": "sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", + "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.0.tgz", - "integrity": "sha512-Oi2qwQ21X7/d9gn3WiwkDTJmq3TQtYNz89lRnoFy8VeZpWlsyXvzSwiRrRZ8cXluvSwqKxqHJ6dBd9Rv+p0ZGQ==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz", + "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==", "requires": { - "core-js-pure": "^3.19.0", + "core-js-pure": "^3.20.2", "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz", - "integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/traverse": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz", - "integrity": "sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ==", - "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.0", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/types": "^7.16.0", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", + "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.0", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.0", + "@babel/types": "^7.17.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, @@ -1173,7 +1215,7 @@ }, "@choojs/findup": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@choojs/findup/-/findup-0.2.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@choojs/findup/-/findup-0.2.1.tgz", "integrity": "sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==", "requires": { "commander": "^2.15.1" @@ -1200,7 +1242,7 @@ }, "@emotion/hash": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@emotion/hash/-/hash-0.8.0.tgz", "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, "@fortawesome/fontawesome-common-types": { @@ -1222,6 +1264,13 @@ "integrity": "sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g==", "requires": { "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "dependencies": { + "@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==" + } } }, "@fortawesome/free-regular-svg-icons": { @@ -1230,6 +1279,13 @@ "integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==", "requires": { "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "dependencies": { + "@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==" + } } }, "@fortawesome/free-solid-svg-icons": { @@ -1238,14 +1294,21 @@ "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", "requires": { "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "dependencies": { + "@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==" + } } }, "@fortawesome/react-fontawesome": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.16.tgz", - "integrity": "sha512-aLmzDwC9rEOAJv2UJdMns89VZR5Ry4IHu5dQQh24Z/lWKEm44lfQr1UNalZlkUaQN8d155tNh+CS7ntntj1VMA==", + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.17.tgz", + "integrity": "sha512-dX43Z5IvMaW7fwzU8farosYjKNGfRb2HB/DgjVBHeJZ/NSnuuaujPPx0YOdcAq+n3mqn70tyCde2HM1mqbhiuw==", "requires": { - "prop-types": "^15.7.2" + "prop-types": "^15.8.1" } }, "@handsontable/react": { @@ -1287,6 +1350,11 @@ "@hapi/hoek": "^8.3.0" } }, + "@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==" + }, "@jest/console": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", @@ -1402,13 +1470,6 @@ "slash": "^2.0.0", "source-map": "^0.6.0", "string-length": "^2.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "@jest/source-map": { @@ -1425,11 +1486,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -1475,13 +1531,6 @@ "slash": "^2.0.0", "source-map": "^0.6.1", "write-file-atomic": "2.4.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "@jest/types": { @@ -1509,7 +1558,7 @@ }, "@mapbox/geojson-rewind": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/geojson-rewind/-/geojson-rewind-0.5.1.tgz", "integrity": "sha512-eL7fMmfTBKjrb+VFHXCGv9Ot0zc3C0U+CwXo1IrP+EPwDczLoXv34Tgq3y+2mPSFNVUXgU42ILWJTC7145KPTA==", "requires": { "get-stream": "^6.0.1", @@ -1518,37 +1567,37 @@ }, "@mapbox/geojson-types": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz", "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==" }, "@mapbox/jsonlint-lines-primitives": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", "integrity": "sha1-zlblOfg1UrWNENZy6k1vya3HsjQ=" }, "@mapbox/mapbox-gl-supported": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz", "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==" }, "@mapbox/point-geometry": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", "integrity": "sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=" }, "@mapbox/tiny-sdf": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz", "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==" }, "@mapbox/unitbezier": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", "integrity": "sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4=" }, "@mapbox/vector-tile": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", "requires": { "@mapbox/point-geometry": "~0.1.0" @@ -1556,7 +1605,7 @@ }, "@mapbox/whoots-js": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==" }, "@material-ui/core": { @@ -1663,12 +1712,12 @@ }, "@plotly/d3": { "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@plotly/d3/-/d3-3.8.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@plotly/d3/-/d3-3.8.0.tgz", "integrity": "sha512-L10iHgzvw3uSic/nQpYehlNzxUQvImwms5U7S95pJAEhrllzkrdQNy1Mc5DW9ab881Yr4fh300gJztKXWZDfkQ==" }, "@plotly/d3-sankey": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@plotly/d3-sankey/-/d3-sankey-0.7.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@plotly/d3-sankey/-/d3-sankey-0.7.2.tgz", "integrity": "sha512-2jdVos1N3mMp3QW0k2q1ph7Gd6j5PY1YihBrwpkFnKqO+cqtZq3AdEYUeSGXMeLsBDQYiqTVcihYfk8vr5tqhw==", "requires": { "d3-array": "1", @@ -1678,7 +1727,7 @@ }, "@plotly/d3-sankey-circular": { "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@plotly/d3-sankey-circular/-/d3-sankey-circular-0.33.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@plotly/d3-sankey-circular/-/d3-sankey-circular-0.33.1.tgz", "integrity": "sha512-FgBV1HEvCr3DV7RHhDsPXyryknucxtfnLwPtCKKxdolKyTFYoLX/ibEfX39iFYIL7DYbVeRtP43dbFcrHNE+KQ==", "requires": { "d3-array": "^1.2.1", @@ -1689,7 +1738,7 @@ }, "@plotly/point-cluster": { "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@plotly/point-cluster/-/point-cluster-3.1.9.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@plotly/point-cluster/-/point-cluster-3.1.9.tgz", "integrity": "sha512-MwaI6g9scKf68Orpr1pHZ597pYx9uP8UEFXLPbsCmuw3a84obwz6pnMXGc90VhgDNeNiLEdlmuK7CPo+5PIxXw==", "requires": { "array-bounds": "^1.0.1", @@ -1706,17 +1755,17 @@ }, "@react-dnd/asap": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@react-dnd/asap/-/asap-4.0.0.tgz", "integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==" }, "@react-dnd/invariant": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@react-dnd/invariant/-/invariant-2.0.0.tgz", "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" }, "@react-dnd/shallowequal": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" }, "@sheerun/mutationobserver-shim": { @@ -1724,6 +1773,11 @@ "resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz", "integrity": "sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw==" }, + "@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" + }, "@socket.io/component-emitter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", @@ -1965,7 +2019,7 @@ }, "@turf/area": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@turf/area/-/area-6.5.0.tgz", "integrity": "sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==", "requires": { "@turf/helpers": "^6.5.0", @@ -1974,7 +2028,7 @@ }, "@turf/bbox": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-6.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@turf/bbox/-/bbox-6.5.0.tgz", "integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==", "requires": { "@turf/helpers": "^6.5.0", @@ -1983,7 +2037,7 @@ }, "@turf/centroid": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@turf/centroid/-/centroid-6.5.0.tgz", "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==", "requires": { "@turf/helpers": "^6.5.0", @@ -1992,21 +2046,21 @@ }, "@turf/helpers": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@turf/helpers/-/helpers-6.5.0.tgz", "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==" }, "@turf/meta": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/@turf/meta/-/meta-6.5.0.tgz", "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", "requires": { "@turf/helpers": "^6.5.0" } }, "@types/babel__core": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", - "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", "requires": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0", @@ -2016,9 +2070,9 @@ } }, "@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "requires": { "@babel/types": "^7.0.0" } @@ -2094,19 +2148,12 @@ } }, "@types/draft-js": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/@types/draft-js/-/draft-js-0.11.6.tgz", - "integrity": "sha512-TY5/Ba9m/uXAJKJc9AxV8r3OpjXk7G0DoI1v99g9aGsx5mJSIK46f2VsFWR8aVTgMxFoxbDLx79Hkri+EbCOYQ==", + "version": "0.11.9", + "resolved": "https://registry.npmjs.org/@types/draft-js/-/draft-js-0.11.9.tgz", + "integrity": "sha512-cQJBZjjIlGaPA1tOY+wGz2KhlPtAAZOIXpUvGPxPRw5uzZ2tcj8m6Yu1QDV9YgP36+cqE3cUvgkARBzgUiuI/Q==", "requires": { "@types/react": "*", "immutable": "~3.7.4" - }, - "dependencies": { - "immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" - } } }, "@types/draftjs-to-html": { @@ -2140,9 +2187,9 @@ } }, "@types/history": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", - "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==" + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" }, "@types/hoist-non-react-statics": { "version": "3.3.1", @@ -2154,9 +2201,9 @@ } }, "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" }, "@types/istanbul-lib-report": { "version": "3.0.0", @@ -2201,9 +2248,9 @@ "dev": true }, "@types/lodash": { - "version": "4.14.176", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.176.tgz", - "integrity": "sha512-xZmuPTa3rlZoIbtDUyJKZQimJV3bxCmzMIO2c9Pz9afyDro6kr7R79GwcB6mRhuoPmV2p1Vb66WOJH7F886WKQ==" + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" }, "@types/minimatch": { "version": "3.0.5", @@ -2217,9 +2264,9 @@ "dev": true }, "@types/node": { - "version": "12.20.36", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.36.tgz", - "integrity": "sha512-+5haRZ9uzI7rYqzDznXgkuacqb6LJhAti8mzZKWxIXn/WEtvB+GHVJ7AuMwcN1HMvXOSJcrvA6PPoYHYOYYebA==" + "version": "12.20.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.43.tgz", + "integrity": "sha512-HCfJdaYqJX3BCzeihgZrD7b85Cu05OC/GVJ4kEYIflwUs4jbnUlLLWoq7hw1LBcdvUyehO+gr6P5JQ895/2ZfA==" }, "@types/parse-json": { "version": "4.0.0", @@ -2235,9 +2282,9 @@ } }, "@types/plotly.js": { - "version": "1.54.16", - "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-1.54.16.tgz", - "integrity": "sha512-Kli9UqZwO12cvJ4dT2kGaBtpgq96y8TPsvsB87XTCO+jEMMVy0OZ4WMW+8plS/lBKCtMNtwRNYNlD3+8Stgn2Q==", + "version": "1.54.20", + "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-1.54.20.tgz", + "integrity": "sha512-vqiqq5chr72QoApD+6Hu52iuBvT5/po/sdVF74IBnacQV6J1MjH9OeFZ3GFDwKLF24xT++FMkEGAWcgVMwg2YQ==", "dev": true, "requires": { "@types/d3": "^3" @@ -2254,9 +2301,9 @@ "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" }, "@types/react": { - "version": "16.14.20", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.20.tgz", - "integrity": "sha512-SV7TaVc8e9E/5Xuv6TIyJ5VhQpZoVFJqX6IZgj5HZoFCtIDCArE3qXkcHlc6O/Ud4UwcMoX+tlvDA95YrKdLgA==", + "version": "16.14.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.23.tgz", + "integrity": "sha512-WngBZLuSkP4IAgPi0HOsGCHo6dn3CcuLQnCfC17VbA7YBgipZiZoTOhObwl/93DsFW0Y2a/ZXeonpW4DxirEJg==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2264,9 +2311,9 @@ }, "dependencies": { "csstype": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" } } }, @@ -2279,6 +2326,25 @@ "@types/react": "*" } }, + "@types/react-color": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.6.tgz", + "integrity": "sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==", + "dev": true, + "requires": { + "@types/react": "*", + "@types/reactcss": "*" + } + }, + "@types/react-d3-graph": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/react-d3-graph/-/react-d3-graph-2.6.3.tgz", + "integrity": "sha512-OYM7eO/4U6ARP8E3izk5VrkHLqO/0YI3QGFymLGt/AR/ETbc4Spx0Ljpa/3hJ/0wLmncLTyUV6gegcNooDAEww==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-dom": { "version": "16.9.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.14.tgz", @@ -2298,9 +2364,9 @@ } }, "@types/react-redux": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz", - "integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==", + "version": "7.1.22", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", + "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -2318,31 +2384,31 @@ } }, "@types/react-router": { - "version": "5.1.17", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz", - "integrity": "sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ==", + "version": "5.1.18", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", + "integrity": "sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g==", "requires": { - "@types/history": "*", + "@types/history": "^4.7.11", "@types/react": "*" } }, "@types/react-router-dom": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz", - "integrity": "sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", "dev": true, "requires": { - "@types/history": "*", + "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router": "*" } }, "@types/react-router-redux": { - "version": "5.0.20", - "resolved": "https://registry.npmjs.org/@types/react-router-redux/-/react-router-redux-5.0.20.tgz", - "integrity": "sha512-2TFSRXk1dvEbG5jfbkyU8HB6Ezhbql582S4AsMa2mo59DFZD6VszXd6DLhT6gY1tWj4H/AkLh334rrtf20uH0Q==", + "version": "5.0.21", + "resolved": "https://registry.npmjs.org/@types/react-router-redux/-/react-router-redux-5.0.21.tgz", + "integrity": "sha512-BF2OrI3bW5gJhjqKElu/YK7lnUySFV9BMm5ryJbm47rARLLdCr72dC6cXBzcFORqsDTCrFbhsFsq2ogJRY4fvg==", "requires": { - "@types/history": "*", + "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router": "*", "redux": ">= 3.7.2" @@ -2357,9 +2423,9 @@ } }, "@types/react-virtualized": { - "version": "9.21.14", - "resolved": "https://registry.npmjs.org/@types/react-virtualized/-/react-virtualized-9.21.14.tgz", - "integrity": "sha512-wvZftXXYNpj3ELVm2v8pySnq/uxKD1UsFpRkNoBAbQFTnI4Bz4OcwjUhwvaqUq5dDoT6SCS2+PdCzysxMYfjdg==", + "version": "9.21.17", + "resolved": "https://registry.npmjs.org/@types/react-virtualized/-/react-virtualized-9.21.17.tgz", + "integrity": "sha512-8JWc9GzurY9L0iqlL+dPziUsyP7MsY27m8k8mCEZNvuYwA3o2vvbkRkb1IoCdV2XYwPU4w8wfaBHungLGr0b4w==", "dev": true, "requires": { "@types/prop-types": "*", @@ -2384,6 +2450,15 @@ "@types/react": "*" } }, + "@types/reactcss": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.6.tgz", + "integrity": "sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/redux": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/@types/redux/-/redux-3.6.0.tgz", @@ -2800,22 +2875,22 @@ }, "abs-svg-path": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/abs-svg-path/-/abs-svg-path-0.1.1.tgz", "integrity": "sha1-32Acjo0roQ1KdtYl4japo5wnI78=" }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "ace-builds": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.13.tgz", - "integrity": "sha512-SOLzdaQkY6ecPKYRDDg+MY1WoGgXA34cIvYJNNoBMGGUswHmlauU2Hy0UL96vW0Fs/LgFbMUjD+6vqzWTldIYQ==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.14.tgz", + "integrity": "sha512-NBOQlm9+7RBqRqZwimpgquaLeTJFayqb9UEPtTkpC3TkkwDnlsT/TwsCC0svjt9kEZ6G9mH5AEOHSz6Q/HrzQQ==" }, "acorn": { "version": "7.4.1", @@ -2906,7 +2981,7 @@ }, "almost-equal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/almost-equal/-/almost-equal-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/almost-equal/-/almost-equal-1.1.0.tgz", "integrity": "sha1-+FHGMROHV5lCdqou++jfowZszN0=" }, "alphanum-sort": { @@ -3047,7 +3122,7 @@ }, "array-bounds": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-bounds/-/array-bounds-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/array-bounds/-/array-bounds-1.0.1.tgz", "integrity": "sha512-8wdW3ZGk6UjMPJx/glyEt0sLzzwAE1bhToPsO1W2pbpR2gULyxe3BjSiuJFheP50T/GgODVPz2fuMUmIywt8cQ==" }, "array-equal": { @@ -3057,7 +3132,7 @@ }, "array-find-index": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" }, "array-flatten": { @@ -3079,7 +3154,7 @@ }, "array-normalize": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array-normalize/-/array-normalize-1.1.4.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/array-normalize/-/array-normalize-1.1.4.tgz", "integrity": "sha512-fCp0wKFLjvSPmCn4F5Tiw4M3lpMZoHlCjfcs7nNzuj3vqQQ1/a8cgB9DXcpDSn18c+coLnaW7rqfcYCvKbyJXg==", "requires": { "array-bounds": "^1.0.0" @@ -3087,12 +3162,12 @@ }, "array-range": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-range/-/array-range-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/array-range/-/array-range-1.0.1.tgz", "integrity": "sha1-9W5GWRhDYRxqVvd+8C7afFAIm/w=" }, "array-rearrange": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/array-rearrange/-/array-rearrange-2.2.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/array-rearrange/-/array-rearrange-2.2.2.tgz", "integrity": "sha512-UfobP5N12Qm4Qu4fwLDIi2v6+wZsSf6snYSxAMeKhrh37YGnNWZPRmVEKc/2wfms53TLQnzfpG8wCx2Y/6NG1w==" }, "array-union": { @@ -3244,7 +3319,7 @@ }, "atob-lite": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/atob-lite/-/atob-lite-2.0.0.tgz", "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=" }, "autolinker": { @@ -3287,9 +3362,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "axe-core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", - "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", + "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", "dev": true }, "axios": { @@ -3498,35 +3573,42 @@ } }, "babel-plugin-named-asset-import": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz", - "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==" + "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==" }, "babel-plugin-polyfill-corejs2": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz", - "integrity": "sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", "requires": { "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.4", + "@babel/helper-define-polyfill-provider": "^0.3.1", "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "babel-plugin-polyfill-corejs3": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.3.0.tgz", - "integrity": "sha512-JLwi9vloVdXLjzACL80j24bG6/T1gYxwowG44dg6HN/7aTPdyPbJJidf6ajoA3RPHHtW0j9KMrSOLpIZpAnPpg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.4", - "core-js-compat": "^3.18.0" + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.3.tgz", - "integrity": "sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.4" + "@babel/helper-define-polyfill-provider": "^0.3.1" } }, "babel-plugin-syntax-object-rest-spread": { @@ -3579,29 +3661,6 @@ "babel-plugin-transform-react-remove-prop-types": "0.4.24" }, "dependencies": { - "@babel/core": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", - "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.0", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.0", - "@babel/parser": "^7.9.0", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, "@babel/plugin-proposal-class-properties": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", @@ -3733,11 +3792,6 @@ "requires": { "regenerator-runtime": "^0.13.4" } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, @@ -3837,11 +3891,6 @@ "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" }, - "base64-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz", - "integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==" - }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -3882,7 +3931,7 @@ }, "binary-search-bounds": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", "integrity": "sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==" }, "bindings": { @@ -3901,7 +3950,7 @@ }, "bitmap-sdf": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bitmap-sdf/-/bitmap-sdf-1.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/bitmap-sdf/-/bitmap-sdf-1.0.3.tgz", "integrity": "sha512-ojYySSvWTx21cbgntR942zgEgqj38wHctN64vr4vYRFf3GKVmI23YlA94meWGkFslidwLwGCsMy2laJ3g/94Sg==", "requires": { "clamp": "^1.0.1" @@ -3957,26 +4006,26 @@ "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", "requires": { - "bytes": "3.1.0", + "bytes": "3.1.1", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" }, "dependencies": { "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" }, "debug": { "version": "2.6.9", @@ -3992,9 +4041,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" } } }, @@ -4170,12 +4219,12 @@ } }, "browserslist": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz", - "integrity": "sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", "requires": { - "caniuse-lite": "^1.0.30001274", - "electron-to-chromium": "^1.3.886", + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", "escalade": "^3.1.1", "node-releases": "^2.0.1", "picocolors": "^1.0.0" @@ -4374,13 +4423,13 @@ } }, "caniuse-lite": { - "version": "1.0.30001278", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001278.tgz", - "integrity": "sha512-mpF9KeH8u5cMoEmIic/cr7PNS+F5LWBk0t2ekGT60lFf0Wq+n9LspAj0g3P+o7DQhD3sUdlMln4YFAWhFYn9jg==" + "version": "1.0.30001310", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001310.tgz", + "integrity": "sha512-cb9xTV8k9HTIUA3GnPUJCk0meUnrHL5gy5QePfDjxHyNBcnzPzrHFv5GqfP7ue5b1ZyzZL0RJboD6hQlPXjhjg==" }, "canvas-fit": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/canvas-fit/-/canvas-fit-1.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/canvas-fit/-/canvas-fit-1.5.0.tgz", "integrity": "sha1-rhO+Zq3kL1vg5IfjRfzjCl5bXl8=", "requires": { "element-size": "^1.1.1" @@ -4449,9 +4498,9 @@ } }, "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4541,7 +4590,7 @@ }, "clamp": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/clamp/-/clamp-1.0.1.tgz", "integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ=" }, "class-utils": { @@ -4576,13 +4625,6 @@ "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", "requires": { "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "clean-stack": { @@ -4706,7 +4748,7 @@ }, "color-alpha": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/color-alpha/-/color-alpha-1.0.4.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/color-alpha/-/color-alpha-1.0.4.tgz", "integrity": "sha512-lr8/t5NPozTSqli+duAN+x+no/2WaKTeWvxhHGN+aXT6AJ8vPlzLa7UriyjWak0pSC2jHol9JgjBYnnHsGha9A==", "requires": { "color-parse": "^1.3.8" @@ -4722,7 +4764,7 @@ }, "color-id": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/color-id/-/color-id-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/color-id/-/color-id-1.1.0.tgz", "integrity": "sha512-2iRtAn6dC/6/G7bBIo0uupVrIne1NsQJvJxZOBCzQOfk7jRq97feaDZ3RdzuHakRXXnHGNwglto3pqtRx1sX0g==", "requires": { "clamp": "^1.0.1" @@ -4735,7 +4777,7 @@ }, "color-normalize": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/color-normalize/-/color-normalize-1.5.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/color-normalize/-/color-normalize-1.5.0.tgz", "integrity": "sha512-rUT/HDXMr6RFffrR53oX3HGWkDOP9goSAQGBkUaAYKjOE2JxozccdGyufageWDlInRAjm/jYPrf/Y38oa+7obw==", "requires": { "clamp": "^1.0.1", @@ -4745,7 +4787,7 @@ }, "color-parse": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.3.8.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/color-parse/-/color-parse-1.3.8.tgz", "integrity": "sha512-1Y79qFv0n1xair3lNMTNeoFvmc3nirMVBij24zbs1f13+7fPpQClMg5b4AuKXLt3szj7BRlHMCXHplkce6XlmA==", "requires": { "color-name": "^1.0.0", @@ -4755,7 +4797,7 @@ }, "color-rgba": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-2.1.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/color-rgba/-/color-rgba-2.1.1.tgz", "integrity": "sha512-VaX97wsqrMwLSOR6H7rU1Doa2zyVdmShabKrPEIFywLlHoibgD3QW9Dw6fSqM4+H/LfjprDNAUUW31qEQcGzNw==", "requires": { "clamp": "^1.0.1", @@ -4765,7 +4807,7 @@ }, "color-space": { "version": "1.16.0", - "resolved": "https://registry.npmjs.org/color-space/-/color-space-1.16.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/color-space/-/color-space-1.16.0.tgz", "integrity": "sha512-A6WMiFzunQ8KEPFmj02OnnoUnqhmSaHaZ/0LVFcPTdlvm8+3aMJ5x1HRHy3bDHPkovkf4sS0f4wsVvwk71fKkg==", "requires": { "hsluv": "^0.0.3", @@ -4773,9 +4815,9 @@ } }, "color-string": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", - "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -4800,9 +4842,9 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "common-tags": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", - "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==" + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==" }, "commondir": { "version": "1.0.1", @@ -4861,7 +4903,7 @@ }, "compute-dims": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/compute-dims/-/compute-dims-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/compute-dims/-/compute-dims-1.1.0.tgz", "integrity": "sha512-YHMiIKjH/8Eom8zATk3g8/lH3HxGCZcVQyEfEoVrfWI7od/WRpTgRGShnei3jArYSx77mQqPxZNokjGHCdLfxg==", "requires": { "utils-copy": "^1.0.0", @@ -4917,9 +4959,9 @@ } }, "confusing-browser-globals": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", - "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==" + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" }, "connect-history-api-fallback": { "version": "1.6.0", @@ -4939,12 +4981,12 @@ }, "const-max-uint32": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/const-max-uint32/-/const-max-uint32-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/const-max-uint32/-/const-max-uint32-1.0.2.tgz", "integrity": "sha1-8Am7YjDmeO2HTdLWqc2ePL+rtnY=" }, "const-pinf-float64": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/const-pinf-float64/-/const-pinf-float64-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/const-pinf-float64/-/const-pinf-float64-1.0.0.tgz", "integrity": "sha1-9u+w15+cCYbT558pI6v5twtj1yY=" }, "constants-browserify": { @@ -4958,11 +5000,18 @@ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } } }, "content-type": { @@ -4979,9 +5028,9 @@ } }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" }, "cookie-signature": { "version": "1.0.6", @@ -4989,12 +5038,12 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "copy-anything": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.3.tgz", - "integrity": "sha512-GK6QUtisv4fNS+XcI7shX0Gx9ORg7QqIznyfho79JTnX1XhLiyZHfftvGiziqzRiEi/Bjhgpi+D2o7HxJFPnDQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, "requires": { - "is-what": "^3.12.0" + "is-what": "^3.14.1" } }, "copy-concurrently": { @@ -5042,16 +5091,16 @@ } }, "core-js": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.1.tgz", - "integrity": "sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg==" + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.0.tgz", + "integrity": "sha512-YUdI3fFu4TF/2WykQ2xzSiTQdldLB4KVuL9WeAy5XONZYt5Cun/fpQvctoKbCgvPhmzADeesTk/j2Rdx77AcKQ==" }, "core-js-compat": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.1.tgz", - "integrity": "sha512-Q/VJ7jAF/y68+aUsQJ/afPOewdsGkDtcMb40J8MbuWKlK3Y+wtHq8bTHKPj2WKWLIqmS5JhHs4CzHtz6pT2W6g==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", + "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", "requires": { - "browserslist": "^4.17.6", + "browserslist": "^4.19.1", "semver": "7.0.0" }, "dependencies": { @@ -5063,9 +5112,9 @@ } }, "core-js-pure": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz", - "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==" + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.0.tgz", + "integrity": "sha512-VaJUunCZLnxuDbo1rNOzwbet9E1K9joiXS5+DQMPtgxd24wfsZbJZMMfQLGYMlCUvSxLfsRUUhoOR2x28mFfeg==" }, "core-util-is": { "version": "1.0.3", @@ -5094,7 +5143,7 @@ }, "country-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/country-regex/-/country-regex-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/country-regex/-/country-regex-1.1.0.tgz", "integrity": "sha1-UcMz3N8Sknt+XuucEKyBEqYSCJY=" }, "create-ecdh": { @@ -5148,11 +5197,11 @@ } }, "cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", "requires": { - "node-fetch": "2.6.1" + "node-fetch": "2.6.7" } }, "cross-spawn": { @@ -5167,11 +5216,6 @@ "which": "^1.2.9" }, "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -5209,13 +5253,6 @@ "source-map": "^0.6.1", "source-map-resolve": "^0.5.2", "urix": "^0.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "css-blank-pseudo": { @@ -5250,7 +5287,7 @@ }, "css-font": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-font/-/css-font-1.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/css-font/-/css-font-1.2.0.tgz", "integrity": "sha512-V4U4Wps4dPDACJ4WpgofJ2RT5Yqwe1lEH6wlOOaIxMi0gTjdIijsc5FmxQlZ7ZZyKQkkutqqvULOp07l9c7ssA==", "requires": { "css-font-size-keywords": "^1.0.0", @@ -5266,27 +5303,27 @@ }, "css-font-size-keywords": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz", "integrity": "sha1-hUh1rOmspqjS7g00WkSq6btttss=" }, "css-font-stretch-keywords": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz", "integrity": "sha1-UM7puboDH7XJUtRyMTnx4Qe1SxA=" }, "css-font-style-keywords": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz", "integrity": "sha1-XDUygT9jtKHelU0TzqhqtDM0CeQ=" }, "css-font-weight-keywords": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz", "integrity": "sha1-m8BGcayFvHJLV07106yWsNYE/Zc=" }, "css-global-keywords": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-global-keywords/-/css-global-keywords-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/css-global-keywords/-/css-global-keywords-1.0.1.tgz", "integrity": "sha1-cqmupyeW0Bmx0qMlLeTlqqN+Smk=" }, "css-has-pseudo": { @@ -5367,7 +5404,7 @@ }, "css-system-font-keywords": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz", "integrity": "sha1-hcbwhquk6zLFcaMIav/ENLhII+0=" }, "css-tree": { @@ -5377,13 +5414,6 @@ "requires": { "mdn-data": "2.0.4", "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "css-vendor": { @@ -5407,7 +5437,7 @@ }, "csscolorparser": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/csscolorparser/-/csscolorparser-1.0.3.tgz", "integrity": "sha1-s085HupNqPPpgjHizNjfnAQfFxs=" }, "cssdb": { @@ -5512,11 +5542,6 @@ "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -5534,9 +5559,9 @@ } }, "csstype": { - "version": "2.6.18", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz", - "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==" + "version": "2.6.19", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", + "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==" }, "cyclist": { "version": "1.0.1", @@ -5554,12 +5579,12 @@ }, "d3-array": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-array/-/d3-array-1.2.4.tgz", "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" }, "d3-collection": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-collection/-/d3-collection-1.0.7.tgz", "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" }, "d3-color": { @@ -5588,7 +5613,7 @@ }, "d3-force": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-force/-/d3-force-1.2.1.tgz", "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", "requires": { "d3-collection": "1", @@ -5599,12 +5624,12 @@ }, "d3-format": { "version": "1.4.5", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-format/-/d3-format-1.4.5.tgz", "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" }, "d3-geo": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-geo/-/d3-geo-1.12.1.tgz", "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", "requires": { "d3-array": "1" @@ -5612,7 +5637,7 @@ }, "d3-geo-projection": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.9.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-geo-projection/-/d3-geo-projection-2.9.0.tgz", "integrity": "sha512-ZULvK/zBn87of5rWAfFMc9mJOipeSo57O+BBitsKIXmU4rTVAnX1kSsJkE0R+TxY8pGNoM1nbyRRE7GYHhdOEQ==", "requires": { "commander": "2", @@ -5641,7 +5666,7 @@ }, "d3-quadtree": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-quadtree/-/d3-quadtree-1.0.7.tgz", "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==" }, "d3-selection": { @@ -5659,12 +5684,12 @@ }, "d3-time": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-time/-/d3-time-1.1.0.tgz", "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" }, "d3-time-format": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/d3-time-format/-/d3-time-format-2.3.0.tgz", "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", "requires": { "d3-time": "1" @@ -5701,9 +5726,9 @@ } }, "damerau-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", - "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==" + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" }, "dashdash": { "version": "1.14.1", @@ -5723,6 +5748,19 @@ "whatwg-url": "^7.0.0" }, "dependencies": { + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, "whatwg-url": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", @@ -5736,9 +5774,9 @@ } }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { "ms": "2.1.2" } @@ -5790,6 +5828,11 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, "default-gateway": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", @@ -5851,7 +5894,7 @@ }, "defined": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/defined/-/defined-1.0.0.tgz", "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" }, "del": { @@ -5944,7 +5987,7 @@ }, "detect-kerning": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-kerning/-/detect-kerning-2.1.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/detect-kerning/-/detect-kerning-2.1.2.tgz", "integrity": "sha512-I3JIbrnKPAntNLl1I6TpSQQdQ4AutYzv/sKMFKbepawV/hlH0GmYKhUoOEMd4xqaUHT+Bm0f4127lh5qs1m1tw==" }, "detect-libc": { @@ -6025,7 +6068,7 @@ }, "dnd-core": { "version": "10.0.2", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-10.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/dnd-core/-/dnd-core-10.0.2.tgz", "integrity": "sha512-PrxEjxF0+6Y1n1n1Z9hSWZ1tvnDXv9syL+BccV1r1RC08uWNsyetf8AnWmUF3NgYPwy0HKQJwTqGkZK+1NlaFA==", "requires": { "@react-dnd/asap": "^4.0.0", @@ -6086,9 +6129,9 @@ }, "dependencies": { "csstype": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" } } }, @@ -6124,12 +6167,19 @@ "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "requires": { "webidl-conversions": "^4.0.2" + }, + "dependencies": { + "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==" + } } }, "domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", "requires": { "domelementtype": "^2.2.0" }, @@ -6142,9 +6192,9 @@ } }, "dompurify": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz", - "integrity": "sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg==" + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz", + "integrity": "sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==" }, "domutils": { "version": "1.7.0", @@ -6204,13 +6254,6 @@ "@babel/runtime": "^7.5.5", "immutable": "~3.7.4", "invariant": "^2.2.1" - }, - "dependencies": { - "immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" - } } }, "draft-js": { @@ -6221,36 +6264,6 @@ "fbjs": "^2.0.0", "immutable": "~3.7.4", "object-assign": "^4.1.1" - }, - "dependencies": { - "fbjs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", - "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", - "requires": { - "core-js": "^3.6.4", - "cross-fetch": "^3.0.4", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - }, - "immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" - }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "requires": { - "asap": "~2.0.3" - } - } } }, "draftjs-to-html": { @@ -6260,7 +6273,7 @@ }, "draw-svg-path": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/draw-svg-path/-/draw-svg-path-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/draw-svg-path/-/draw-svg-path-1.0.0.tgz", "integrity": "sha1-bxFtli3TFLmepTTW9Y3WbNvWk3k=", "requires": { "abs-svg-path": "~0.1.1", @@ -6269,12 +6282,12 @@ }, "dtype": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dtype/-/dtype-2.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/dtype/-/dtype-2.0.0.tgz", "integrity": "sha1-zQUjI84GFETs0uj1dI9popvihDQ=" }, "dup": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/dup/-/dup-1.0.0.tgz", "integrity": "sha1-UfxaxoX4GWRp3wuQXpNLIK9bQCk=" }, "duplexer": { @@ -6324,7 +6337,7 @@ }, "earcut": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/earcut/-/earcut-2.2.3.tgz", "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==" }, "ecc-jsbn": { @@ -6342,18 +6355,18 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.890", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.890.tgz", - "integrity": "sha512-VWlVXSkv0cA/OOehrEyqjUTHwV8YXCPTfPvbtoeU2aHR21vI4Ejh5aC4AxUwOmbLbBgb6Gd3URZahoCxtBqCYQ==" + "version": "1.4.67", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.67.tgz", + "integrity": "sha512-A6a2jEPLueEDfb7kvh7/E94RKKnIb01qL+4I7RFxtajmo+G9F5Ei7HgY5PRbQ4RDrh6DGDW66P0hD5XI2nRAcg==" }, "element-size": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/element-size/-/element-size-1.1.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/element-size/-/element-size-1.1.1.tgz", "integrity": "sha1-ZOXxWdlxIWMYRby67K8nnDm1404=" }, "elementary-circuits-directed-graph": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/elementary-circuits-directed-graph/-/elementary-circuits-directed-graph-1.3.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/elementary-circuits-directed-graph/-/elementary-circuits-directed-graph-1.3.1.tgz", "integrity": "sha512-ZEiB5qkn2adYmpXGnJKkxT8uJHlW/mxmBpmeqawEHzPxh9HkLD4/1mFYX5l0On+f6rcPIt8/EWlRU2Vo3fX6dQ==", "requires": { "strongly-connected-components": "^1.0.1" @@ -6409,9 +6422,9 @@ } }, "engine.io": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.0.1.tgz", - "integrity": "sha512-Y53UaciUh2Rmx5MiogtMxOQcfh7pnemday+Bb4QDg0Wjmnvo/VTvuEyNGQgYmh8L7VOe8Je1QuiqjLNDelMqLA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.1.2.tgz", + "integrity": "sha512-v/7eGHxPvO2AWsksyx2PUsQvBafuvqs0jJJQ0FdmJG1b9qIvgSbqDRGwNhfk2XHaTTbTXiC4quRE8Q9nRjsrQQ==", "requires": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -6425,11 +6438,6 @@ "ws": "~8.2.3" }, "dependencies": { - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, "ws": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", @@ -6438,9 +6446,9 @@ } }, "engine.io-client": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.0.2.tgz", - "integrity": "sha512-cAep9lhZV6Q8jMXx3TNSU5cydMzMed8/O7Tz5uzyqZvpNPtQ3WQXrLYGADxlsuaFmOLN7wZLmT7ImiFhUOku8g==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", "requires": { "@socket.io/component-emitter": "~3.0.0", "debug": "~4.3.1", @@ -6461,11 +6469,11 @@ } }, "engine.io-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.1.tgz", - "integrity": "sha512-j4p3WwJrG2k92VISM0op7wiq60vO92MlF3CRGxhKHy9ywG1/Dkc72g0dXeDQ+//hrcDn8gqQzoEkdO9FN0d9AA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", "requires": { - "base64-arraybuffer": "~1.0.1" + "@socket.io/base64-arraybuffer": "~1.0.2" } }, "enhanced-resolve": { @@ -6645,14 +6653,6 @@ "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - } } }, "eslint": { @@ -6742,6 +6742,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -6825,13 +6830,12 @@ } }, "eslint-module-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", - "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "requires": { "debug": "^3.2.7", - "find-up": "^2.1.0", - "pkg-dir": "^2.0.0" + "find-up": "^2.1.0" }, "dependencies": { "debug": { @@ -6879,14 +6883,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "requires": { - "find-up": "^2.1.0" - } } } }, @@ -6899,9 +6895,9 @@ } }, "eslint-plugin-import": { - "version": "2.25.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz", - "integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==", + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", + "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -6909,14 +6905,14 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.0", + "eslint-module-utils": "^2.7.2", "has": "^1.0.3", - "is-core-module": "^2.7.0", + "is-core-module": "^2.8.0", "is-glob": "^4.0.3", "minimatch": "^3.0.4", "object.values": "^1.1.5", "resolve": "^1.20.0", - "tsconfig-paths": "^3.11.0" + "tsconfig-paths": "^3.12.0" }, "dependencies": { "debug": { @@ -6946,22 +6942,23 @@ } }, "eslint-plugin-jsx-a11y": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", - "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", + "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", "dev": true, "requires": { - "@babel/runtime": "^7.11.2", + "@babel/runtime": "^7.16.3", "aria-query": "^4.2.2", - "array-includes": "^3.1.1", + "array-includes": "^3.1.4", "ast-types-flow": "^0.0.7", - "axe-core": "^4.0.2", + "axe-core": "^4.3.5", "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.6", - "emoji-regex": "^9.0.0", + "damerau-levenshtein": "^1.0.7", + "emoji-regex": "^9.2.2", "has": "^1.0.3", - "jsx-ast-utils": "^3.1.0", - "language-tags": "^1.0.5" + "jsx-ast-utils": "^3.2.1", + "language-tags": "^1.0.5", + "minimatch": "^3.0.4" }, "dependencies": { "emoji-regex": { @@ -6983,25 +6980,25 @@ } }, "eslint-plugin-react": { - "version": "7.26.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz", - "integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", "dev": true, "requires": { - "array-includes": "^3.1.3", - "array.prototype.flatmap": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", "doctrine": "^2.1.0", - "estraverse": "^5.2.0", + "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.0.4", - "object.entries": "^1.1.4", - "object.fromentries": "^2.0.4", - "object.hasown": "^1.0.0", - "object.values": "^1.1.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", "prop-types": "^15.7.2", "resolve": "^2.0.0-next.3", "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.5" + "string.prototype.matchall": "^4.0.6" }, "dependencies": { "doctrine": { @@ -7028,6 +7025,12 @@ "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, @@ -7253,16 +7256,16 @@ } }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", "requires": { "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -7276,13 +7279,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -7313,9 +7316,14 @@ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, @@ -7328,9 +7336,9 @@ }, "dependencies": { "type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", + "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" } } }, @@ -7439,7 +7447,7 @@ }, "falafel": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.4.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/falafel/-/falafel-2.2.4.tgz", "integrity": "sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ==", "requires": { "acorn": "^7.1.1", @@ -7450,7 +7458,7 @@ "dependencies": { "isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" } } @@ -7496,7 +7504,7 @@ }, "fast-isnumeric": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-isnumeric/-/fast-isnumeric-1.1.4.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/fast-isnumeric/-/fast-isnumeric-1.1.4.tgz", "integrity": "sha512-1mM8qOr2LYz8zGaUdmiqRDiuue00Dxjgcb1NQR7TnhLVh6sQyngP9xvLo7Sl7LZpP/sk5eb+bcyWXw530NTBZw==", "requires": { "is-string-blank": "^1.0.1" @@ -7547,30 +7555,37 @@ "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", "requires": { "fbjs": "^3.0.0" + }, + "dependencies": { + "fbjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.2.tgz", + "integrity": "sha512-qv+boqYndjElAJHNN3NoM8XuwQZ1j2m3kEvTgdle8IDjr6oUbkEpvABWtj/rQl3vq4ew7dnElBxL4YJAwTVqQQ==", + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + } } }, "fbjs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.1.tgz", - "integrity": "sha512-8+vkGyT4lNDRKHQNPp0yh/6E7FfkLg89XqQbOYnvntRh+8RiSD43yrh9E5ejp1muCizTL4nDVG+y8W4e+LROHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", + "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", "requires": { + "core-js": "^3.6.4", "cross-fetch": "^3.0.4", "fbjs-css-vars": "^1.0.0", "loose-envify": "^1.0.0", "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" - }, - "dependencies": { - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "requires": { - "asap": "~2.0.3" - } - } + "ua-parser-js": "^0.7.18" } }, "fbjs-css-vars": { @@ -7719,7 +7734,7 @@ }, "flatten-vertex-data": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz", "integrity": "sha512-BvCBFK2NZqerFTdMDgqfHBwxYWnxeCkwONsw6PvBMcUXqo8U/KDWwmXhqx1x2kLIg7DqIsJfOaJFOmlua3Lxuw==", "requires": { "dtype": "^2.0.0" @@ -7727,7 +7742,7 @@ }, "flip-pixels": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flip-pixels/-/flip-pixels-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/flip-pixels/-/flip-pixels-1.0.2.tgz", "integrity": "sha512-oXbJGbjDnfJRWPC7Va38EFhd+A8JWE5/hCiKcK8qjCdbLj9DTpsq6MEudwpRTH+V4qq+Jw7d3pUgQdSr3x3mTA==" }, "flush-write-stream": { @@ -7769,22 +7784,38 @@ } }, "flux": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.2.tgz", - "integrity": "sha512-u/ucO5ezm3nBvdaSGkWpDlzCePoV+a9x3KHmy13TV/5MzOaCZDN8Mfd94jmf0nOi8ZZay+nOKbBUkOe2VNaupQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", + "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", "requires": { "fbemitter": "^3.0.0", - "fbjs": "^3.0.0" + "fbjs": "^3.0.1" + }, + "dependencies": { + "fbjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.2.tgz", + "integrity": "sha512-qv+boqYndjElAJHNN3NoM8XuwQZ1j2m3kEvTgdle8IDjr6oUbkEpvABWtj/rQl3vq4ew7dnElBxL4YJAwTVqQQ==", + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + } } }, "follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "font-atlas": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/font-atlas/-/font-atlas-2.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/font-atlas/-/font-atlas-2.1.0.tgz", "integrity": "sha512-kP3AmvX+HJpW4w3d+PiPR2X6E1yvsBXt2yhuCw+yReO9F1WYhvZwx3c95DGZGwg9xYzDGrgJYa885xmVA+28Cg==", "requires": { "css-font": "^1.0.0" @@ -7792,7 +7823,7 @@ }, "font-measure": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/font-measure/-/font-measure-1.2.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/font-measure/-/font-measure-1.2.2.tgz", "integrity": "sha512-mRLEpdrWzKe9hbfaF3Qpr06TAjquuBVP5cHy4b3hyeNdjc9i0PO6HniGsX5vjL5OWv7+Bd++NiooNpT/s8BvIA==", "requires": { "css-font": "^1.2.0" @@ -7813,7 +7844,7 @@ }, "foreach": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/foreach/-/foreach-2.0.5.tgz", "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" }, "forever-agent": { @@ -7834,13 +7865,6 @@ "semver": "^5.6.0", "tapable": "^1.0.0", "worker-rpc": "^0.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } } }, "form-data": { @@ -7854,9 +7878,9 @@ } }, "form-data-encoder": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.0.tgz", - "integrity": "sha512-zGhcpAhxoq7ut+sldaXVwmQHvvrlUHm6jLJoqCMuhf4vjMe+Vn+PAjIB6OrqSFoIk4c3/oK6M69RXJYrYl0zWg==" + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==" }, "format": { "version": "0.2.2", @@ -7864,9 +7888,9 @@ "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=" }, "formdata-node": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.3.1.tgz", - "integrity": "sha512-8xKSa9et4zb+yziWsD/bI+EYjdg1z2p9EpKr+o+Yk12F/wP66bmDdvjj2ZXd2K/MJlR3HBzWnuV7f82jzHRqCA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.3.2.tgz", + "integrity": "sha512-k7lYJyzDOSL6h917favP8j1L0/wNyylzU+x+1w4p5haGVHNlP58dbpdJhiCUsDbWsa9HwEtLp89obQgXl2e0qg==", "requires": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.1" @@ -8014,7 +8038,7 @@ }, "geojson-vt": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/geojson-vt/-/geojson-vt-3.2.1.tgz", "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==" }, "get-caller-file": { @@ -8024,7 +8048,7 @@ }, "get-canvas-context": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-canvas-context/-/get-canvas-context-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/get-canvas-context/-/get-canvas-context-1.0.2.tgz", "integrity": "sha1-1ue1C8TkyGNXzTnyJkeoS3NgHpM=" }, "get-intrinsic": { @@ -8092,17 +8116,17 @@ }, "gl-mat4": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/gl-mat4/-/gl-mat4-1.2.0.tgz", "integrity": "sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA==" }, "gl-matrix": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/gl-matrix/-/gl-matrix-3.4.3.tgz", "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" }, "gl-text": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/gl-text/-/gl-text-1.3.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/gl-text/-/gl-text-1.3.1.tgz", "integrity": "sha512-/f5gcEMiZd+UTBJLTl3D+CkCB/0UFGTx3nflH8ZmyWcLkZhsZ1+Xx5YYkw2rgWAzgPeE35xCqBuHSoMKQVsR+w==", "requires": { "bit-twiddle": "^1.0.2", @@ -8126,7 +8150,7 @@ }, "gl-util": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/gl-util/-/gl-util-3.1.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/gl-util/-/gl-util-3.1.3.tgz", "integrity": "sha512-dvRTggw5MSkJnCbh74jZzSoTOGnVYK+Bt+Ckqm39CVcl6+zSsxqWk4lr5NKhkqXHL6qvZAU9h17ZF8mIskY9mA==", "requires": { "is-browser": "^2.0.1", @@ -8236,7 +8260,7 @@ }, "glsl-inject-defines": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz", "integrity": "sha1-3RqswsF/yyvT/DJBHGYz0Ne2D9Q=", "requires": { "glsl-token-inject-block": "^1.0.0", @@ -8246,7 +8270,7 @@ }, "glsl-resolve": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/glsl-resolve/-/glsl-resolve-0.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-resolve/-/glsl-resolve-0.0.1.tgz", "integrity": "sha1-iUvvc5ENeSyBtRQxgANdCnivdtM=", "requires": { "resolve": "^0.6.1", @@ -8255,24 +8279,24 @@ "dependencies": { "resolve": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/resolve/-/resolve-0.6.3.tgz", "integrity": "sha1-3ZV5gufnNt699TtYpN2RdUV13UY=" }, "xtend": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/xtend/-/xtend-2.2.0.tgz", "integrity": "sha1-7vax8ZjByN6vrYsXZaBNrUoBxak=" } } }, "glsl-token-assignments": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/glsl-token-assignments/-/glsl-token-assignments-2.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-assignments/-/glsl-token-assignments-2.0.2.tgz", "integrity": "sha1-pdgqt4SZwuimuDy2lJXm5mXOAZ8=" }, "glsl-token-defines": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/glsl-token-defines/-/glsl-token-defines-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-defines/-/glsl-token-defines-1.0.0.tgz", "integrity": "sha1-y4kqqVmTYjFyhHDU90AySJaX+p0=", "requires": { "glsl-tokenizer": "^2.0.0" @@ -8280,12 +8304,12 @@ }, "glsl-token-depth": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/glsl-token-depth/-/glsl-token-depth-1.1.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-depth/-/glsl-token-depth-1.1.2.tgz", "integrity": "sha1-I8XjDuK9JViEtKKLyFC495HpXYQ=" }, "glsl-token-descope": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glsl-token-descope/-/glsl-token-descope-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-descope/-/glsl-token-descope-1.0.2.tgz", "integrity": "sha1-D8kKsyYYa4L1l7LnfcniHvzTIHY=", "requires": { "glsl-token-assignments": "^2.0.0", @@ -8296,27 +8320,27 @@ }, "glsl-token-inject-block": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz", "integrity": "sha1-4QFfWYDBCRgkraomJfHf3ovQADQ=" }, "glsl-token-properties": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/glsl-token-properties/-/glsl-token-properties-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-properties/-/glsl-token-properties-1.0.1.tgz", "integrity": "sha1-SD3D2Dnw1LXGFx0VkfJJvlPCip4=" }, "glsl-token-scope": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/glsl-token-scope/-/glsl-token-scope-1.1.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-scope/-/glsl-token-scope-1.1.2.tgz", "integrity": "sha1-oXKOeN8kRE+cuT/RjvD3VQOmQ7E=" }, "glsl-token-string": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/glsl-token-string/-/glsl-token-string-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-string/-/glsl-token-string-1.0.1.tgz", "integrity": "sha1-WUQdL4V958NEnJRWZgIezjWOSOw=" }, "glsl-token-whitespace-trim": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/glsl-token-whitespace-trim/-/glsl-token-whitespace-trim-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glsl-token-whitespace-trim/-/glsl-token-whitespace-trim-1.0.0.tgz", "integrity": "sha1-RtHf6Yx1vX1QTAXX0RsbPpzJOxA=" }, "glsl-tokenizer": { @@ -8329,7 +8353,7 @@ }, "glslify": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glslify/-/glslify-7.1.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glslify/-/glslify-7.1.1.tgz", "integrity": "sha512-bud98CJ6kGZcP9Yxcsi7Iz647wuDz3oN+IZsjCRi5X1PI7t/xPKeL0mOwXJjo+CRZMqvq0CkSJiywCcY7kVYog==", "requires": { "bl": "^2.2.1", @@ -8351,7 +8375,7 @@ "dependencies": { "bl": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/bl/-/bl-2.2.1.tgz", "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", "requires": { "readable-stream": "^2.3.5", @@ -8365,7 +8389,7 @@ }, "readable-stream": { "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", @@ -8379,7 +8403,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -8398,7 +8422,7 @@ }, "glslify-bundle": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glslify-bundle/-/glslify-bundle-5.1.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glslify-bundle/-/glslify-bundle-5.1.1.tgz", "integrity": "sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A==", "requires": { "glsl-inject-defines": "^1.0.1", @@ -8415,7 +8439,7 @@ }, "glslify-deps": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/glslify-deps/-/glslify-deps-1.3.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/glslify-deps/-/glslify-deps-1.3.2.tgz", "integrity": "sha512-7S7IkHWygJRjcawveXQjRXLO2FTjijPDYC7QfZyAQanY+yGLCFHYnPtsGT9bdyHiwPTw/5a1m1M9hamT2aBpag==", "requires": { "@choojs/findup": "^0.2.0", @@ -8434,14 +8458,26 @@ "integrity": "sha512-+lbp8rQ0p1nTa6Gk6HoLiw4yM6JTpql82U+nCF3sZbX4FJWP9PzzF1018dW8K+pbmqRmhLHbn6Bjc6i6tgUpbA==", "optional": true }, + "gpu.js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gpu.js/-/gpu.js-2.3.0.tgz", + "integrity": "sha512-4maf/y6AFb97WspNF0L121GgnwoVC5OIbbLTp0eFMg76jcDr/TuXr93HOLGaGnwTHXjD/e8pRc+olZaFXqkKsg==", + "optional": true, + "requires": { + "acorn": "^7.1.0", + "gl": "^4.4.0", + "gl-wiretap": "^0.6.2", + "gpu-mock.js": "^1.1.1" + } + }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, "grid-index": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/grid-index/-/grid-index-1.1.0.tgz", "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==" }, "growly": { @@ -8550,7 +8586,7 @@ }, "has-hover": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-hover/-/has-hover-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/has-hover/-/has-hover-1.0.1.tgz", "integrity": "sha1-PZdDeusZnGK4rAisvcU9O8UsF/c=", "requires": { "is-browser": "^2.0.1" @@ -8558,7 +8594,7 @@ }, "has-passive-events": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-passive-events/-/has-passive-events-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/has-passive-events/-/has-passive-events-1.0.0.tgz", "integrity": "sha512-2vSj6IeIsgvsRMyeQ0JaCX5Q3lX4zMn5HpoVc7MEhQ6pv8Iq9rsXjsp+E5ZwaT7T0xhMT0KmU8gtt1EFVdbJiw==", "requires": { "is-browser": "^2.0.1" @@ -8781,7 +8817,7 @@ }, "hsluv": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/hsluv/-/hsluv-0.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/hsluv/-/hsluv-0.0.3.tgz", "integrity": "sha1-gpEH2vtKn4tSoYCe0C4JHq3mdUw=" }, "html-encoding-sniffer": { @@ -8899,22 +8935,15 @@ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } + "toidentifier": "1.0.1" } }, "http-proxy": { @@ -8965,20 +8994,6 @@ "regenerator-runtime": "^0.13.3", "tiny-emitter": "^2.1.0", "unorm": "^1.6.0" - }, - "dependencies": { - "gpu.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gpu.js/-/gpu.js-2.3.0.tgz", - "integrity": "sha512-4maf/y6AFb97WspNF0L121GgnwoVC5OIbbLTp0eFMg76jcDr/TuXr93HOLGaGnwTHXjD/e8pRc+olZaFXqkKsg==", - "optional": true, - "requires": { - "acorn": "^7.1.0", - "gl": "^4.4.0", - "gl-wiretap": "^0.6.2", - "gpu-mock.js": "^1.1.1" - } - } } }, "hyphenate-style-name": { @@ -9051,7 +9066,7 @@ }, "image-palette": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/image-palette/-/image-palette-2.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/image-palette/-/image-palette-2.1.0.tgz", "integrity": "sha512-3ImSEWD26+xuQFdP0RWR4WSXadZwvgrFhjGNpMEapTG1tf2XrBFS2dlKK5hNgH4UIaSQlSUFRn1NeA+zULIWbQ==", "requires": { "color-id": "^1.1.0", @@ -9072,9 +9087,9 @@ "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==" }, "immutable": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", - "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" }, "import-cwd": { "version": "2.1.0", @@ -9327,7 +9342,7 @@ }, "is-base64": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-base64/-/is-base64-0.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-base64/-/is-base64-0.1.0.tgz", "integrity": "sha512-WRRyllsGXJM7ZN7gPTCCQ/6wNPTRDwiWdPK66l5sJzcU/oOzcIcRRf0Rux8bkpox/1yjt0F6VJRsQOIG2qz5sg==" }, "is-bigint": { @@ -9348,7 +9363,7 @@ }, "is-blob": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-blob/-/is-blob-2.1.0.tgz", "integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==" }, "is-boolean-object": { @@ -9362,7 +9377,7 @@ }, "is-browser": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-browser/-/is-browser-2.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-browser/-/is-browser-2.1.0.tgz", "integrity": "sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ==" }, "is-buffer": { @@ -9397,9 +9412,9 @@ } }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "requires": { "has": "^1.0.3" } @@ -9473,17 +9488,17 @@ }, "is-finite": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-finite/-/is-finite-1.1.0.tgz", "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" }, "is-firefox": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-firefox/-/is-firefox-1.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-firefox/-/is-firefox-1.0.3.tgz", "integrity": "sha1-KioVZ3g6QX9uFYMjEI84YbCRhWI=" }, "is-float-array": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-float-array/-/is-float-array-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-float-array/-/is-float-array-1.0.0.tgz", "integrity": "sha512-4ew1Sx6B6kEAl3T3NOM0yB94J3NZnBdNt4paw0e8nY73yHHTeTEhyQ3Lj7EQEnv5LD+GxNTaT4L46jcKjjpLiQ==" }, "is-fullwidth-code-point": { @@ -9515,23 +9530,23 @@ }, "is-iexplorer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-iexplorer/-/is-iexplorer-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-iexplorer/-/is-iexplorer-1.0.0.tgz", "integrity": "sha1-HXK8ZtP+Iur2Fw3ajPEJQySM/HY=" }, "is-in-browser": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-in-browser/-/is-in-browser-1.1.3.tgz", "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" }, "is-mobile": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-2.2.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-mobile/-/is-mobile-2.2.2.tgz", "integrity": "sha512-wW/SXnYJkTjs++tVK5b6kVITZpAZPtUrt9SF80vvxGiF/Oywal+COk1jlRkiVq15RFNEQKQY31TkV24/1T5cVg==" }, "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" }, "is-number": { "version": "3.0.0", @@ -9642,12 +9657,12 @@ }, "is-string-blank": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-string-blank/-/is-string-blank-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-string-blank/-/is-string-blank-1.0.1.tgz", "integrity": "sha512-9H+ZBCVs3L9OYqv8nuUAzpcT9OTgMD1yAWrG7ihlnibdkbtB850heAmYWxHuXc4CHy4lKeK69tN+ny1K7gBIrw==" }, "is-svg-path": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-svg-path/-/is-svg-path-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/is-svg-path/-/is-svg-path-1.0.2.tgz", "integrity": "sha1-d6tZDBKz0gNI5cehPQBAyHeE3aA=" }, "is-symbol": { @@ -9664,11 +9679,11 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "requires": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2" } }, "is-what": { @@ -9729,6 +9744,13 @@ "@babel/types": "^7.4.0", "istanbul-lib-coverage": "^2.0.5", "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } } }, "istanbul-lib-report": { @@ -9770,11 +9792,6 @@ "requires": { "glob": "^7.1.3" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -9951,6 +9968,19 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==" }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, "whatwg-url": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", @@ -10205,6 +10235,11 @@ "requires": { "minimist": "^1.2.5" } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -10239,11 +10274,6 @@ "requires": { "minimist": "^1.2.5" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -10404,6 +10434,29 @@ "version": "5.7.4", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } } } }, @@ -10423,9 +10476,9 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, "json-schema-traverse": { "version": "0.4.1", @@ -10477,20 +10530,20 @@ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, "jss": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz", - "integrity": "sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.9.0.tgz", + "integrity": "sha512-YpzpreB6kUunQBbrlArlsMpXYyndt9JATbt95tajx0t4MTJJcCJdd4hdNpHmOIDiUJrF/oX5wtVFrS3uofWfGw==", "requires": { "@babel/runtime": "^7.3.1", "csstype": "^3.0.2", @@ -10499,77 +10552,77 @@ }, "dependencies": { "csstype": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" } } }, "jss-plugin-camel-case": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz", - "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.9.0.tgz", + "integrity": "sha512-UH6uPpnDk413/r/2Olmw4+y54yEF2lRIV8XIZyuYpgPYTITLlPOsq6XB9qeqv+75SQSg3KLocq5jUBXW8qWWww==", "requires": { "@babel/runtime": "^7.3.1", "hyphenate-style-name": "^1.0.3", - "jss": "10.8.2" + "jss": "10.9.0" } }, "jss-plugin-default-unit": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz", - "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.9.0.tgz", + "integrity": "sha512-7Ju4Q9wJ/MZPsxfu4T84mzdn7pLHWeqoGd/D8O3eDNNJ93Xc8PxnLmV8s8ZPNRYkLdxZqKtm1nPQ0BM4JRlq2w==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.8.2" + "jss": "10.9.0" } }, "jss-plugin-global": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz", - "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.9.0.tgz", + "integrity": "sha512-4G8PHNJ0x6nwAFsEzcuVDiBlyMsj2y3VjmFAx/uHk/R/gzJV+yRHICjT4MKGGu1cJq2hfowFWCyrr/Gg37FbgQ==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.8.2" + "jss": "10.9.0" } }, "jss-plugin-nested": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz", - "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.9.0.tgz", + "integrity": "sha512-2UJnDrfCZpMYcpPYR16oZB7VAC6b/1QLsRiAutOt7wJaaqwCBvNsosLEu/fUyKNQNGdvg2PPJFDO5AX7dwxtoA==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.8.2", + "jss": "10.9.0", "tiny-warning": "^1.0.2" } }, "jss-plugin-props-sort": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz", - "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.9.0.tgz", + "integrity": "sha512-7A76HI8bzwqrsMOJTWKx/uD5v+U8piLnp5bvru7g/3ZEQOu1+PjHvv7bFdNO3DwNPC9oM0a//KwIJsIcDCjDzw==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.8.2" + "jss": "10.9.0" } }, "jss-plugin-rule-value-function": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz", - "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.9.0.tgz", + "integrity": "sha512-IHJv6YrEf8pRzkY207cPmdbBstBaE+z8pazhPShfz0tZSDtRdQua5jjg6NMz3IbTasVx9FdnmptxPqSWL5tyJg==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "10.8.2", + "jss": "10.9.0", "tiny-warning": "^1.0.2" } }, "jss-plugin-vendor-prefixer": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz", - "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.9.0.tgz", + "integrity": "sha512-MbvsaXP7iiVdYVSEoi+blrW+AYnTDvHTW6I6zqi7JcwXdc6I9Kbm234nEblayhF38EftoenbM+5218pidmC5gA==", "requires": { "@babel/runtime": "^7.3.1", "css-vendor": "^2.0.8", - "jss": "10.8.2" + "jss": "10.9.0" } }, "jsx-ast-utils": { @@ -10588,7 +10641,7 @@ }, "kdbush": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/kdbush/-/kdbush-3.0.0.tgz", "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==" }, "killable": { @@ -10673,13 +10726,6 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "optional": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true } } }, @@ -10725,9 +10771,9 @@ } }, "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "load-json-file": { "version": "4.0.0", @@ -10880,7 +10926,7 @@ }, "lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "lodash.sortby": { @@ -10911,9 +10957,9 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", + "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==" }, "loose-envify": { "version": "1.4.0", @@ -10976,11 +11022,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, @@ -11004,7 +11045,7 @@ }, "map-limit": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/map-limit/-/map-limit-0.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/map-limit/-/map-limit-0.0.1.tgz", "integrity": "sha1-63lhAxwPDo0AG/LVb6toXViCLzg=", "requires": { "once": "~1.3.0" @@ -11012,7 +11053,7 @@ "dependencies": { "once": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/once/-/once-1.3.3.tgz", "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "requires": { "wrappy": "1" @@ -11030,7 +11071,7 @@ }, "mapbox-gl": { "version": "1.10.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.10.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/mapbox-gl/-/mapbox-gl-1.10.1.tgz", "integrity": "sha512-0aHt+lFUpYfvh0kMIqXqNXqoYMuhuAsMlw87TbhWrw78Tx2zfuPI0Lx31/YPUgJ+Ire0tzQ4JnuBL7acDNXmMg==", "requires": { "@mapbox/geojson-rewind": "^0.5.0", @@ -11058,9 +11099,14 @@ "vt-pbf": "^3.1.1" } }, + "material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + }, "math-log2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-log2/-/math-log2-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/math-log2/-/math-log2-1.0.1.tgz", "integrity": "sha1-+4lBvl9evol55xjmJzsXjlhpRWU=" }, "md5.js": { @@ -11232,16 +11278,16 @@ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" }, "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" }, "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", "requires": { - "mime-db": "1.50.0" + "mime-db": "1.51.0" } }, "mimic-fn": { @@ -11303,9 +11349,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "requires": { "brace-expansion": "^1.1.7" } @@ -11316,9 +11362,9 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minipass": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", - "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "requires": { "yallist": "^4.0.0" } @@ -11466,7 +11512,7 @@ }, "mouse-change": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mouse-change/-/mouse-change-1.4.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/mouse-change/-/mouse-change-1.4.0.tgz", "integrity": "sha1-wrd+W/o0pDzhRFyBV6Tk3JiVwU8=", "requires": { "mouse-event": "^1.0.0" @@ -11474,17 +11520,17 @@ }, "mouse-event": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/mouse-event/-/mouse-event-1.0.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/mouse-event/-/mouse-event-1.0.5.tgz", "integrity": "sha1-s3ie23EJmX1aky0dAdqhVDpQFzI=" }, "mouse-event-offset": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mouse-event-offset/-/mouse-event-offset-3.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/mouse-event-offset/-/mouse-event-offset-3.0.2.tgz", "integrity": "sha1-39hqbiSMa6jK1TuQXVA3ogY+mYQ=" }, "mouse-wheel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mouse-wheel/-/mouse-wheel-1.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/mouse-wheel/-/mouse-wheel-1.2.0.tgz", "integrity": "sha1-bSkDseqPtI5h8bU7kDZ3PwQs21w=", "requires": { "right-now": "^1.0.0", @@ -11544,7 +11590,7 @@ }, "mumath": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/mumath/-/mumath-3.3.4.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/mumath/-/mumath-3.3.4.tgz", "integrity": "sha1-SNSg8P2MrU57Mglu6JsWGmPTC78=", "requires": { "almost-equal": "^1.1.0" @@ -11552,7 +11598,7 @@ }, "murmurhash-js": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/murmurhash-js/-/murmurhash-js-1.0.0.tgz", "integrity": "sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=" }, "mute-stream": { @@ -11599,7 +11645,7 @@ }, "native-promise-only": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/native-promise-only/-/native-promise-only-0.8.1.tgz", "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=" }, "native-request": { @@ -11616,7 +11662,7 @@ }, "needle": { "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/needle/-/needle-2.9.1.tgz", "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", "requires": { "debug": "^3.2.6", @@ -11626,7 +11672,7 @@ "dependencies": { "debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { "ms": "^2.1.1" @@ -11635,9 +11681,9 @@ } }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "neo-async": { "version": "2.6.2", @@ -11677,14 +11723,6 @@ "optional": true, "requires": { "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "optional": true - } } }, "node-domexception": { @@ -11693,9 +11731,12 @@ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } }, "node-forge": { "version": "0.10.0", @@ -11827,11 +11868,6 @@ } } }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" - }, "node-notifier": { "version": "5.4.5", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", @@ -11844,11 +11880,6 @@ "which": "^1.3.0" }, "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -11860,9 +11891,9 @@ } }, "node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" }, "noop-logger": { "version": "0.1.1", @@ -11888,13 +11919,6 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } } }, "normalize-path": { @@ -11912,7 +11936,7 @@ }, "normalize-svg-path": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-0.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/normalize-svg-path/-/normalize-svg-path-0.1.0.tgz", "integrity": "sha1-RWNg5g7Odfvve11+FgSA5//Rb+U=" }, "normalize-url": { @@ -11970,7 +11994,7 @@ }, "number-is-integer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-integer/-/number-is-integer-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/number-is-integer/-/number-is-integer-1.0.1.tgz", "integrity": "sha1-5ZvKFy/+0nMY55x862y3LAlbIVI=", "requires": { "is-finite": "^1.0.1" @@ -12031,9 +12055,9 @@ "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" }, "object-is": { "version": "1.1.5", @@ -12358,9 +12382,9 @@ } }, "parenthesis": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.7.tgz", - "integrity": "sha512-iMtu+HCbLXVrpf6Ys/4YKhcFxbux3xK4ZVB9r+a2kMSqeeQWQoDNYlXIsOjwlT2ldYXZ3k5PVeBnYn7fbAo/Bg==" + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.8.tgz", + "integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==" }, "parse-asn1": { "version": "5.1.6", @@ -12398,7 +12422,7 @@ }, "parse-rect": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parse-rect/-/parse-rect-1.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/parse-rect/-/parse-rect-1.2.0.tgz", "integrity": "sha512-4QZ6KYbnE6RTwg9E0HpLchUM9EZt6DnDxajFZZDSV4p/12ZJEvPO702DZpGvRYEPo00yKDys7jASi+/w7aO8LA==", "requires": { "pick-by-alias": "^1.2.0" @@ -12406,12 +12430,12 @@ }, "parse-svg-path": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/parse-svg-path/-/parse-svg-path-0.1.2.tgz", "integrity": "sha1-en7A0esG+lMlx9PgCbhZoJtdSes=" }, "parse-unit": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/parse-unit/-/parse-unit-1.0.1.tgz", "integrity": "sha1-fhu21b7zh0wo45JSaiVBFwKR7s8=" }, "parse5": { @@ -12508,7 +12532,7 @@ }, "pbf": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/pbf/-/pbf-3.2.1.tgz", "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", "requires": { "ieee754": "^1.1.12", @@ -12534,7 +12558,7 @@ }, "pick-by-alias": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pick-by-alias/-/pick-by-alias-1.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/pick-by-alias/-/pick-by-alias-1.2.0.tgz", "integrity": "sha1-X3yysfIabh6ISgyHhVqko3NhEHs=" }, "picocolors": { @@ -12543,9 +12567,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pify": { "version": "3.0.0", @@ -12571,12 +12595,9 @@ } }, "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "requires": { - "node-modules-regexp": "^1.0.0" - } + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==" }, "pkg-dir": { "version": "3.0.0", @@ -12595,9 +12616,9 @@ } }, "plotly.js": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-2.6.2.tgz", - "integrity": "sha512-KzOwyNNdRnJVvZPnBvA2VwgcO9202FexFpiivuWaAFvmQiX+oC3yKrQHyXaPeNqZn4lAq3GVgYYPQdx3o5uEuw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-2.9.0.tgz", + "integrity": "sha512-A3kqjGq2PCeL/z19BNvg5YD712mWCMaRW2WbmYA+qpdbNPUjBNjMK/MWXDi7pV53CUM2ZKAqre4j6Uy7bIoAGA==", "requires": { "@plotly/d3": "3.8.0", "@plotly/d3-sankey": "0.7.2", @@ -12633,7 +12654,7 @@ "native-promise-only": "^0.8.1", "parse-svg-path": "^0.1.2", "polybooljs": "^1.2.0", - "probe-image-size": "^7.2.1", + "probe-image-size": "^7.2.3", "regl": "^2.1.0", "regl-error2d": "^2.0.12", "regl-line2d": "^3.1.2", @@ -12664,7 +12685,7 @@ }, "polybooljs": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/polybooljs/-/polybooljs-1.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/polybooljs/-/polybooljs-1.2.0.tgz", "integrity": "sha1-tDkMLgedTCYtOyUExiiNlbp6R1g=" }, "popper.js": { @@ -12718,11 +12739,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -13573,9 +13589,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -13609,9 +13625,9 @@ } }, "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "postcss-values-parser": { "version": "2.0.1", @@ -13625,7 +13641,7 @@ }, "potpack": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/potpack/-/potpack-1.0.2.tgz", "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" }, "prebuild-install": { @@ -13662,9 +13678,9 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, "prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "dev": true }, "pretty-bytes": { @@ -13693,14 +13709,14 @@ } }, "prismjs": { - "version": "1.25.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz", - "integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==" + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.26.0.tgz", + "integrity": "sha512-HUoH9C5Z3jKkl3UunCyiD5jwk0+Hz0fIgQ2nbwU2Oo/ceuTAQAg+pPVnfdt2TJWRVLcxKh9iuoYDUSc8clb5UQ==" }, "probe-image-size": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.1.tgz", - "integrity": "sha512-d+6L3NvQBCNt4peRDoEfA7r9bPm6/qy18FnLKwg4NWBC5JrJm0pMLRg1kF4XNsPe1bUdt3WIMonPJzQWN2HXjQ==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz", + "integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==", "requires": { "lodash.merge": "^4.6.2", "needle": "^2.5.2", @@ -13723,11 +13739,11 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, "promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { - "asap": "~2.0.6" + "asap": "~2.0.3" } }, "promise-inflight": { @@ -13745,13 +13761,13 @@ } }, "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "property-information": { @@ -13764,7 +13780,7 @@ }, "protocol-buffers-schema": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" }, "proxy-addr": { @@ -13848,7 +13864,7 @@ }, "pxls": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/pxls/-/pxls-2.3.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/pxls/-/pxls-2.3.2.tgz", "integrity": "sha512-pQkwgbLqWPcuES5iEmGa10OlCf5xG0blkIF3dg7PpRZShbTYcvAdfFfGL03SMrkaSUaa/V0UpN9HWg40O2AIIw==", "requires": { "arr-flatten": "^1.1.0", @@ -13865,13 +13881,13 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" }, "quantize": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/quantize/-/quantize-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/quantize/-/quantize-1.0.2.tgz", "integrity": "sha1-0lrCAKd7bXD0ASfKFxoQ4zyFRt4=" }, "query-string": { @@ -13900,7 +13916,7 @@ }, "quickselect": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/quickselect/-/quickselect-2.0.0.tgz", "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" }, "raf": { @@ -13939,20 +13955,20 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.1", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" } } }, @@ -14001,6 +14017,16 @@ "raf": "^3.4.1", "regenerator-runtime": "^0.13.3", "whatwg-fetch": "^3.0.0" + }, + "dependencies": { + "promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "requires": { + "asap": "~2.0.6" + } + } } }, "react-base16-styling": { @@ -14028,10 +14054,24 @@ "use-memo-one": "^1.1.1" } }, + "react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "requires": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + } + }, "react-content-loader": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-6.0.3.tgz", - "integrity": "sha512-CIRgTHze+ls+jGDIfCitw27YkW2XcaMpsYORTUdBxsMFiKuUYMnlvY76dZE4Lsaa9vFXVw+41ieBEK7SJt0nug==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-6.1.0.tgz", + "integrity": "sha512-S4/+doQrNs0PGDgUYCGGfdFjGax8dMQzYkWcSSxfaUcUjFkbnikWARuX9lWkglocIVhxnn3lxNb6uEWFFUzNUw==" }, "react-copy-to-clipboard": { "version": "5.0.3", @@ -14042,10 +14082,15 @@ "prop-types": "^15.5.8" } }, + "react-d3-graph": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-d3-graph/-/react-d3-graph-2.6.0.tgz", + "integrity": "sha512-U72didZuPuYEqAi1n2bJvnph+9MviIw2x9I0eoxb1IKk3cyEwsJV96n3RL72z/7HDsa1FOvDKuOJE7ujSNZB/Q==" + }, "react-d3-tree": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/react-d3-tree/-/react-d3-tree-3.1.1.tgz", - "integrity": "sha512-PSy1UZG8CQ/fhqtk8ZGigBT/D2NQkS0vTYis/0ZNZxxIqtf0SAEu0VFdT8tvEXsmnuK9+6iAeSRchbqj59WvWg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/react-d3-tree/-/react-d3-tree-3.2.1.tgz", + "integrity": "sha512-nS1enKAdmlxE8uzHgM1sOOsmPSsvU0OJiJ36z5QxU2YuqHY7iUmjIMdo1nzW0TMmd9FdK2vaC7EFswDoYUNhqw==", "requires": { "@bkrem/react-transition-group": "^1.3.1", "@types/d3-hierarchy": "^1.1.8", @@ -14297,7 +14342,7 @@ }, "react-dnd": { "version": "10.0.2", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-10.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/react-dnd/-/react-dnd-10.0.2.tgz", "integrity": "sha512-SC2Ymvntynhoqtf5zaFhZscm9xenCoMofilxPdlwUlaelAzmbl9fw82C4ZJ//+lNm3kWAKXjGDZg2/aWjKEAtg==", "requires": { "@react-dnd/shallowequal": "^2.0.0", @@ -14308,7 +14353,7 @@ }, "react-dnd-html5-backend": { "version": "10.0.2", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-10.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/react-dnd-html5-backend/-/react-dnd-html5-backend-10.0.2.tgz", "integrity": "sha512-ny17gUdInZ6PIGXdzfwPhoztRdNVVvjoJMdG80hkDBamJBeUPuNF2Wv4D3uoQJLjXssX1+i9PhBqc7EpogClwQ==", "requires": { "dnd-core": "^10.0.2" @@ -14326,9 +14371,9 @@ } }, "react-error-overlay": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", - "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", + "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" }, "react-hook-form": { "version": "6.15.8", @@ -14336,11 +14381,12 @@ "integrity": "sha512-prq82ofMbnRyj5wqDe8hsTRcdR25jQ+B8KtCS7BLCzjFHAwNuCjRwzPuP4eYLsEBjEIeYd6try+pdLdw0kPkpg==" }, "react-i18next": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.13.0.tgz", - "integrity": "sha512-AY8ydSqx8LVm1Tn5yXFA0JwCeSWpcFOSr96HrjUXXVAWWbptamZOY2iMxVaGNlGxSLnRY0U2sdCIPVYHcmhBxQ==", + "version": "11.15.4", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.15.4.tgz", + "integrity": "sha512-jKJNAcVcbPGK+yrTcXhLblgPY16n6NbpZZL3Mk8nswj1v3ayIiUBVDU09SgqnT+DluyQBS97hwSvPU5yVFG0yg==", "requires": { "@babel/runtime": "^7.14.5", + "html-escaper": "^2.0.2", "html-parse-stringify": "^3.0.1" } }, @@ -14407,7 +14453,7 @@ }, "react-plotly.js": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/react-plotly.js/-/react-plotly.js-2.5.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/react-plotly.js/-/react-plotly.js-2.5.1.tgz", "integrity": "sha512-Oya14whSHvPsYXdI0nHOGs1pZhMzV2edV7HAW1xFHD58Y73m/LbG2Encvyz1tztL0vfjph0JNhiwO8cGBJnlhg==", "requires": { "prop-types": "^15.7.2" @@ -14529,36 +14575,6 @@ "workbox-webpack-plugin": "4.3.1" }, "dependencies": { - "@babel/core": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", - "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.0", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.0", - "@babel/parser": "^7.9.0", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, "aria-query": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", @@ -14568,6 +14584,14 @@ "commander": "^2.11.0" } }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "doctrine": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", @@ -14604,16 +14628,6 @@ "object.values": "^1.1.0", "read-pkg-up": "^2.0.0", "resolve": "^1.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } } }, "eslint-plugin-jsx-a11y": { @@ -14660,12 +14674,13 @@ } }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } } } @@ -14776,18 +14791,23 @@ "requires": { "path-parse": "^1.0.6" } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "react-syntax-highlighter": { - "version": "15.4.4", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.4.tgz", - "integrity": "sha512-PsOFHNTzkb3OroXdoR897eKN5EZ6grht1iM+f1lJSq7/L0YVnkJaNVwC3wEUYPOAmeyl5xyer1DjL6MrumO6Zw==", + "version": "15.4.5", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.5.tgz", + "integrity": "sha512-RC90KQTxZ/b7+9iE6s9nmiFLFjWswUcfULi4GwVzdFVKVMQySkJWBuOmJFfjwjMVCo0IUUuJrWebNKyviKpwLQ==", "requires": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "lowlight": "^1.17.0", - "prismjs": "^1.22.0", + "prismjs": "^1.25.0", "refractor": "^3.2.0" } }, @@ -14813,12 +14833,12 @@ } }, "react-tsparticles": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/react-tsparticles/-/react-tsparticles-1.39.0.tgz", - "integrity": "sha512-PkLYNVJsRv7zIG9dhZnGGk5g6nHVMMx7c524L4Hu1+IftlX1lBsHJa3SJctGM+wzEmDn0oUGv3xyFoe2QkK+3w==", + "version": "1.40.2", + "resolved": "https://registry.npmjs.org/react-tsparticles/-/react-tsparticles-1.40.2.tgz", + "integrity": "sha512-Gak/vUvn3gh/fxVbQAdptQJ1FU8eY4PXzw1uVqtKBse2LJxJTOnrThW8foPUZP48/y5DeNbJoIqfMXwG4quBmg==", "requires": { "fast-deep-equal": "^3.1.3", - "tsparticles": "^1.39.0" + "tsparticles": "^1.40.2" } }, "react-virtualized-auto-sizer": { @@ -14835,6 +14855,14 @@ "memoize-one": ">=3.1.1 <6" } }, + "reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "requires": { + "lodash": "^4.0.1" + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -14887,6 +14915,16 @@ "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", "requires": { "minimatch": "3.0.4" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "redent": { @@ -14917,6 +14955,13 @@ "integrity": "sha1-yvvWhuBxEmERm5wolgk13EeknQo=", "requires": { "immutable": "^3.8.1" + }, + "dependencies": { + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + } } }, "redux-logger": { @@ -14936,9 +14981,9 @@ } }, "redux-thunk": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.0.tgz", - "integrity": "sha512-/y6ZKQNU/0u8Bm7ROLq9Pt/7lU93cT0IucYMrubo89ENjxPa7i8pqLKu6V4X7/TvYovQ6x01unTeyeZ9lgXiTA==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==" }, "refractor": { "version": "3.5.0", @@ -14948,6 +14993,13 @@ "hastscript": "^6.0.0", "parse-entities": "^2.0.0", "prismjs": "~1.25.0" + }, + "dependencies": { + "prismjs": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz", + "integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==" + } } }, "regenerate": { @@ -14956,9 +15008,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "requires": { "regenerate": "^1.4.2" } @@ -14992,7 +15044,7 @@ }, "regex-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regex-regex/-/regex-regex-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/regex-regex/-/regex-regex-1.0.0.tgz", "integrity": "sha1-kEih6uuHD01IDavHb8Qs3MC8OnI=" }, "regexp-to-ast": { @@ -15002,9 +15054,9 @@ "optional": true }, "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", + "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -15016,27 +15068,27 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" }, "regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" }, "regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "requires": { "jsesc": "~0.5.0" }, @@ -15050,12 +15102,12 @@ }, "regl": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/regl/-/regl-2.1.0.tgz", "integrity": "sha512-oWUce/aVoEvW5l2V0LK7O5KJMzUSKeiOwFuJehzpSFd43dO5spP9r+sSUfhKtsky4u6MCqWJaRL+abzExynfTg==" }, "regl-error2d": { "version": "2.0.12", - "resolved": "https://registry.npmjs.org/regl-error2d/-/regl-error2d-2.0.12.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/regl-error2d/-/regl-error2d-2.0.12.tgz", "integrity": "sha512-r7BUprZoPO9AbyqM5qlJesrSRkl+hZnVKWKsVp7YhOl/3RIpi4UDGASGJY0puQ96u5fBYw/OlqV24IGcgJ0McA==", "requires": { "array-bounds": "^1.0.1", @@ -15069,7 +15121,7 @@ }, "regl-line2d": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/regl-line2d/-/regl-line2d-3.1.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/regl-line2d/-/regl-line2d-3.1.2.tgz", "integrity": "sha512-nmT7WWS/WxmXAQMkgaMKWXaVmwJ65KCrjbqHGOUjjqQi6shfT96YbBOvelXwO9hG7/hjvbzjtQ2UO0L3e7YaXQ==", "requires": { "array-bounds": "^1.0.1", @@ -15088,7 +15140,7 @@ }, "regl-scatter2d": { "version": "3.2.8", - "resolved": "https://registry.npmjs.org/regl-scatter2d/-/regl-scatter2d-3.2.8.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/regl-scatter2d/-/regl-scatter2d-3.2.8.tgz", "integrity": "sha512-bqrqJyeHkGBa9mEfuBnRd7FUtdtZ1l+gsM2C5Ugr1U3vJG5K3mdWdVWtOAllZ5FHHyWJV/vgjVvftgFUg6CDig==", "requires": { "@plotly/point-cluster": "^3.1.9", @@ -15111,7 +15163,7 @@ }, "regl-splom": { "version": "1.0.14", - "resolved": "https://registry.npmjs.org/regl-splom/-/regl-splom-1.0.14.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/regl-splom/-/regl-splom-1.0.14.tgz", "integrity": "sha512-OiLqjmPRYbd7kDlHC6/zDf6L8lxgDC65BhC8JirhP4ykrK4x22ZyS+BnY8EUinXKDeMgmpRwCvUmk7BK4Nweuw==", "requires": { "array-bounds": "^1.0.1", @@ -15156,15 +15208,15 @@ }, "dependencies": { "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", "requires": { "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" } }, "css-what": { @@ -15285,17 +15337,18 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "reselect": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.2.tgz", - "integrity": "sha512-wg60ebcPOtxcptIUfrr7Jt3h4BR86cCW3R7y4qt65lnNb4yz4QgrXcbSioVsIOYguyz42+XTHIyJ5TEruzkFgQ==" + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz", + "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-cwd": { @@ -15318,7 +15371,7 @@ }, "resolve-protobuf-schema": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", "requires": { "protocol-buffers-schema": "^3.3.1" @@ -15387,11 +15440,6 @@ "supports-color": "^6.1.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -15454,7 +15502,7 @@ }, "right-now": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/right-now/-/right-now-1.0.0.tgz", "integrity": "sha1-bolgne69fc2vja7Mmuo5z1haCRg=" }, "rimraf": { @@ -15495,7 +15543,7 @@ }, "rw": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/rw/-/rw-1.3.3.tgz", "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" }, "rxjs": { @@ -15572,6 +15620,11 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -15620,22 +15673,22 @@ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" }, "selfsigned": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", - "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz", + "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==", "requires": { "node-forge": "^0.10.0" } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -15644,9 +15697,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -15673,9 +15726,9 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" } } }, @@ -15753,14 +15806,14 @@ } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" } }, "set-blocking": { @@ -15795,9 +15848,9 @@ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "sha.js": { "version": "2.4.11", @@ -15841,7 +15894,7 @@ }, "shallow-copy": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/shallow-copy/-/shallow-copy-0.0.1.tgz", "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" }, "shebang-command": { @@ -15878,13 +15931,13 @@ } }, "signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "signum": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/signum/-/signum-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/signum/-/signum-1.0.0.tgz", "integrity": "sha1-dKfSvyogtA66FqkrFSEk8dVZ+nc=" }, "simple-concat": { @@ -15894,9 +15947,9 @@ "optional": true }, "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "optional": true, "requires": { "decompress-response": "^4.2.0", @@ -15989,6 +16042,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -16052,32 +16110,32 @@ } }, "socket.io": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.3.2.tgz", - "integrity": "sha512-6S5tV4jcY6dbZ/lLzD6EkvNWI3s81JO6ABP/EpvOlK1NPOcIj3AS4khi6xXw6JlZCASq82HQV4SapfmVMMl2dg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.4.1.tgz", + "integrity": "sha512-s04vrBswdQBUmuWJuuNTmXUVJhP0cVky8bBDhdkf8y0Ptsu7fKU2LuLbts9g+pdmAdyMMn8F/9Mf1/wbtUN0fg==", "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.0.0", - "socket.io-adapter": "~2.3.2", + "engine.io": "~6.1.0", + "socket.io-adapter": "~2.3.3", "socket.io-parser": "~4.0.4" } }, "socket.io-adapter": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.2.tgz", - "integrity": "sha512-PBZpxUPYjmoogY0aoaTmo1643JelsaS1CiAwNjRVdrI0X9Seuc19Y2Wife8k88avW6haG8cznvwbubAZwH4Mtg==" + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", + "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" }, "socket.io-client": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.3.2.tgz", - "integrity": "sha512-2B9LqSunN60yV8F7S84CCEEcgbYNfrn7ejIInZtLZ7ppWtiX8rGZAjvdCvbnC8bqo/9RlCNOUsORLyskxSFP1g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", + "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", "requires": { "@socket.io/component-emitter": "~3.0.0", "backo2": "~1.0.2", "debug": "~4.3.2", - "engine.io-client": "~6.0.1", + "engine.io-client": "~6.1.1", "parseuri": "0.0.6", "socket.io-parser": "~4.1.1" }, @@ -16165,9 +16223,9 @@ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-resolve": { "version": "0.5.3", @@ -16182,19 +16240,12 @@ } }, "source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "source-map-url": { @@ -16231,9 +16282,9 @@ } }, "spdx-license-ids": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==" + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==" }, "spdy": { "version": "4.0.2", @@ -16299,9 +16350,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -16330,7 +16381,7 @@ }, "stack-trace": { "version": "0.0.9", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/stack-trace/-/stack-trace-0.0.9.tgz", "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=" }, "stack-utils": { @@ -16350,7 +16401,7 @@ }, "static-eval": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/static-eval/-/static-eval-2.1.0.tgz", "integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==", "requires": { "escodegen": "^1.11.1" @@ -16483,7 +16534,7 @@ }, "stream-parser": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/stream-parser/-/stream-parser-0.3.1.tgz", "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", "requires": { "debug": "2" @@ -16491,7 +16542,7 @@ "dependencies": { "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" @@ -16499,7 +16550,7 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } @@ -16540,7 +16591,7 @@ }, "string-split-by": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/string-split-by/-/string-split-by-1.0.0.tgz", "integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==", "requires": { "parenthesis": "^3.1.5" @@ -16548,7 +16599,7 @@ }, "string-to-arraybuffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-to-arraybuffer/-/string-to-arraybuffer-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/string-to-arraybuffer/-/string-to-arraybuffer-1.0.2.tgz", "integrity": "sha512-DaGZidzi93dwjQen5I2osxR9ERS/R7B1PFyufNMnzhj+fmlDQAc1DSDIJVJhgI8Oq221efIMbABUBdPHDRt43Q==", "requires": { "atob-lite": "^2.0.0", @@ -16664,7 +16715,7 @@ }, "strongly-connected-components": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strongly-connected-components/-/strongly-connected-components-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/strongly-connected-components/-/strongly-connected-components-1.0.1.tgz", "integrity": "sha1-CSDitN9nyOrulsa2I0/inoc9upk=" }, "style-loader": { @@ -16712,7 +16763,7 @@ }, "supercluster": { "version": "7.1.4", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.4.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/supercluster/-/supercluster-7.1.4.tgz", "integrity": "sha512-GhKkRM1jMR6WUwGPw05fs66pOFWhf59lXq+Q3J3SxPvhNcmgOtLRV6aVQPMRsmXdpaeFJGivt+t7QXUPL3ff4g==", "requires": { "kdbush": "^3.0.0" @@ -16720,7 +16771,7 @@ }, "superscript-text": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/superscript-text/-/superscript-text-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/superscript-text/-/superscript-text-1.0.0.tgz", "integrity": "sha1-58snUlZzYN9QvrBhDOjfPXHY39g=" }, "supports-color": { @@ -16731,9 +16782,14 @@ "has-flag": "^3.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, "svg-arc-to-cubic-bezier": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", "integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==" }, "svg-parser": { @@ -16743,7 +16799,7 @@ }, "svg-path-bounds": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/svg-path-bounds/-/svg-path-bounds-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/svg-path-bounds/-/svg-path-bounds-1.0.2.tgz", "integrity": "sha512-H4/uAgLWrppIC0kHsb2/dWUYSmb4GE5UqH06uqWBcg6LBjX2fu0A8+JrO2/FJPZiSsNOKZAhyFFgsLTdYUvSqQ==", "requires": { "abs-svg-path": "^0.1.1", @@ -16754,7 +16810,7 @@ "dependencies": { "normalize-svg-path": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz", "integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==", "requires": { "svg-arc-to-cubic-bezier": "^3.0.0" @@ -16764,7 +16820,7 @@ }, "svg-path-sdf": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/svg-path-sdf/-/svg-path-sdf-1.1.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/svg-path-sdf/-/svg-path-sdf-1.1.3.tgz", "integrity": "sha512-vJJjVq/R5lSr2KLfVXVAStktfcfa1pNFjFOgyJnzZFXlO/fDZ5DmM8FpnSKKzLPfEYTVeXuVBTHF296TpxuJVg==", "requires": { "bitmap-sdf": "^1.0.0", @@ -16805,21 +16861,22 @@ } }, "swagger-client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.17.0.tgz", - "integrity": "sha512-d8DOEME49wTXm+uT+lBAjJ5D6IDjEHdbkqa7MbcslR2c+oHIhi13ObwleVWGfr89MPkWgBl6RBq9VUHmrBJRbg==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.18.4.tgz", + "integrity": "sha512-Wj26oEctONq/u0uM+eSj18675YM5e2vFnx7Kr4neLeXEHKUsfceVQ/OdtrBXdrT3VbtdBbZfMTfl1JOBpix2MA==", "requires": { "@babel/runtime-corejs3": "^7.11.2", "btoa": "^1.2.1", "cookie": "~0.4.1", - "cross-fetch": "^3.1.4", - "deep-extend": "~0.6.0", + "cross-fetch": "^3.1.5", + "deepmerge": "~4.2.2", "fast-json-patch": "^3.0.0-1", "form-data-encoder": "^1.4.3", "formdata-node": "^4.0.0", + "is-plain-object": "^5.0.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", - "qs": "^6.9.4", + "qs": "^6.10.2", "traverse": "~0.6.6", "url": "~0.11.0" }, @@ -16829,10 +16886,10 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" }, "js-yaml": { "version": "4.1.0", @@ -16843,9 +16900,9 @@ } }, "qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "requires": { "side-channel": "^1.0.4" } @@ -17072,13 +17129,6 @@ "commander": "^2.20.0", "source-map": "~0.6.1", "source-map-support": "~0.5.12" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "terser-webpack-plugin": { @@ -17167,10 +17217,10 @@ "find-up": "^4.0.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "supports-color": { "version": "7.2.0", @@ -17262,12 +17312,12 @@ }, "tinycolor2": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/tinycolor2/-/tinycolor2-1.4.2.tgz", "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" }, "tinyqueue": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/tinyqueue/-/tinyqueue-2.0.3.tgz", "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" }, "tmp": { @@ -17285,7 +17335,7 @@ }, "to-array-buffer": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/to-array-buffer/-/to-array-buffer-3.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/to-array-buffer/-/to-array-buffer-3.2.0.tgz", "integrity": "sha512-zN33mwi0gpL+7xW1ITLfJ48CEj6ZQW0ZAP0MU+2W3kEY0PAIncyuxmD4OqkUVhPAbTP7amq9j/iwvZKYS+lzSQ==", "requires": { "flatten-vertex-data": "^1.0.2", @@ -17305,7 +17355,7 @@ }, "to-float32": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/to-float32/-/to-float32-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/to-float32/-/to-float32-1.1.0.tgz", "integrity": "sha512-keDnAusn/vc+R3iEiSDw8TOF7gPiTLdK1ArvWtYbJQiVfmRg6i/CAvbKq3uIS0vWroAC7ZecN3DjQKw3aSklUg==" }, "to-object-path": { @@ -17346,7 +17396,7 @@ }, "to-uint8": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/to-uint8/-/to-uint8-1.4.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/to-uint8/-/to-uint8-1.4.1.tgz", "integrity": "sha512-o+ochsMlTZyucbww8It401FC2Rx+OP2RpDeYbA6h+y9HgedDl1UjdsJ9CmzKEG7AFP9es5PmJ4eDWeeeXihESg==", "requires": { "arr-flatten": "^1.1.0", @@ -17362,13 +17412,13 @@ "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "topojson-client": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/topojson-client/-/topojson-client-3.1.0.tgz", "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", "requires": { "commander": "2" @@ -17384,32 +17434,24 @@ } }, "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "requires": { - "punycode": "^2.1.0" - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "traverse": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" }, - "ts-essentials": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", - "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" - }, "ts-pnp": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==" }, "tsconfig-paths": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", - "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", "dev": true, "requires": { "@types/json5": "^0.0.29", @@ -17435,9 +17477,9 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsparticles": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/tsparticles/-/tsparticles-1.39.0.tgz", - "integrity": "sha512-UeCY5YeUU2j7eyBPwQOAeIK+TeQQkaHNpRCGQ2axdOXEFt6lm3TffgzsLSsFciEn0TrugWhNf+nO1zliWKAYcQ==" + "version": "1.40.2", + "resolved": "https://registry.npmjs.org/tsparticles/-/tsparticles-1.40.2.tgz", + "integrity": "sha512-EU+YnBibI5GD8QUZLYyG7U4p3AWQfzVyPuXXCQMhuqtiN8GConmYHHrFWjrRisduOK7ayLckRHnNpPQ3PcHYSQ==" }, "tsutils": { "version": "3.21.0", @@ -17494,7 +17536,7 @@ }, "type-name": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/type-name/-/type-name-2.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/type-name/-/type-name-2.0.2.tgz", "integrity": "sha1-7+fUEj2KxSr/9/QMfk3sUmYAj7Q=" }, "typedarray": { @@ -17504,7 +17546,7 @@ }, "typedarray-pool": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/typedarray-pool/-/typedarray-pool-1.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/typedarray-pool/-/typedarray-pool-1.2.0.tgz", "integrity": "sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==", "requires": { "bit-twiddle": "^1.0.0", @@ -17663,7 +17705,7 @@ }, "update-diff": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-diff/-/update-diff-1.1.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/update-diff/-/update-diff-1.1.0.tgz", "integrity": "sha1-9RAYLYHugZ+4LDprIrYrve2ngI8=" }, "uri-js": { @@ -17706,9 +17748,9 @@ } }, "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz", + "integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -17720,12 +17762,9 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, "use-composed-ref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz", - "integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==", - "requires": { - "ts-essentials": "^2.0.3" - } + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.2.1.tgz", + "integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==" }, "use-isomorphic-layout-effect": { "version": "1.1.1", @@ -17783,7 +17822,7 @@ }, "utils-copy": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/utils-copy/-/utils-copy-1.1.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/utils-copy/-/utils-copy-1.1.1.tgz", "integrity": "sha1-biuXmCqozXPhGCo+b4vsPA9AWKc=", "requires": { "const-pinf-float64": "^1.0.0", @@ -17799,7 +17838,7 @@ }, "utils-copy-error": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-copy-error/-/utils-copy-error-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/utils-copy-error/-/utils-copy-error-1.0.1.tgz", "integrity": "sha1-eR3jk8DwmJCv1Z88vqY18HmpT6U=", "requires": { "object-keys": "^1.0.9", @@ -17808,7 +17847,7 @@ }, "utils-indexof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-indexof/-/utils-indexof-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/utils-indexof/-/utils-indexof-1.0.0.tgz", "integrity": "sha1-IP6r8J7xAYtSNkPoOA57yD7GG1w=", "requires": { "validate.io-array-like": "^1.0.1", @@ -17822,7 +17861,7 @@ }, "utils-regex-from-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-regex-from-string/-/utils-regex-from-string-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/utils-regex-from-string/-/utils-regex-from-string-1.0.0.tgz", "integrity": "sha1-/hopCfjeD/DVGCyA+8ZU1qaH0Yk=", "requires": { "regex-regex": "^1.0.0", @@ -17850,12 +17889,12 @@ }, "validate.io-array": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-array/-/validate.io-array-1.0.6.tgz", "integrity": "sha1-W1osr9j4uFq7L4hroVPy2Tond00=" }, "validate.io-array-like": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/validate.io-array-like/-/validate.io-array-like-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-array-like/-/validate.io-array-like-1.0.2.tgz", "integrity": "sha1-evn363tRcVvrIhVmjsXM5U+t21o=", "requires": { "const-max-uint32": "^1.0.2", @@ -17864,12 +17903,12 @@ }, "validate.io-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/validate.io-buffer/-/validate.io-buffer-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-buffer/-/validate.io-buffer-1.0.2.tgz", "integrity": "sha1-hS1nNAIZFNXROvwyUxdh43IO1E4=" }, "validate.io-integer": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-integer/-/validate.io-integer-1.0.5.tgz", "integrity": "sha1-FoSWSAuVviJH7EQ/IjPeT4mHgGg=", "requires": { "validate.io-number": "^1.0.3" @@ -17877,7 +17916,7 @@ }, "validate.io-integer-primitive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-integer-primitive/-/validate.io-integer-primitive-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-integer-primitive/-/validate.io-integer-primitive-1.0.0.tgz", "integrity": "sha1-qaoBA1X+hoHA/qbBp0rSQZyt3cY=", "requires": { "validate.io-number-primitive": "^1.0.0" @@ -17885,17 +17924,17 @@ }, "validate.io-matrix-like": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/validate.io-matrix-like/-/validate.io-matrix-like-1.0.2.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-matrix-like/-/validate.io-matrix-like-1.0.2.tgz", "integrity": "sha1-XsMqddCInaxzbepovdYUWxVe38M=" }, "validate.io-ndarray-like": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-ndarray-like/-/validate.io-ndarray-like-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-ndarray-like/-/validate.io-ndarray-like-1.0.0.tgz", "integrity": "sha1-2KOw7RZbvx0vwNAHMnDPpVIpWRk=" }, "validate.io-nonnegative-integer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-nonnegative-integer/-/validate.io-nonnegative-integer-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-nonnegative-integer/-/validate.io-nonnegative-integer-1.0.0.tgz", "integrity": "sha1-gGkkOgjF+Y6VQTySnf17GPP28p8=", "requires": { "validate.io-integer": "^1.0.5" @@ -17903,17 +17942,17 @@ }, "validate.io-number": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-number/-/validate.io-number-1.0.3.tgz", "integrity": "sha1-9j/+2iSL8opnqNSODjtGGhZluvg=" }, "validate.io-number-primitive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-number-primitive/-/validate.io-number-primitive-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-number-primitive/-/validate.io-number-primitive-1.0.0.tgz", "integrity": "sha1-0uAfICmJNp3PEVVElWQgOv5YTlU=" }, "validate.io-positive-integer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-positive-integer/-/validate.io-positive-integer-1.0.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-positive-integer/-/validate.io-positive-integer-1.0.0.tgz", "integrity": "sha1-ftLQO0wnVYzGagCqsPDpIYFKZYI=", "requires": { "validate.io-integer": "^1.0.5" @@ -17921,7 +17960,7 @@ }, "validate.io-string-primitive": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/validate.io-string-primitive/-/validate.io-string-primitive-1.0.1.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/validate.io-string-primitive/-/validate.io-string-primitive-1.0.1.tgz", "integrity": "sha1-uBNbn7E3K94C/dU60dDM1t55j+4=" }, "value-equal": { @@ -17968,7 +18007,7 @@ }, "vt-pbf": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/vt-pbf/-/vt-pbf-3.1.3.tgz", "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", "requires": { "@mapbox/point-geometry": "0.1.0", @@ -17992,6 +18031,13 @@ "domexception": "^1.0.1", "webidl-conversions": "^4.0.2", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "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==" + } } }, "wait-for-expect": { @@ -18160,7 +18206,7 @@ }, "weak-map": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.5.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/weak-map/-/weak-map-1.0.5.tgz", "integrity": "sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes=" }, "web-streams-polyfill": { @@ -18170,16 +18216,16 @@ }, "webgl-context": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/webgl-context/-/webgl-context-2.2.0.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/webgl-context/-/webgl-context-2.2.0.tgz", "integrity": "sha1-jzfXJXz23xzQpJ5qextyG5TMhqA=", "requires": { "get-canvas-context": "^1.0.1" } }, "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==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "webpack": { "version": "4.42.0", @@ -18286,11 +18332,6 @@ "ajv-keywords": "^3.1.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, "ssri": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", @@ -18494,6 +18535,11 @@ "ajv-keywords": "^3.1.0" } }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -18566,13 +18612,6 @@ "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "websocket-driver": { @@ -18607,13 +18646,12 @@ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" }, "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "which": { @@ -18840,7 +18878,7 @@ }, "world-calendars": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.3.tgz", + "resolved": "https://devin-depot.rte-france.com/repository/npm-all/world-calendars/-/world-calendars-1.0.3.tgz", "integrity": "sha1-slxQMrokEo/8QdCfr0pewbnBQzU=", "requires": { "object-assign": "^4.1.0" diff --git a/webapp/package.json b/webapp/package.json index 3ab5e61aff..44c7c140e1 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -3,7 +3,7 @@ "version": "2.2.4", "private": true, "dependencies": { - "@fortawesome/fontawesome-svg-core": "^1.2.36", + "@fortawesome/fontawesome-svg-core": "~1.2.36", "@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4", @@ -55,7 +55,9 @@ "react-ace": "^8.1.0", "react-app-polyfill": "^1.0.6", "react-beautiful-dnd": "^13.1.0", + "react-color": "^2.19.3", "react-content-loader": "^6.0.3", + "react-d3-graph": "^2.6.0", "react-d3-tree": "^3.1.1", "react-dnd": "^10.0.2", "react-dnd-html5-backend": "^10.0.2", @@ -114,6 +116,8 @@ "@types/debug": "^4.1.7", "@types/js-cookie": "^2.2.7", "@types/react-beautiful-dnd": "^13.1.2", + "@types/react-color": "^3.0.6", + "@types/react-d3-graph": "^2.6.2", "@types/react-plotly.js": "^2.5.0", "@types/react-resizable": "^1.7.4", "@types/react-router-dom": "^5.3.2", diff --git a/webapp/public/locales/en/main.json b/webapp/public/locales/en/main.json index a5fa15f1a7..8e479c7eae 100644 --- a/webapp/public/locales/en/main.json +++ b/webapp/public/locales/en/main.json @@ -30,5 +30,6 @@ "appUnderMaintenance": "App under maintenance.", "comeBackLater": "Please come back later.", "onGetMessageInfoError": "Unable to retrieve message info", - "onGetMaintenanceError": "Unable to retrieve maintenance status" + "onGetMaintenanceError": "Unable to retrieve maintenance status", + "search": "Search" } \ No newline at end of file diff --git a/webapp/public/locales/en/singlestudy.json b/webapp/public/locales/en/singlestudy.json index 0167aa0bfc..d08ca0d533 100644 --- a/webapp/public/locales/en/singlestudy.json +++ b/webapp/public/locales/en/singlestudy.json @@ -68,11 +68,29 @@ "onStudyIdCopyError": "Failed to copy study id", "copyId": "Copy the study id", "copyIdDir": "Copy id", + "newArea": "New Area", + "newLink": "New Link", + "areaName": "Area name", + "linkSource": "Source name", + "linkTarget": "Target name", + "map": "Map", + "posX": "Position X", + "posY": "Position Y", + "color": "Color", + "more": "More", + "confirmDeleteLink": "Are you sure you want to delete this link ?", + "confirmDeleteArea": "Are you sure you want to delete this area ?", + "createAreaError": "Failed to create the area", + "createLinkError": "Failed to create the link", + "updateUIError": "Failed to update the area", + "deleteAreaOrLink": "Area or link not deleted", "exportAll": "Export all outputs", "outputExportSuccess": "Outputs exported successfully", "outputExportInProgress": "Downloading study outputs...", "columns": "Columns", "filter": "Filter", "filterIn": "Filter In", - "filterOut": "Filter Out" + "filterOut": "Filter Out", + "area1": "Area 1", + "area2": "Area 2" } diff --git a/webapp/public/locales/fr/main.json b/webapp/public/locales/fr/main.json index c156390f0f..7a7b27089e 100644 --- a/webapp/public/locales/fr/main.json +++ b/webapp/public/locales/fr/main.json @@ -31,5 +31,6 @@ "appUnderMaintenance": "Site en maintenance", "comeBackLater": "Merci de revenir plus tard", "onGetMessageInfoError": "Impossible de récupérer le message d'info", - "onGetMaintenanceError": "Impossible de récupérer le status de maintenance de l'application" + "onGetMaintenanceError": "Impossible de récupérer le status de maintenance de l'application", + "search": "Rechercher" } \ No newline at end of file diff --git a/webapp/public/locales/fr/singlestudy.json b/webapp/public/locales/fr/singlestudy.json index 13355e2e60..0641bbdac6 100644 --- a/webapp/public/locales/fr/singlestudy.json +++ b/webapp/public/locales/fr/singlestudy.json @@ -68,11 +68,29 @@ "onStudyIdCopyError": "Erreur lors de la copie de l'identifiant de l'étude", "copyId": "Copie l'identifiant de l'étude", "copyIdDir": "Copier l'ID", + "newArea": "Nouvelle zone", + "newLink": "Nouveau lien", + "areaName": "Nom de la zone", + "linkSource": "Nom de la source", + "linkTarget": "Nom de la cible", + "map": "Map", + "posX": "Position X", + "posY": "Position Y", + "color": "Couleur", + "more": "Plus", + "confirmDeleteLink": "Êtes-vous sûr de vouloir supprimer ce lien ?", + "confirmDeleteArea": "Êtes-vous sûr de vouloir supprimer cette zone ?", + "createAreaError": "Échec lors de la création de la zone", + "createLinkError": "Échec lors de la création du lien", + "updateUIError": "Échec lors de la modification de la zone", + "deleteAreaOrLink": "Zone ou lien non supprimé", "exportAll": "Exporter toutes les sorties", "outputExportSuccess": "Sorties exportées avec succès", "outputExportInProgress": "Téléchargement des sorties en cours...", "columns": "Colonnes", "filter": "Filtre", "filterIn": "Filtre d'inclusion (Regex)", - "filterOut": "Filtre d'exclusion (Regex)" + "filterOut": "Filtre d'exclusion (Regex)", + "area1": "Zone 1", + "area2": "Zone 2" } \ No newline at end of file diff --git a/webapp/src/App/Pages/SingleStudy.tsx b/webapp/src/App/Pages/SingleStudy.tsx index 845cbc3da3..c40a65556a 100644 --- a/webapp/src/App/Pages/SingleStudy.tsx +++ b/webapp/src/App/Pages/SingleStudy.tsx @@ -16,6 +16,7 @@ import StudyViewLoader from '../../components/SingleStudy/StudyViewLoader'; import { LaunchJob, StudyMetadata, WSEvent, WSMessage } from '../../common/types'; import { addListener, removeListener } from '../../ducks/websockets'; import enqueueErrorSnackbar from '../../components/ui/ErrorSnackBar'; +import MapView from '../../components/SingleStudy/MapView'; const logError = debug('antares:singlestudyview:error'); @@ -80,7 +81,7 @@ const SingleStudyView = (props: PropTypes) => { const [navData, setNavData] = useState({}); const { enqueueSnackbar } = useSnackbar(); - const paramList = ['treeView', 'informations', 'variants']; + const paramList = ['treeView', 'informations', 'variants', 'map']; const fetchStudyInfo = useCallback(async () => { try { @@ -172,6 +173,8 @@ const SingleStudyView = (props: PropTypes) => { const newNavData: {[key: string]: () => JSX.Element} = { informations: () => (study ? : ), + map: () => + (study ? : ), }; if (study?.managed) { newNavData.variants = () => (study ? :
); diff --git a/webapp/src/components/SingleStudy/MapView/CreateAreaModal.tsx b/webapp/src/components/SingleStudy/MapView/CreateAreaModal.tsx new file mode 100644 index 0000000000..8904141069 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/CreateAreaModal.tsx @@ -0,0 +1,80 @@ +import React, { useState } from 'react'; +import { + makeStyles, + createStyles, + Theme, + TextField, +} from '@material-ui/core'; +import { useTranslation } from 'react-i18next'; +import { useSnackbar } from 'notistack'; +import GenericModal from '../../ui/GenericModal'; +import { isStringEmpty } from '../../../services/utils'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + name: { + margin: theme.spacing(2), + }, + positions: { + margin: theme.spacing(2), + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, + posX: { + width: '130px', + }, + posY: { + width: '130px', + }, + color: { + margin: theme.spacing(2), + }, + })); + +interface PropType { + open: boolean; + onClose: () => void; + onSave: (name: string, posX: number, posY: number, color: string) => void; +} + +const DEFAULT_COLOR = 'rgb(230, 108, 44)'; +const DEFAULT_X = 0; +const DEFAULT_Y = 0; + +const CreateAreaModal = (props: PropType) => { + const classes = useStyles(); + const [t] = useTranslation(); + const { enqueueSnackbar } = useSnackbar(); + const { open, onClose, onSave } = props; + const [name, setName] = useState(''); + + const handleSave = (id: string, posX: number, posY: number, color: string) => { + if (!isStringEmpty(id)) { + onSave(id, posX, posY, color); + } else { + enqueueSnackbar(t('singlestudy:createAreaError'), { variant: 'error' }); + } + }; + + return ( + handleSave(name, DEFAULT_X, DEFAULT_Y, DEFAULT_COLOR)} + title={t('singlestudy:newArea')} + > +
+ setName(event.target.value as string)} + value={name} + size="small" + /> +
+
+ ); +}; + +export default CreateAreaModal; diff --git a/webapp/src/components/SingleStudy/MapView/GraphView.tsx b/webapp/src/components/SingleStudy/MapView/GraphView.tsx new file mode 100644 index 0000000000..650a184342 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/GraphView.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { Graph, GraphLink, GraphNode } from 'react-d3-graph'; +import NodeView from './NodeView'; +import { LinkProperties, NodeProperties } from './types'; + +interface GraphViewProps { + nodeData: Array; + linkData: Array; + height: number; + width: number; + onClickNode: (nodeId: string) => void; + onClickLink: (src: string, target: string) => void; + graph: React.RefObject>; + setSelectedItem: (item: NodeProperties | LinkProperties | undefined) => void; + onLink: (id: string) => void; + onNodePositionChange: (id: string, x: number, y: number) => void; + } + +const GraphView = (props: GraphViewProps) => { + const { nodeData, linkData, height, width, onClickNode, onClickLink, graph, setSelectedItem, onLink, onNodePositionChange } = props; + let nodeDataToRender = nodeData; + const initialZoom = 1; + if (nodeData.length > 0) { + // compute center offset with scale fix on x axis + const centerVector = { x: (width / initialZoom / 2), y: (height / 2) }; + + // get real center from origin enclosing rectangle + const realCenter = { + y: 0, + x: 0, + }; + // apply translations (y axis is inverted) + nodeDataToRender = nodeData.map((area) => ({ + ...area, + x: (area.x + centerVector.x - realCenter.x), + y: -area.y + centerVector.y + realCenter.y, + })); + } + return ( + , + }, + link: { + color: '#d3d3d3', + strokeWidth: 2, + }, + }} + onClickNode={onClickNode} + onClickLink={onClickLink} + onClickGraph={() => setSelectedItem(undefined)} + // eslint-disable-next-line @typescript-eslint/camelcase + onNodePositionChange={(id, x, y) => onNodePositionChange(id, x - (width / initialZoom / 2) - 0, -y + (height / 2) + 0)} + /> + + ); +}; + +export default GraphView; diff --git a/webapp/src/components/SingleStudy/MapView/LinksView.tsx b/webapp/src/components/SingleStudy/MapView/LinksView.tsx new file mode 100644 index 0000000000..164a940a77 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/LinksView.tsx @@ -0,0 +1,119 @@ +import React from 'react'; +import { + makeStyles, + createStyles, + Theme, + ListItemText, + ListItem, + Typography, +} from '@material-ui/core'; +import DeleteIcon from '@material-ui/icons/Delete'; +import { useTranslation } from 'react-i18next'; +import AutoSizer from 'react-virtualized-auto-sizer'; +import { areEqual, FixedSizeList, ListChildComponentProps } from 'react-window'; +import { LinkProperties, NodeProperties } from './types'; + +const ROW_ITEM_SIZE = 40; +const BUTTONS_SIZE = 50; + +const hoverStyle = () => ({ + '&:hover': { + textDecoration: 'underline', + }, +}); + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + width: '100%', + padding: theme.spacing(1), + flexGrow: 1, + flexShrink: 1, + minHeight: '100px', + color: theme.palette.primary.main, + }, + deleteIcon: { + cursor: 'pointer', + color: theme.palette.error.light, + '&:hover': { + color: theme.palette.error.main, + }, + }, + buttons: { + width: '100%', + justifyContent: 'flex-end', + alignItems: 'center', + display: 'flex', + height: BUTTONS_SIZE, + }, + title: { + width: '90%', + marginBottom: theme.spacing(0.7), + color: theme.palette.primary.main, + boxSizing: 'border-box', + fontWeight: 'bold', + }, + list: { + '&> div > li > div': { + cursor: 'pointer', + '&:hover': { + textDecoration: 'underline', + }, + }, + }, + })); + +interface PropsType { + links: Array; + node: NodeProperties; + onDelete: () => void; + setSelectedItem: (item: NodeProperties | LinkProperties | undefined) => void; +} + +const Row = React.memo((props: ListChildComponentProps) => { + const { data, index, style } = props; + const { links, node, setSelectedItem } = data; + const link = links[index].source === node.id ? links[index].target : links[index].source; + const linkData = links[index].source === node.id ? { source: links[index].source, target: links[index].target } : { source: links[index].target, target: links[index].source }; + + return ( + + setSelectedItem(linkData)} style={{ width: '100%', ...hoverStyle }} /> + + ); +}, areEqual); + +const LinksView = (props: PropsType) => { + const classes = useStyles(); + const { links, node, onDelete, setSelectedItem } = props; + const [t] = useTranslation(); + + return ( +
+ {links.length >= 1 && ( + + {t('singlestudy:link')} + + )} + + { + ({ height, width }) => { + const idealHeight = ROW_ITEM_SIZE * links.length; + return ( + <> + height - BUTTONS_SIZE ? height - BUTTONS_SIZE : idealHeight} width={width} itemSize={ROW_ITEM_SIZE} itemCount={links.length} itemData={{ links, node, setSelectedItem }}> + {Row} + +
+ +
+ + ); + } + } +
+
+ ); +}; + +export default LinksView; diff --git a/webapp/src/components/SingleStudy/MapView/NodeListing.tsx b/webapp/src/components/SingleStudy/MapView/NodeListing.tsx new file mode 100644 index 0000000000..d66e6a8582 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/NodeListing.tsx @@ -0,0 +1,84 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +import React from 'react'; +import { + makeStyles, + createStyles, + Theme, +} from '@material-ui/core'; +import AutoSizer from 'react-virtualized-auto-sizer'; +import { FixedSizeList, areEqual, ListChildComponentProps } from 'react-window'; +import { LinkProperties, NodeProperties } from './types'; + +const ROW_ITEM_SIZE = 30; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + height: '500px', + width: '90%', + paddingLeft: theme.spacing(3), + paddingTop: theme.spacing(1), + paddingRight: theme.spacing(2), + color: theme.palette.primary.main, + flexGrow: 1, + flexShrink: 1, + marginBottom: '76px', + }, + list: { + '&> div > div': { + cursor: 'pointer', + '&:hover': { + textDecoration: 'underline', + }, + }, + }, + })); + +interface PropsType { + nodes: Array; + setSelectedItem: (item: NodeProperties | LinkProperties) => void; +} + +const Row = React.memo((props: ListChildComponentProps) => { + const { data, index, style } = props; + const { nodes, setSelectedItem } = data; + const node = nodes[index]; + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events +
setSelectedItem(node)}> + {node.name} +
+ ); +}, areEqual); + +const NodeListing = (props: PropsType) => { + const classes = useStyles(); + const { nodes, setSelectedItem } = props; + + return ( +
+ {nodes.length > 0 && nodes && ( + + { ({ height, width }) => { + const idealHeight = ROW_ITEM_SIZE * nodes.length; + return ( + height ? height + ROW_ITEM_SIZE : idealHeight + ROW_ITEM_SIZE} + width={width} + itemCount={nodes.length} + itemSize={ROW_ITEM_SIZE} + itemData={{ nodes, setSelectedItem }} + className={classes.list} + > + {Row} + + ); + } + } + + )} +
+ ); +}; + +export default NodeListing; diff --git a/webapp/src/components/SingleStudy/MapView/NodeView.tsx b/webapp/src/components/SingleStudy/MapView/NodeView.tsx new file mode 100644 index 0000000000..e87a51af39 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/NodeView.tsx @@ -0,0 +1,103 @@ +import React, { useEffect, useRef } from 'react'; +import { + makeStyles, + createStyles, + Theme, +} from '@material-ui/core'; +import LinkIcon from '@material-ui/icons/Link'; +import { NodeProperties } from './types'; +import { rgbToHsl } from '../../../services/utils'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + width: '100%', + height: '100%', + display: 'flex', + padding: theme.spacing(0.5), + marginTop: '2px', + marginLeft: '2px', + }, + node: { + opacity: '.8', + minWidth: '40px', + textAlign: 'center', + padding: theme.spacing(0.5), + borderRadius: '30px', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + height: '20px', + backgroundColor: '#555', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + fontSize: '16px', + }, + linkIcon: { + marginLeft: theme.spacing(1), + color: theme.palette.secondary.main, + '&:hover': { + color: theme.palette.secondary.dark, + }, + }, + })); + +interface PropType { + node: NodeProperties; + linkCreation: (id: string) => void; +} + +const NodeView = (props: PropType) => { + const classes = useStyles(); + const nodeRef = useRef(null); + const { node, linkCreation } = props; + + const hslColors = rgbToHsl(node.color || 'rgb(211, 211, 211)'); + + useEffect(() => { + if (nodeRef.current) { + const parentNodeClickedWidth = nodeRef.current.parentElement?.parentElement?.parentElement?.getAttribute('width'); + const parentNodePrevWidth = nodeRef.current.parentElement?.parentElement?.parentElement?.getAttribute('prevWidth'); + if (node.highlighted) { + if (parentNodeClickedWidth !== null && parentNodeClickedWidth && !parentNodePrevWidth) { + const newSizeClickedWidth = parseInt(parentNodeClickedWidth, 10) + 32; + // eslint-disable-next-line no-unused-expressions + nodeRef.current.parentElement?.parentElement?.parentElement?.setAttribute('width', `${newSizeClickedWidth}`); + // eslint-disable-next-line no-unused-expressions + nodeRef.current.parentElement?.parentElement?.parentElement?.setAttribute('prevWidth', parentNodeClickedWidth); + // eslint-disable-next-line no-unused-expressions + nodeRef.current.parentElement?.style.setProperty('width', `${newSizeClickedWidth}px`); + } + } else if (parentNodePrevWidth) { + const newSize = parseInt(parentNodePrevWidth, 10); + // eslint-disable-next-line no-unused-expressions + nodeRef.current.parentElement?.parentElement?.parentElement?.setAttribute('width', `${newSize}`); + // eslint-disable-next-line no-unused-expressions + nodeRef.current.parentElement?.style.setProperty('width', `${newSize}px`); + // eslint-disable-next-line no-unused-expressions + nodeRef.current.parentElement?.parentElement?.parentElement?.removeAttribute('prevWidth'); + } + } + }, [node]); + + return ( +
+ {node.highlighted ? ( + <> +
= 75 || (hslColors[0] >= 50 && hslColors[0] <= 75 && hslColors[2] >= 50) ? 'black' : 'white', boxShadow: `0px 0px 4px 2px hsl(${hslColors[0]}, ${hslColors[1]}%, ${hslColors[2]}%)` }}> + {node.name} +
+ { e.preventDefault(); e.stopPropagation(); linkCreation(node.id); }} /> + + ) : ( +
= 75 || (hslColors[0] >= 50 && hslColors[0] <= 75 && hslColors[2] >= 50) ? 'black' : 'white' }}> + {node.name} +
+ ) + } +
+ ); +}; + +export default NodeView; diff --git a/webapp/src/components/SingleStudy/MapView/PanelView.tsx b/webapp/src/components/SingleStudy/MapView/PanelView.tsx new file mode 100644 index 0000000000..542de43039 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/PanelView.tsx @@ -0,0 +1,195 @@ +import clsx from 'clsx'; +import React, { useEffect, useState } from 'react'; +import { ColorResult, HuePicker, MaterialPicker } from 'react-color'; +import { + makeStyles, + createStyles, + Theme, + Typography, + TextField, +} from '@material-ui/core'; +import { useTranslation } from 'react-i18next'; +import DeleteIcon from '@material-ui/icons/Delete'; +import { NodeProperties, LinkProperties, UpdateAreaUi } from './types'; +import ConfirmationModal from '../../ui/ConfirmationModal'; +import LinksView from './LinksView'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + form: { + display: 'flex', + justifyContent: 'flex-start', + alignItems: 'center', + flexDirection: 'column', + padding: theme.spacing(1), + flexGrow: 1, + marginBottom: '76px', + width: '94%', + }, + fields: { + marginTop: theme.spacing(1), + }, + deleteIcon: { + cursor: 'pointer', + color: theme.palette.error.light, + '&:hover': { + color: theme.palette.error.main, + }, + }, + buttons: { + width: '100%', + justifyContent: 'flex-end', + alignItems: 'center', + display: 'flex', + }, + sliderpicker: { + width: '100% !important', + margin: theme.spacing(1), + }, + materialpicker: { + width: 'unset !important', + maxWidth: '230px !important', + fontFamily: '"Inter", sans-serif !important', + boxShadow: 'none', + border: '1px solid rgba(0,0,0,.12)', + }, + links: { + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + }, + link: { + cursor: 'pointer', + color: theme.palette.primary.main, + padding: theme.spacing(1), + '&:hover': { + textDecoration: 'underline', + }, + }, + info: { + width: '90%', + marginBottom: theme.spacing(0.7), + color: theme.palette.primary.main, + display: 'flex', + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + alignItems: 'center', + boxSizing: 'border-box', + }, + alignBaseline: { + alignItems: 'baseline', + }, + infoTitle: { + textDecoration: 'underline', + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + }, + infoLabel: { + fontWeight: 'bold', + }, + })); + +interface PropType { + node?: NodeProperties; + nodes?: Array; + links?: Array; + link?: LinkProperties; + onDelete: (id: string, target?: string) => void; + updateUI: (id: string, value: UpdateAreaUi) => void; + setSelectedItem: (item: NodeProperties | LinkProperties | undefined) => void; +} + +const PanelView = (props: PropType) => { + const classes = useStyles(); + const [t] = useTranslation(); + const { node, nodes, links, link, onDelete, updateUI, setSelectedItem } = props; + const [openConfirmationModal, setOpenConfirmationModal] = useState(false); + const [currentColor, setCurrentColor] = useState(node?.color || ''); + + const handleChangeColor = (color: ColorResult) => { + if (node) { + setCurrentColor(`rgb(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b})`); + // eslint-disable-next-line @typescript-eslint/camelcase + updateUI(node.id, { x: node.x, y: node.y, color_rgb: color.rgb !== null ? [color.rgb.r, color.rgb.g, color.rgb.b] : node.color.slice(4, -1).split(',').map(Number) }); + } + }; + + const handleClick = (name: string) => { + if (nodes) { + setSelectedItem(nodes.find((o) => o.id === name)); + } + }; + + useEffect(() => { + if (node?.color) { + setCurrentColor(node.color); + } + }, [node]); + + return ( + <> +
+ {node && ( + <> + + + + handleChangeColor(color)} /> + handleChangeColor(color)} /> + + )} + {links && node && ( + setOpenConfirmationModal(true)} setSelectedItem={setSelectedItem} /> + )} + {link && ( +
+ {t('singlestudy:link')} +
+ {t('singlestudy:area1')} + handleClick(link.source)}> + {link.source} + +
+
+ {t('singlestudy:area2')} + handleClick(link.target)}> + {link.target} + +
+
+ setOpenConfirmationModal(true)} /> +
+
+ )} + +
+ {openConfirmationModal && node && ( + { onDelete(node.id); setOpenConfirmationModal(false); }} + handleNo={() => setOpenConfirmationModal(false)} + /> + )} + {openConfirmationModal && link && ( + { onDelete(link.source, link.target); setOpenConfirmationModal(false); }} + handleNo={() => setOpenConfirmationModal(false)} + /> + )} + + ); +}; + +PanelView.defaultProps = { + nodes: undefined, + node: undefined, + links: undefined, + link: undefined, +}; +export default PanelView; diff --git a/webapp/src/components/SingleStudy/MapView/PropertiesView.tsx b/webapp/src/components/SingleStudy/MapView/PropertiesView.tsx new file mode 100644 index 0000000000..60cdb0a9e6 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/PropertiesView.tsx @@ -0,0 +1,131 @@ +import React, { useState } from 'react'; +import { + makeStyles, + createStyles, + Theme, + TextField, + InputAdornment, + Button, +} from '@material-ui/core'; +import SearchIcon from '@material-ui/icons/Search'; +import { useTranslation } from 'react-i18next'; +import AddIcon from '@material-ui/icons/Add'; +import { LinkProperties, NodeProperties, UpdateAreaUi, isNode } from './types'; +import PanelView from './PanelView'; +import NodeListing from './NodeListing'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + width: '20%', + height: '100%', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'flex-start', + alignItems: 'center', + boxSizing: 'border-box', + }, + list: { + minWidth: '75%', + height: '100%', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'flex-start', + alignItems: 'flex-start', + }, + search: { + margin: theme.spacing(2), + }, + button: { + position: 'absolute', + left: '20px', + bottom: '25px', + cursor: 'pointer', + borderRadius: '50px', + padding: theme.spacing(2), + backgroundColor: theme.palette.secondary.main, + color: 'white', + '&:hover': { + backgroundColor: theme.palette.secondary.dark, + }, + height: '25px', + }, + prevButton: { + color: theme.palette.primary.main, + }, + })); + +interface PropsType { + item?: NodeProperties | LinkProperties | undefined; + setSelectedItem: (item: NodeProperties | LinkProperties | undefined) => void; + nodeList: Array; + nodeLinks?: Array | undefined; + onDelete?: (id: string, target?: string) => void; + onArea?: () => void; + updateUI: (id: string, value: UpdateAreaUi) => void; +} + +const PropertiesView = (props: PropsType) => { + const classes = useStyles(); + const { item, setSelectedItem, nodeList, nodeLinks, onDelete, onArea, updateUI } = props; + const [t] = useTranslation(); + const [filteredNodes, setFilteredNodes] = useState>(); + + const filter = (currentName: string): NodeProperties[] => { + if (nodeList) { + return nodeList.filter((s) => !currentName || (s.id.search(new RegExp(currentName, 'i')) !== -1)); + } + return []; + }; + + const onChange = async (currentName: string) => { + if (currentName !== '') { + const f = filter(currentName); + setFilteredNodes(f); + } else { + setFilteredNodes(undefined); + } + }; + + return ( +
+ + + + ), + }} + onChange={(e) => onChange(e.target.value as string)} + /> + {item && isNode(item) && onDelete ? ( +
+ + +
+ ) : (item && onDelete && ( +
+ + +
+ ))} + {filteredNodes && !item && ( + + )} + +
+ ); +}; + +PropertiesView.defaultProps = { + item: undefined, + nodeLinks: undefined, + onDelete: undefined, + onArea: undefined, +}; + +export default PropertiesView; diff --git a/webapp/src/components/SingleStudy/MapView/index.tsx b/webapp/src/components/SingleStudy/MapView/index.tsx new file mode 100644 index 0000000000..21578a6edd --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/index.tsx @@ -0,0 +1,363 @@ +import React, { useEffect, useState, useRef, useCallback } from 'react'; +import { Graph, GraphLink, GraphNode } from 'react-d3-graph'; +import { AxiosError } from 'axios'; +import { + makeStyles, + createStyles, + Theme, + Paper, + Typography, +} from '@material-ui/core'; +import AutoSizer from 'react-virtualized-auto-sizer'; +import { useTranslation } from 'react-i18next'; +import { useSnackbar } from 'notistack'; +import { getAreaPositions, getSynthesis } from '../../../services/api/study'; +import enqueueErrorSnackbar from '../../ui/ErrorSnackBar'; +import { NodeProperties, LinkProperties, AreasConfig, SingleAreaConfig, UpdateAreaUi, isNode } from './types'; +import CreateAreaModal from './CreateAreaModal'; +import PropertiesView from './PropertiesView'; +import SimpleLoader from '../../ui/loaders/SimpleLoader'; +import { StudyMetadata } from '../../../common/types'; +import GraphView from './GraphView'; +import { createArea, createLink, deleteArea, deleteLink, updateAreaUI } from '../../../services/api/studydata'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + width: '99%', + height: '100%', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'flex-start', + alignItems: 'center', + backgroundColor: 'white', + margin: theme.spacing(1), + boxSizing: 'border-box', + }, + header: { + width: '100%', + height: '40px', + boxSizing: 'border-box', + display: 'flex', + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + alignItems: 'center', + backgroundColor: theme.palette.primary.main, + borderTopLeftRadius: theme.shape.borderRadius, + borderTopRightRadius: theme.shape.borderRadius, + paddingLeft: theme.spacing(2), + }, + title: { + fontWeight: 'bold', + color: 'white', + }, + autosizer: { + display: 'block', + width: '80%', + height: '100%', + position: 'relative', + }, + popup: { + position: 'absolute', + right: '30px', + top: '100px', + width: '200px', + }, + graph: { + '& svg[name="svg-container-graph-id"]': { + backgroundColor: '#fefefe', + backgroundImage: 'url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'8\' height=\'8\' viewBox=\'0 0 8 8\'%3E%3Cg fill=\'%23dedede\' fill-opacity=\'0.4\'%3E%3Cpath fill-rule=\'evenodd\' d=\'M0 0h4v4H0V0zm4 4h4v4H4V4z\'/%3E%3C/g%3E%3C/svg%3E")', + }, + }, + graphView: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + height: '100%', + }, + areaCount: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '12%', + position: 'absolute', + right: theme.spacing(2), + }, + })); + +interface Props { + study: StudyMetadata; +} + +const FONT_SIZE = 15; +const NODE_HEIGHT = 400; + +const calculateSize = (text: string): number => { + const textSize = text.length; + if (textSize === 1) { + return FONT_SIZE * textSize * 36; + } + if (textSize <= 2) { + return FONT_SIZE * textSize * 20; + } + if (textSize <= 3) { + return FONT_SIZE * textSize * 12; + } + if (textSize <= 5) { + return FONT_SIZE * textSize * 10; + } + if (textSize <= 6) { + return FONT_SIZE * textSize * 8.5; + } + if (textSize <= 10) { + return FONT_SIZE * textSize * 7.5; + } + return FONT_SIZE * textSize * 6.5; +}; + +const GraphViewMemo = React.memo(GraphView); + +const MapView = (props: Props) => { + const classes = useStyles(); + const [t] = useTranslation(); + const { study } = props; + const [loaded, setLoaded] = useState(false); + const [selectedItem, setSelectedItem] = useState(); + const [selectedNodeLinks, setSelectedNodeLinks] = useState>(); + const [nodeData, setNodeData] = useState>([]); + const [linkData, setLinkData] = useState>([]); + const { enqueueSnackbar } = useSnackbar(); + const [openModal, setOpenModal] = useState(false); + const [firstNode, setFirstNode] = useState(); + const [secondNode, setSecondNode] = useState(); + const graphRef = useRef>(null); + const prevselectedItemId = useRef(); + + const onClickNode = useCallback((nodeId: string) => { + if (!firstNode && nodeData) { + const obj = nodeData.find((o) => o.id === nodeId); + setSelectedItem(obj); + } else if (firstNode) { + setSecondNode(nodeId); + } + }, [firstNode, nodeData]); + + const onClickLink = useCallback((source: string, target: string) => { + const obj = { + source, + target, + }; + setSelectedItem(obj); + }, []); + + const createModeLink = useCallback((id: string) => { + if (firstNode && firstNode === id) { + setFirstNode(undefined); + setSecondNode(undefined); + } else { + setFirstNode(id); + } + }, [firstNode, setFirstNode, setSecondNode]); + + const onClose = () => { + setOpenModal(false); + }; + + const onSave = async (name: string, posX: number, posY: number, color: string) => { + setOpenModal(false); + try { + const area = await createArea(study.id, name); + setNodeData([...nodeData, { + id: area.id, + name: area.name, + x: posX, + y: posY, + color, + rgbColor: color.slice(4, -1).split(',').map(Number), + size: { width: calculateSize(name), height: NODE_HEIGHT }, + }]); + } catch (e) { + enqueueErrorSnackbar(enqueueSnackbar, t('singlestudy:createAreaError'), e as AxiosError); + } + }; + + const getTargetNode = (id: string) => nodeData.find((o) => o.id === id); + + const updateUI = async (id: string, value: UpdateAreaUi) => { + const targetNode = getTargetNode(id); + if (targetNode) { + try { + const prevColors = targetNode.rgbColor; + const prevPosition = { x: targetNode.x, y: targetNode.y }; + if ((value.color_rgb[0] !== prevColors[0] || value.color_rgb[1] !== prevColors[1] || value.color_rgb[2] !== prevColors[2]) || (value.x !== prevPosition.x || value.y !== prevPosition.y)) { + const updateNode = nodeData.filter((o) => o.id !== id); + setNodeData([...updateNode, { + ...targetNode, + x: value.x, + y: value.y, + color: `rgb(${value.color_rgb[0]}, ${value.color_rgb[1]}, ${value.color_rgb[2]})`, + rgbColor: [value.color_rgb[0], value.color_rgb[1], value.color_rgb[2]], + }]); + await updateAreaUI(study.id, id, value); + } + } catch (e) { + setNodeData([...nodeData]); + enqueueErrorSnackbar(enqueueSnackbar, t('singlestudy:updateUIError'), e as AxiosError); + } + } + }; + + const handleUpdatePosition = async (id: string, x: number, y: number) => { + const targetNode = getTargetNode(id); + if (targetNode) { + // eslint-disable-next-line @typescript-eslint/camelcase + updateUI(id, { x, y, color_rgb: targetNode.rgbColor }); + } + }; + + const onDelete = async (id: string, target?: string) => { + if (graphRef.current) { + const currentGraph = graphRef.current; + // eslint-disable-next-line no-underscore-dangle + currentGraph._setNodeHighlightedValue(id, false); + } + + setTimeout(async () => { + if (target && linkData) { + try { + const links = linkData.filter((o) => o.source !== id || o.target !== target); + setLinkData(links); + setSelectedItem(undefined); + await deleteLink(study.id, id, target); + } catch (e) { + setLinkData([...linkData]); + enqueueErrorSnackbar(enqueueSnackbar, t('singlestudy:deleteAreaOrLink'), e as AxiosError); + } + } else if (nodeData && linkData && !target) { + const obj = nodeData.filter((o) => o.id !== id); + const links = linkData.filter((o) => o.source !== id && o.target !== id); + try { + setSelectedItem(undefined); + setLinkData(links); + setNodeData(obj); + await deleteArea(study.id, id); + } catch (e) { + setLinkData([...linkData]); + setNodeData([...nodeData]); + enqueueErrorSnackbar(enqueueSnackbar, t('singlestudy:deleteAreaOrLink'), e as AxiosError); + } + } + }, 0); + }; + + useEffect(() => { + const init = async () => { + if (firstNode && secondNode) { + try { + setLinkData([...linkData, ...[{ + source: firstNode, + target: secondNode, + }]]); + setFirstNode(undefined); + setSecondNode(undefined); + await createLink(study.id, { area1: firstNode, area2: secondNode }); + } catch (e) { + setLinkData(linkData.filter((o) => o.source !== firstNode || o.target !== secondNode)); + enqueueErrorSnackbar(enqueueSnackbar, t('singlestudy:createLinkError'), e as AxiosError); + } + } + }; + init(); + }, [enqueueSnackbar, t, firstNode, secondNode, study.id, linkData]); + + useEffect(() => { + const init = async () => { + try { + const data = await getSynthesis(study.id); + const areaData = await getAreaPositions(study.id, Object.keys(data.areas).join(',')); + const areas: AreasConfig = Object.keys(data.areas).length === 1 ? { [Object.keys(data.areas)[0]]: areaData as SingleAreaConfig } : areaData as AreasConfig; + const tempNodeData = Object.keys(areas).map((areaId) => ({ + id: areaId, + name: data.areas[areaId].name, + x: areas[areaId].ui.x, + y: areas[areaId].ui.y, + color: `rgb(${areas[areaId].ui.color_r}, ${areas[areaId].ui.color_g}, ${areas[areaId].ui.color_b})`, + rgbColor: [areas[areaId].ui.color_r, areas[areaId].ui.color_g, areas[areaId].ui.color_b], + size: { width: calculateSize(areaId), height: NODE_HEIGHT }, + })); + setNodeData(tempNodeData); + setLinkData(Object.keys(data.areas).reduce((links, currentAreaId) => + links.concat(Object.keys(data.areas[currentAreaId].links).map((linkId) => ({ + source: currentAreaId, + target: linkId, + }))), [] as Array)); + } catch (e) { + enqueueErrorSnackbar(enqueueSnackbar, t('studymanager:failtoloadstudy'), e as AxiosError); + } finally { + setLoaded(true); + } + }; + init(); + }, [enqueueSnackbar, study.id, t]); + + useEffect(() => { + if (selectedItem && isNode(selectedItem)) { + setSelectedNodeLinks(linkData.filter((o) => o.source === (selectedItem as NodeProperties).id || o.target === (selectedItem as NodeProperties).id)); + } + if (graphRef.current) { + const currentGraph = graphRef.current; + if (prevselectedItemId.current) { + // eslint-disable-next-line no-underscore-dangle + currentGraph._setNodeHighlightedValue(prevselectedItemId.current, false); + } + if (selectedItem && isNode(selectedItem)) { + setTimeout(() => { + // eslint-disable-next-line no-underscore-dangle + currentGraph._setNodeHighlightedValue((selectedItem as NodeProperties).id, true); + prevselectedItemId.current = (selectedItem as NodeProperties).id; + }, 0); + } + } + }, [selectedItem, linkData]); + + return ( + +
+ {t('singlestudy:map')} +
+
+ o.id === (selectedItem as NodeProperties).id) : selectedItem} setSelectedItem={setSelectedItem} nodeLinks={selectedNodeLinks} nodeList={nodeData} onDelete={onDelete} onArea={() => setOpenModal(true)} updateUI={updateUI} /> +
+ {loaded ? ( + + { + ({ height, width }) => ( + + ) + } + + ) : + } +
+

+ {`${nodeData.length} ${t('singlestudy:area')}`} +

+

+ {`${linkData.length} ${t('singlestudy:link')}`} +

+
+
+
+ {openModal && ( + + )} +
+ ); +}; + +export default MapView; diff --git a/webapp/src/components/SingleStudy/MapView/types.ts b/webapp/src/components/SingleStudy/MapView/types.ts new file mode 100644 index 0000000000..0003a02ce2 --- /dev/null +++ b/webapp/src/components/SingleStudy/MapView/types.ts @@ -0,0 +1,108 @@ +export interface NodeProperties { + id: string; + name: string; + x: number; + y: number; + color: string; + rgbColor: Array; + size: { width: number; height: number }; + highlighted?: boolean; +} + +export interface LinkSynthesis { + [index: string]: object; +} + +export interface AreasSynthesis { + name: string; + links: LinkSynthesis; + thermals: string; + renewables: Array; + // eslint-disable-next-line camelcase + filters_synthesis: Array; + // eslint-disable-next-line camelcase + filters_year: Array; +} + +export interface AreasNameSynthesis { + [index: string]: AreasSynthesis; +} + +export interface StudyProperties { + archiveInputSeries: Array; + areas: AreasNameSynthesis; + bindings: Array; + enrModelling: string; + outputPath: string; + outputs: string; + path: string; + sets: string; + storeNewSet: boolean; + studyId: string; + studyPath: string; + version: number; +} + +export interface LinkProperties { + source: string; + target: string; +} + +export interface AreaLayerColor { + [key: number]: string; +} +export interface AreaLayerXandY { + [key: number]: string; +} + +export interface AreaUI { + id: string; + // eslint-disable-next-line camelcase + color_b: number; + // eslint-disable-next-line camelcase + color_g: number; + // eslint-disable-next-line camelcase + color_r: number; + layers: string; + x: number; + y: number; +} + +export interface SingleAreaConfig { + layerColor: AreaLayerColor; + layerX: AreaLayerXandY; + layerY: AreaLayerXandY; + ui: AreaUI; +} + +export interface AreasConfig { + [index: string]: SingleAreaConfig; +} + +export interface UpdateAreaUi { + x: number; + y: number; + // eslint-disable-next-line camelcase + color_rgb: Array; +} + +export interface LinkCreationInfo { + area1: string; + area2: string; +} + +export interface AreaCreationDTO { + name: string; + type: object; + metadata?: object; + set?: Array; +} + +export interface AreaInfoDTO extends AreaCreationDTO { + id: string; + thermals: Array; +} + +export const isNode = (el: NodeProperties | LinkProperties): boolean => (el as any).id !== undefined; + +export default {}; diff --git a/webapp/src/services/api/study.ts b/webapp/src/services/api/study.ts index 159d14f7e6..f00e8e4818 100644 --- a/webapp/src/services/api/study.ts +++ b/webapp/src/services/api/study.ts @@ -4,6 +4,7 @@ import { FileStudyTreeConfigDTO, LaunchJob, MatrixAggregationResult, StudyOutput import { getConfig } from '../config'; import { convertStudyDtoToMetadata } from '../utils'; import { FileDownloadTask } from './downloads'; +import { AreasConfig, SingleAreaConfig, StudyProperties } from '../../components/SingleStudy/MapView/types'; const getStudiesRaw = async (): Promise<{[sid: string]: StudyMetadataDTO}> => { const res = await client.get('/v1/studies?summary=true'); @@ -33,6 +34,16 @@ export const getComments = async (sid: string): Promise => { return res.data; }; +export const getSynthesis = async (uuid: string): Promise => { + const res = await client.get(`/v1/studies/${uuid}/synthesis`); + return res.data; +}; + +export const getAreaPositions = async (uuid: string, path: string, depth = -1): Promise => { + const res = await client.get(`v1/studies/${uuid}/raw?path=/input/areas/${encodeURIComponent(path)}/ui&depth=${depth}`); + return res.data; +}; + export const getStudyMetadata = async (sid: string, summary = true): Promise => { const res = await client.get(`/v1/studies/${sid}?summary=${summary}`); return convertStudyDtoToMetadata(sid, res.data); diff --git a/webapp/src/services/api/studydata.ts b/webapp/src/services/api/studydata.ts new file mode 100644 index 0000000000..0ccb590480 --- /dev/null +++ b/webapp/src/services/api/studydata.ts @@ -0,0 +1,29 @@ +import { AreaInfoDTO, LinkCreationInfo, UpdateAreaUi } from '../../components/SingleStudy/MapView/types'; +import client from './client'; + +export const createArea = async (uuid: string, name: string): Promise => { + const res = await client.post(`/v1/studies/${uuid}/areas?uuid=${uuid}`, { name, type: 'AREA' }); + return res.data; +}; + +export const createLink = async (uuid: string, linkCreationInfo: LinkCreationInfo): Promise => { + const res = await client.post(`/v1/studies/${uuid}/links?uuid=${uuid}`, linkCreationInfo); + return res.data; +}; + +export const updateAreaUI = async (uuid: string, areaId: string, areaUi: UpdateAreaUi): Promise => { + const res = await client.put(`/v1/studies/${uuid}/areas/${areaId}/ui?uuid=${uuid}&area_id=${areaId}`, areaUi); + return res.data; +}; + +export const deleteArea = async (uuid: string, areaId: string): Promise => { + const res = await client.delete(`/v1/studies/${uuid}/areas/${areaId}?uuid=${uuid}&area_id=${areaId}`); + return res.data; +}; + +export const deleteLink = async (uuid: string, areaIdFrom: string, areaIdTo: string): Promise => { + const res = await client.delete(`/v1/studies/${uuid}/links/${areaIdFrom}/${areaIdTo}?uuid=${uuid}&area_from=${areaIdFrom}&area_to=${areaIdTo}`); + return res.data; +}; + +export default {}; diff --git a/webapp/src/services/utils/index.ts b/webapp/src/services/utils/index.ts index 9d1dbd69ff..bf2e5ca34c 100644 --- a/webapp/src/services/utils/index.ts +++ b/webapp/src/services/utils/index.ts @@ -141,4 +141,42 @@ export const getInitMessageInfo = async (): Promise => { export const isStringEmpty = (data: string): boolean => data.replace(/\s/g, '') === ''; +export const rgbToHsl = (rgbStr: string): Array => { + const [r, g, b] = rgbStr.slice(4, -1).split(',').map(Number); + const red = r / 255; + const green = g / 255; + const blue = b / 255; + + const cmin = Math.min(red, green, blue); + const cmax = Math.max(red, green, blue); + const delta = cmax - cmin; + let h = 0; + let s = 0; + let l = 0; + + if (delta === 0) { + h = 0; + } else if (cmax === red) { + h = ((green - blue) / delta) % 6; + } else if (cmax === green) { + h = (blue - red) / delta + 2; + } else { + h = (red - green) / delta + 4; + } + + h = Math.round(h * 60); + + if (h < 0) { + h += 360; + } + + l = (cmax + cmin) / 2; + s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); + + s = +(s * 100).toFixed(1); + l = +(l * 100).toFixed(1); + + return [h, s, l]; +}; + export default {}; From ea9d7f7a14ede37bb3d497f16d70cb0a79fe1c43 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Fri, 11 Feb 2022 13:26:58 +0100 Subject: [PATCH 18/23] Matrix gc fixes (#742) --- antarest/core/config.py | 3 + antarest/main.py | 2 +- .../matrixstore/matrix_garbage_collector.py | 55 ++++++++++++++----- antarest/matrixstore/repository.py | 10 +++- antarest/study/common/uri_resolver_service.py | 22 ++++++-- resources/application.yaml | 4 +- .../test_matrix_garbage_collector.py | 22 ++++++-- 7 files changed, 90 insertions(+), 28 deletions(-) diff --git a/antarest/core/config.py b/antarest/core/config.py index 06e3781d59..dbf2fd5236 100644 --- a/antarest/core/config.py +++ b/antarest/core/config.py @@ -113,6 +113,7 @@ class StorageConfig: watcher_lock_delay: int = 10 download_default_expiration_timeout_minutes: int = 1440 matrix_gc_sleeping_time: int = 3600 + matrix_gc_dry_run: bool = False @staticmethod def from_dict(data: JSON) -> "StorageConfig": @@ -130,6 +131,8 @@ def from_dict(data: JSON) -> "StorageConfig": download_default_expiration_timeout_minutes=data.get( "download_default_expiration_timeout_minutes", 1440 ), + matrix_gc_sleeping_time=data.get("matrix_gc_sleeping_time", 3600), + matrix_gc_dry_run=data.get("matrix_gc_dry_run", False), ) diff --git a/antarest/main.py b/antarest/main.py index 9ad889b6de..dfeec0af23 100644 --- a/antarest/main.py +++ b/antarest/main.py @@ -472,6 +472,6 @@ def handle_all_exception(request: Request, exc: Exception) -> Any: configure_logger(config) init_db(config_file, config, False, None) matrix_gc = create_matrix_gc(config=config, application=None) - matrix_gc.start() + matrix_gc.start(threaded=False) else: raise UnknownModuleError(module) diff --git a/antarest/matrixstore/matrix_garbage_collector.py b/antarest/matrixstore/matrix_garbage_collector.py index 246f4b1c66..94fcbf5526 100644 --- a/antarest/matrixstore/matrix_garbage_collector.py +++ b/antarest/matrixstore/matrix_garbage_collector.py @@ -1,18 +1,22 @@ +import contextlib import logging import threading import time from os import listdir from pathlib import Path -from typing import Set, List +from typing import Set, List, Optional from antarest.core.config import Config from antarest.core.utils.fastapi_sqlalchemy import db from antarest.core.utils.utils import StopWatch from antarest.matrixstore.repository import MatrixDataSetRepository from antarest.matrixstore.service import MatrixService +from antarest.study.common.uri_resolver_service import UriResolverService from antarest.study.model import DEFAULT_WORKSPACE_NAME from antarest.study.service import StudyService +from antarest.study.storage.variantstudy.model.command.icommand import ICommand from antarest.study.storage.variantstudy.model.dbmodel import CommandBlock +from antarest.study.storage.variantstudy.model.model import CommandDTO from antarest.study.storage.variantstudy.variant_study_service import ( VariantStudyService, ) @@ -41,16 +45,21 @@ def __init__( matrix_service.repo_dataset ) self.sleeping_time = config.storage.matrix_gc_sleeping_time + self.dry_run = config.storage.matrix_gc_dry_run def _get_saved_matrices(self) -> Set[str]: - logging.info("Getting all saved matrices") + logger.info("Getting all saved matrices") return {f.split(".")[0] for f in listdir(self.saved_matrices_path)} def _get_raw_studies_matrices(self) -> Set[str]: logger.info("Getting all matrices used in raw studies") return { - f.name.split(".")[0] - for f in self.managed_studies_path.rglob("*.link") + matrix_id + for matrix_id in [ + UriResolverService.extract_id(f.read_text()) + for f in self.managed_studies_path.rglob("*.link") + ] + if matrix_id } def _get_variant_studies_matrices(self) -> Set[str]: @@ -58,12 +67,22 @@ def _get_variant_studies_matrices(self) -> Set[str]: command_blocks: List[ CommandBlock ] = self.variant_study_service.repository.get_all_commandblocks() + + def transform_to_icommand(command_dto: CommandDTO) -> List[ICommand]: + try: + return self.variant_study_service.command_factory.to_icommand( + command_dto + ) + except Exception as e: + logger.warning( + f"Failed to parse command {command_dto} !", exc_info=e + ) + return [] + variant_study_commands = [ icommand for c in command_blocks - for icommand in self.variant_study_service.command_factory.to_icommand( - c.to_dto() - ) + for icommand in transform_to_icommand(c.to_dto()) ] matrices = { matrix @@ -92,10 +111,12 @@ def _get_used_matrices(self) -> Set[str]: def _delete_unused_saved_matrices(self, unused_matrices: Set[str]) -> None: """Delete all files with the name in unused_matrices""" - logging.info("Deleting unused saved matrices:") + logger.info("Deleting unused saved matrices:") for unused_matrix_id in unused_matrices: - logging.info(f"Deleting {unused_matrix_id}") - self.matrix_service.delete(unused_matrix_id) + logger.info(f"Matrix {unused_matrix_id} is set to be deleted") + if not self.dry_run: + logger.info(f"Deleting {unused_matrix_id}") + self.matrix_service.delete(unused_matrix_id) def _clean_matrices(self) -> None: """Delete all matrices that are not used anymore""" @@ -112,11 +133,15 @@ def _clean_matrices(self) -> None: def _loop(self) -> None: while True: try: - self._clean_matrices() + with db(): + self._clean_matrices() except Exception as e: - logging.error(f"Error while cleaning matrices: {e}") - logging.info(f"Sleeping for {self.sleeping_time}s") + logger.error(f"Error while cleaning matrices", exc_info=e) + logger.info(f"Sleeping for {self.sleeping_time}s") time.sleep(self.sleeping_time) - def start(self) -> None: - self.thread.start() + def start(self, threaded: bool = True) -> None: + if threaded: + self.thread.start() + else: + self._loop() diff --git a/antarest/matrixstore/repository.py b/antarest/matrixstore/repository.py index 69692900e1..520797e60f 100644 --- a/antarest/matrixstore/repository.py +++ b/antarest/matrixstore/repository.py @@ -103,9 +103,13 @@ def exists(self, id: str) -> bool: def delete(self, id: str) -> None: g = db.session.query(Matrix).get(id) - db.session.delete(g) - db.session.commit() - + if g: + db.session.delete(g) + db.session.commit() + else: + logger.warning( + f"Trying to delete matrix {id}, but was not found in database!" + ) logger.debug(f"Matrix {id} deleted") diff --git a/antarest/study/common/uri_resolver_service.py b/antarest/study/common/uri_resolver_service.py index f6cbd11f1d..14323b7dd7 100644 --- a/antarest/study/common/uri_resolver_service.py +++ b/antarest/study/common/uri_resolver_service.py @@ -1,5 +1,5 @@ import re -from typing import Union +from typing import Union, Optional, Tuple from antarest.core.config import Config from antarest.core.model import JSON, SUB_JSON @@ -11,16 +11,30 @@ def __init__(self, matrix_service: ISimpleMatrixService): self.matrix_service = matrix_service def resolve(self, uri: str) -> Union[bytes, SUB_JSON]: + res = UriResolverService._extract_uri_components(uri) + if res: + protocol, uuid = res + else: + return None + + if protocol == "matrix": + return self._resolve_matrix(uuid) + raise NotImplementedError(f"protocol {protocol} not implemented") + + @staticmethod + def _extract_uri_components(uri: str) -> Optional[Tuple[str, str]]: match = re.match(r"^(\w+)://(.+)$", uri) if not match: return None protocol = match.group(1) uuid = match.group(2) + return protocol, uuid - if protocol == "matrix": - return self._resolve_matrix(uuid) - raise NotImplementedError(f"protocol {protocol} not implemented") + @staticmethod + def extract_id(uri: str) -> Optional[str]: + res = UriResolverService._extract_uri_components(uri) + return res[1] if res else None def _resolve_matrix(self, id: str) -> JSON: data = self.matrix_service.get(id) diff --git a/resources/application.yaml b/resources/application.yaml index 0382d7851e..f32fc3a4d8 100644 --- a/resources/application.yaml +++ b/resources/application.yaml @@ -23,7 +23,8 @@ storage: matrixstore: ./matrices archive_dir: examples/archives allow_deletion: false # indicate if studies found in non default workspace can be deleted by the application - matrix_gc_sleeping_time: 3600 # time in seconds to sleep between two garbage collection + #matrix_gc_sleeping_time: 3600 # time in seconds to sleep between two garbage collection + #matrix_gc_dry_run: False # Skip matrix effective deletion workspaces: default: # required, no filters applied, this folder is not watched path: examples/internal_studies/ @@ -73,6 +74,7 @@ server: worker_threadpool_size: 12 services: - watcher + - matrix_gc logging: level: INFO diff --git a/tests/matrixstore/test_matrix_garbage_collector.py b/tests/matrixstore/test_matrix_garbage_collector.py index 363386d72f..e4f4fd3e44 100644 --- a/tests/matrixstore/test_matrix_garbage_collector.py +++ b/tests/matrixstore/test_matrix_garbage_collector.py @@ -41,6 +41,7 @@ def matrix_garbage_collector(tmp_path: Path): mock_config = Mock() mock_config.storage.matrixstore = matrix_store mock_config.storage.workspaces = {"default": mock_workspace_config} + mock_config.storage.matrix_gc_dry_run = False command_factory = CommandFactory( generator_matrix_constants=Mock(spec=GeneratorMatrixConstants), @@ -100,10 +101,18 @@ def test_get_matrices_used_in_raw_studies( matrix_garbage_collector.managed_studies_path / "raw_study" ) raw_study_path.mkdir() - (raw_study_path / f"{matrix_name1}.link").touch() - (raw_study_path / f"{matrix_name2}.link").touch() - (raw_study_path / f"{matrix_name3}.link").touch() - (raw_study_path / f"{matrix_name4}.txt").touch() + (raw_study_path / f"{matrix_name1}.link").write_text( + f"matrix://{matrix_name1}" + ) + (raw_study_path / f"{matrix_name2}.link").write_text( + f"matrix://{matrix_name2}" + ) + (raw_study_path / f"{matrix_name3}.link").write_text( + f"matrix://{matrix_name3}" + ) + (raw_study_path / f"{matrix_name4}.txt").write_text( + f"matrix://{matrix_name4}" + ) output = matrix_garbage_collector._get_raw_studies_matrices() @@ -220,6 +229,11 @@ def test_delete_unused_saved_matrices( matrix_garbage_collector.matrix_service.delete.assert_any_call("matrix1") matrix_garbage_collector.matrix_service.delete.assert_any_call("matrix2") + matrix_garbage_collector.dry_run = True + matrix_garbage_collector.matrix_service.delete.reset_mock() + matrix_garbage_collector._delete_unused_saved_matrices(unused_matrices) + matrix_garbage_collector.matrix_service.delete.assert_not_called() + @pytest.mark.unit_test def test_clean_matrices(matrix_garbage_collector: MatrixGarbageCollector): From 0b9cc1b9fa0838c795e1dc4b3b54885c19a3f601 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Fri, 11 Feb 2022 16:20:21 +0100 Subject: [PATCH 19/23] Update version Signed-off-by: Paul Bui-Quang --- antarest/__init__.py | 2 +- setup.py | 2 +- sonar-project.properties | 2 +- webapp/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/antarest/__init__.py b/antarest/__init__.py index 7d2de2d731..9d27d72231 100644 --- a/antarest/__init__.py +++ b/antarest/__init__.py @@ -1,4 +1,4 @@ -__version__ = "2.2.4" +__version__ = "2.3.0" from pathlib import Path diff --git a/setup.py b/setup.py index 5dfa8622bb..b1a24a9b50 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="AntaREST", - version="2.2.4", + version="2.3.0", description="Antares Server", long_description=long_description, long_description_content_type="text/markdown", diff --git a/sonar-project.properties b/sonar-project.properties index 30386dd3c6..2204ec5766 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -4,4 +4,4 @@ sonar.sources=antarest sonar.language=python sonar.exclusions=antarest/gui.py,antarest/main.py sonar.python.coverage.reportPaths=coverage.xml -sonar.projectVersion=2.2.4 \ No newline at end of file +sonar.projectVersion=2.3.0 \ No newline at end of file diff --git a/webapp/package.json b/webapp/package.json index 44c7c140e1..42e8415151 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "antares-web", - "version": "2.2.4", + "version": "2.3.0", "private": true, "dependencies": { "@fortawesome/fontawesome-svg-core": "~1.2.36", From 5fa0d0dc127f79bd35e00e491c8285741ced90eb Mon Sep 17 00:00:00 2001 From: Charly Bion <37449809+Hyralc@users.noreply.github.com> Date: Mon, 14 Feb 2022 21:01:07 +0100 Subject: [PATCH 20/23] Integrate new ntc model solver (#723) --- antarest/study/model.py | 3 +- .../filesystem/root/input/link/area/area.py | 28 +++- .../input/link/area/capacities/__init__.py | 0 .../input/link/area/capacities/capacities.py | 38 +++++ .../matrix_constants/link/__init__.py | 2 + .../matrix_constants/{link.py => link/v7.py} | 0 .../business/matrix_constants/link/v8.py | 3 + .../business/matrix_constants_generator.py | 30 +++- .../variantstudy/model/command/create_link.py | 95 ++++++++++-- .../variantstudy/model/command/remove_link.py | 27 +++- .../model/command/replace_matrix.py | 6 +- .../variantstudy/model/command/utils.py | 20 +++ .../model/command/utils_extractor.py | 44 +++++- resources/empty_study_820.zip | Bin 0 -> 64070 bytes .../test_matrix_garbage_collector.py | 27 +++- .../business/assets/empty_study_820.zip | Bin 0 -> 64070 bytes .../storage/business/test_arealink_manager.py | 1 - .../model/command/test_alias_decoder.py | 43 ++++++ .../model/command/test_create_link.py | 42 ++++- .../model/command/test_remove_link.py | 144 ++++++++++-------- 20 files changed, 447 insertions(+), 106 deletions(-) create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/__init__.py create mode 100644 antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py create mode 100644 antarest/study/storage/variantstudy/business/matrix_constants/link/__init__.py rename antarest/study/storage/variantstudy/business/matrix_constants/{link.py => link/v7.py} (100%) create mode 100644 antarest/study/storage/variantstudy/business/matrix_constants/link/v8.py create mode 100644 resources/empty_study_820.zip create mode 100644 tests/storage/business/assets/empty_study_820.zip create mode 100644 tests/variantstudy/model/command/test_alias_decoder.py diff --git a/antarest/study/model.py b/antarest/study/model.py index ac1446e24d..9ae2508325 100644 --- a/antarest/study/model.py +++ b/antarest/study/model.py @@ -32,9 +32,10 @@ "720": "empty_study_720.zip", "800": "empty_study_803.zip", "810": "empty_study_810.zip", + "820": "empty_study_820.zip", } -NEW_DEFAULT_STUDY_VERSION: str = "810" +NEW_DEFAULT_STUDY_VERSION: str = "820" class StudyContentStatus(enum.Enum): diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py index 539dffd613..0ccd71cfc6 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/area.py @@ -11,6 +11,9 @@ from antarest.study.storage.rawstudy.model.filesystem.matrix.input_series_matrix import ( InputSeriesMatrix, ) +from antarest.study.storage.rawstudy.model.filesystem.root.input.link.area.capacities.capacities import ( + InputLinkAreaCapacities, +) from antarest.study.storage.rawstudy.model.filesystem.root.input.link.area.properties import ( InputLinkAreaProperties, ) @@ -27,12 +30,27 @@ def __init__( self.area = area def build(self) -> TREE: - children: TREE = { - l: InputSeriesMatrix( - self.context, self.config.next_file(f"{l}.txt") + children: TREE = {} + if self.config.version < 820: + children = { + l: InputSeriesMatrix( + self.context, self.config.next_file(f"{l}.txt") + ) + for l in self.config.get_links(self.area) + } + else: + children = { + f"{l}_parameters": InputSeriesMatrix( + self.context, self.config.next_file(f"{l}_parameters.txt") + ) + for l in self.config.get_links(self.area) + } + children["capacities"] = InputLinkAreaCapacities( + self.context, + self.config.next_file("capacities"), + area=self.area, ) - for l in self.config.get_links(self.area) - } + children["properties"] = InputLinkAreaProperties( self.context, self.config.next_file("properties.ini"), diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/__init__.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py new file mode 100644 index 0000000000..c3ae6e0f43 --- /dev/null +++ b/antarest/study/storage/rawstudy/model/filesystem/root/input/link/area/capacities/capacities.py @@ -0,0 +1,38 @@ +from antarest.study.storage.rawstudy.model.filesystem.config.model import ( + FileStudyTreeConfig, +) +from antarest.study.storage.rawstudy.model.filesystem.context import ( + ContextServer, +) +from antarest.study.storage.rawstudy.model.filesystem.folder_node import ( + FolderNode, +) +from antarest.study.storage.rawstudy.model.filesystem.inode import TREE +from antarest.study.storage.rawstudy.model.filesystem.matrix.input_series_matrix import ( + InputSeriesMatrix, +) + + +class InputLinkAreaCapacities(FolderNode): + def __init__( + self, + context: ContextServer, + config: FileStudyTreeConfig, + area: str, + ): + FolderNode.__init__(self, context, config) + self.area = area + + def build(self) -> TREE: + children: TREE = {} + for area_to in self.config.get_links(self.area): + children[f"{area_to}_direct"] = InputSeriesMatrix( + self.context, + self.config.next_file(f"{area_to}_direct.txt"), + ) + children[f"{area_to}_indirect"] = InputSeriesMatrix( + self.context, + self.config.next_file(f"{area_to}_indirect.txt"), + ) + + return children diff --git a/antarest/study/storage/variantstudy/business/matrix_constants/link/__init__.py b/antarest/study/storage/variantstudy/business/matrix_constants/link/__init__.py new file mode 100644 index 0000000000..d31153ba7e --- /dev/null +++ b/antarest/study/storage/variantstudy/business/matrix_constants/link/__init__.py @@ -0,0 +1,2 @@ +from . import v7 +from . import v8 diff --git a/antarest/study/storage/variantstudy/business/matrix_constants/link.py b/antarest/study/storage/variantstudy/business/matrix_constants/link/v7.py similarity index 100% rename from antarest/study/storage/variantstudy/business/matrix_constants/link.py rename to antarest/study/storage/variantstudy/business/matrix_constants/link/v7.py diff --git a/antarest/study/storage/variantstudy/business/matrix_constants/link/v8.py b/antarest/study/storage/variantstudy/business/matrix_constants/link/v8.py new file mode 100644 index 0000000000..4ada31812a --- /dev/null +++ b/antarest/study/storage/variantstudy/business/matrix_constants/link/v8.py @@ -0,0 +1,3 @@ +link = [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] * 8760 +direct = [[1.0]] * 8760 +indirect = [[1.0]] * 8760 diff --git a/antarest/study/storage/variantstudy/business/matrix_constants_generator.py b/antarest/study/storage/variantstudy/business/matrix_constants_generator.py index 4e26d895be..dd47538dd2 100644 --- a/antarest/study/storage/variantstudy/business/matrix_constants_generator.py +++ b/antarest/study/storage/variantstudy/business/matrix_constants_generator.py @@ -20,7 +20,10 @@ PREPRO_DATA = "prepro/data" THERMAL_PREPRO_DATA = "thermals/prepro/data" THERMAL_PREPRO_MODULATION = "thermals/prepro/modulation" -LINK = "link" +LINK_V7 = "link_v7" +LINK_V8 = "link_v8" +LINK_DIRECT = "link_direct" +LINK_INDIRECT = "link_indirect" NULL_MATRIX_NAME = "null_matrix" MATRIX_PROTOCOL_PREFIX = "matrix://" @@ -65,8 +68,17 @@ def _init(self) -> None: self.hashes[THERMAL_PREPRO_MODULATION] = self.matrix_service.create( matrix_constants.thermals.prepro.modulation ) - self.hashes[LINK] = self.matrix_service.create( - matrix_constants.link.link + self.hashes[LINK_V7] = self.matrix_service.create( + matrix_constants.link.v7.link + ) + self.hashes[LINK_V8] = self.matrix_service.create( + matrix_constants.link.v8.link + ) + self.hashes[LINK_DIRECT] = self.matrix_service.create( + matrix_constants.link.v8.direct + ) + self.hashes[LINK_INDIRECT] = self.matrix_service.create( + matrix_constants.link.v8.indirect ) self.hashes[NULL_MATRIX_NAME] = self.matrix_service.create(NULL_MATRIX) @@ -115,8 +127,16 @@ def get_thermal_prepro_data(self) -> str: def get_thermal_prepro_modulation(self) -> str: return MATRIX_PROTOCOL_PREFIX + self.hashes[THERMAL_PREPRO_MODULATION] - def get_link(self) -> str: - return MATRIX_PROTOCOL_PREFIX + self.hashes[LINK] + def get_link(self, version: int) -> str: + if version < 820: + return MATRIX_PROTOCOL_PREFIX + self.hashes[LINK_V7] + return MATRIX_PROTOCOL_PREFIX + self.hashes[LINK_V8] + + def get_link_direct(self) -> str: + return MATRIX_PROTOCOL_PREFIX + self.hashes[LINK_DIRECT] + + def get_link_indirect(self) -> str: + return MATRIX_PROTOCOL_PREFIX + self.hashes[LINK_INDIRECT] def get_null_matrix(self) -> str: return MATRIX_PROTOCOL_PREFIX + self.hashes[NULL_MATRIX_NAME] diff --git a/antarest/study/storage/variantstudy/model/command/create_link.py b/antarest/study/storage/variantstudy/model/command/create_link.py index a225584614..887ed02fda 100644 --- a/antarest/study/storage/variantstudy/model/command/create_link.py +++ b/antarest/study/storage/variantstudy/model/command/create_link.py @@ -37,21 +37,21 @@ class CreateLink(ICommand): area2: str parameters: Optional[Dict[str, str]] = None series: Optional[Union[List[List[MatrixData]], str]] = None + direct: Optional[Union[List[List[MatrixData]], str]] = None + indirect: Optional[Union[List[List[MatrixData]], str]] = None def __init__(self, **data: Any) -> None: super().__init__( command_name=CommandName.CREATE_LINK, version=1, **data ) - @validator("series", always=True) + @validator("series", "direct", "indirect", always=True) def validate_series( cls, v: Optional[Union[List[List[MatrixData]], str]], values: Any ) -> Optional[Union[List[List[MatrixData]], str]]: - if v is None: - v = values["command_context"].generator_matrix_constants.get_link() - return v - else: + if v is not None: return validate_matrix(v, values) + return v def _create_link_in_config( self, area_from: str, area_to: str, study_data: FileStudyTreeConfig @@ -173,6 +173,7 @@ def _apply_config( ) def _apply(self, study_data: FileStudy) -> CommandOutput: + version = study_data.config.version output, data = self._apply_config(study_data.config) if not output.status: return output @@ -185,22 +186,75 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: study_data.tree.save( link_property, ["input", "links", area_from, "properties", area_to] ) - if self.series: - assert isinstance(self.series, str) + self.series = self.series or ( + self.command_context.generator_matrix_constants.get_link( + version=version + ) + ) + self.direct = self.direct or ( + self.command_context.generator_matrix_constants.get_link_direct() + ) + self.indirect = self.indirect or ( + self.command_context.generator_matrix_constants.get_link_indirect() + ) + + assert type(self.series) is str + if version < 820: study_data.tree.save( self.series, ["input", "links", area_from, area_to] ) + else: + study_data.tree.save( + self.series, + ["input", "links", area_from, f"{area_to}_parameters"], + ) + + study_data.tree.save( + {}, ["input", "links", area_from, "capacities"] + ) + if self.direct: + assert isinstance(self.direct, str) + study_data.tree.save( + self.direct, + [ + "input", + "links", + area_from, + "capacities", + f"{area_to}_direct", + ], + ) + + if self.indirect: + assert isinstance(self.indirect, str) + study_data.tree.save( + self.indirect, + [ + "input", + "links", + area_from, + "capacities", + f"{area_to}_indirect", + ], + ) + return output def to_dto(self) -> CommandDTO: + args = { + "area1": self.area1, + "area2": self.area2, + "parameters": self.parameters, + } + if self.series: + args["series"] = strip_matrix_protocol(self.series) + if self.direct: + args["direct"] = strip_matrix_protocol(self.direct) + if self.indirect: + args["indirect"] = strip_matrix_protocol(self.indirect) return CommandDTO( action=CommandName.CREATE_LINK.value, - args={ - "area1": self.area1, - "area2": self.area2, - "parameters": self.parameters, - "series": strip_matrix_protocol(self.series), - }, + args=args, ) def match_signature(self) -> str: @@ -222,6 +276,8 @@ def match(self, other: ICommand, equal: bool = False) -> bool: simple_match and self.parameters == other.parameters and self.series == other.series + and self.direct == other.direct + and self.indirect == other.indirect ) def revert( @@ -264,7 +320,7 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: if self.series != other.series: commands.append( ReplaceMatrix( - target=f"input/links/{area_from}/{area_to}", + target=f"@links_series/{area_from}/{area_to}", matrix=strip_matrix_protocol(other.series), command_context=self.command_context, ) @@ -272,7 +328,14 @@ def _create_diff(self, other: "ICommand") -> List["ICommand"]: return commands def get_inner_matrices(self) -> List[str]: + list_matrices = [] if self.series: assert isinstance(self.series, str) - return [strip_matrix_protocol(self.series)] - return [] + list_matrices.append(strip_matrix_protocol(self.series)) + if self.direct: + assert isinstance(self.direct, str) + list_matrices.append(strip_matrix_protocol(self.direct)) + if self.indirect: + assert isinstance(self.indirect, str) + list_matrices.append(strip_matrix_protocol(self.indirect)) + return list_matrices diff --git a/antarest/study/storage/variantstudy/model/command/remove_link.py b/antarest/study/storage/variantstudy/model/command/remove_link.py index c2a2af9c34..d1f344233a 100644 --- a/antarest/study/storage/variantstudy/model/command/remove_link.py +++ b/antarest/study/storage/variantstudy/model/command/remove_link.py @@ -1,5 +1,5 @@ import logging -from typing import Any, List, Optional, Tuple, Dict +from typing import Any, List, Tuple, Dict from antarest.study.storage.rawstudy.model.filesystem.config.model import ( FileStudyTreeConfig, @@ -83,7 +83,30 @@ def _apply(self, study_data: FileStudy) -> CommandOutput: return output area_from = data["area_from"] area_to = data["area_to"] - study_data.tree.delete(["input", "links", area_from, area_to]) + if study_data.config.version < 820: + study_data.tree.delete(["input", "links", area_from, area_to]) + else: + study_data.tree.delete( + ["input", "links", area_from, f"{area_to}_parameters"] + ) + study_data.tree.delete( + [ + "input", + "links", + area_from, + "capacities", + f"{area_to}_direct", + ] + ) + study_data.tree.delete( + [ + "input", + "links", + area_from, + "capacities", + f"{area_to}_indirect", + ] + ) study_data.tree.delete( ["input", "links", area_from, "properties", area_to] ) diff --git a/antarest/study/storage/variantstudy/model/command/replace_matrix.py b/antarest/study/storage/variantstudy/model/command/replace_matrix.py index 1f1650cca2..5ddc7ec3b9 100644 --- a/antarest/study/storage/variantstudy/model/command/replace_matrix.py +++ b/antarest/study/storage/variantstudy/model/command/replace_matrix.py @@ -1,4 +1,4 @@ -from typing import Union, List, Any, Optional, Tuple, Dict +from typing import Union, List, Any, Tuple, Dict from pydantic import validator @@ -25,6 +25,7 @@ from antarest.study.storage.variantstudy.model.command.utils import ( validate_matrix, strip_matrix_protocol, + AliasDecoder, ) from antarest.study.storage.variantstudy.model.model import CommandDTO @@ -54,6 +55,9 @@ def _apply_config( ) def _apply(self, study_data: FileStudy) -> CommandOutput: + if self.target[0] == "@": + self.target = AliasDecoder.decode(self.target, study_data) + replace_matrix_data: JSON = {} target_matrix = replace_matrix_data url = self.target.split("/") diff --git a/antarest/study/storage/variantstudy/model/command/utils.py b/antarest/study/storage/variantstudy/model/command/utils.py index 84b4501692..b1f89fadb2 100644 --- a/antarest/study/storage/variantstudy/model/command/utils.py +++ b/antarest/study/storage/variantstudy/model/command/utils.py @@ -2,6 +2,7 @@ from antarest.core.model import JSON from antarest.matrixstore.model import MatrixData +from antarest.study.storage.rawstudy.model.filesystem.factory import FileStudy from antarest.study.storage.variantstudy.business.matrix_constants_generator import ( MATRIX_PROTOCOL_PREFIX, ) @@ -56,3 +57,22 @@ def strip_matrix_protocol( if matrix_uri.startswith(MATRIX_PROTOCOL_PREFIX): return matrix_uri[len(MATRIX_PROTOCOL_PREFIX) :] return matrix_uri + + +class AliasDecoder: + @staticmethod + def links_series(alias: str, study: FileStudy) -> str: + data = alias.split("/") + area_from = data[1] + area_to = data[2] + if study.config.version < 820: + return f"input/links/{area_from}/{area_to}" + return f"input/links/{area_from}/{area_to}_parameters" + + @staticmethod + def decode(alias: str, study: FileStudy) -> str: + alias_map = {"@links_series": AliasDecoder.links_series} + alias_code = alias.split("/")[0] + if alias_code in alias_map: + return alias_map[alias_code](alias, study) + raise NotImplementedError(f"Alias {alias} not implemented") diff --git a/antarest/study/storage/variantstudy/model/command/utils_extractor.py b/antarest/study/storage/variantstudy/model/command/utils_extractor.py index e9aec001fa..6f6bd81cdd 100644 --- a/antarest/study/storage/variantstudy/model/command/utils_extractor.py +++ b/antarest/study/storage/variantstudy/model/command/utils_extractor.py @@ -206,7 +206,7 @@ def extract_link( link_data = ( links_data.get(area2) if links_data is not None - else study_tree.get(["input", "links", area1, area2]) + else study_tree.get(["input", "links", area1, "properties", area2]) ) link_config_command = UpdateConfig( target=f"input/links/{area1}/properties/{area2}", @@ -215,13 +215,43 @@ def extract_link( ) commands.append(link_command) commands.append(link_config_command) - commands.append( - self.generate_replace_matrix( - study_tree, - ["input", "links", area1, area2], - self.null_matrix_id, + if study.config.version < 820: + commands.append( + self.generate_replace_matrix( + study_tree, + ["input", "links", area1, area2], + self.null_matrix_id, + ) ) - ) + else: + commands.append( + self.generate_replace_matrix( + study_tree, + ["input", "links", area1, f"{area2}_parameters"], + self.null_matrix_id, + ) + ) + commands.append( + self.generate_replace_matrix( + study_tree, + ["input", "links", area1, "capacities", f"{area2}_direct"], + self.null_matrix_id, + ) + ) + commands.append( + self.generate_replace_matrix( + study_tree, + [ + "input", + "links", + area1, + "capacities", + f"{area2}_indirect", + ], + self.null_matrix_id, + ) + ) + return commands def _extract_cluster( diff --git a/resources/empty_study_820.zip b/resources/empty_study_820.zip new file mode 100644 index 0000000000000000000000000000000000000000..1fd8241e8b36c76cff061165736abcaebfdceb82 GIT binary patch literal 64070 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
f)E$0cI^O#0au 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

5oxlTqkbh_RD3rLY~ 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%0AT#XkpzsROgSOD;u;(5tMB8R+?!yo(88+LG4we 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 TZvcQF{o#Ka0LVsvBLMJ!8wH0I literal 0 HcmV?d00001 diff --git a/tests/matrixstore/test_matrix_garbage_collector.py b/tests/matrixstore/test_matrix_garbage_collector.py index e4f4fd3e44..fc5eae4d1c 100644 --- a/tests/matrixstore/test_matrix_garbage_collector.py +++ b/tests/matrixstore/test_matrix_garbage_collector.py @@ -134,11 +134,9 @@ def test_get_matrices_used_in_variant_studies( custom_engine=engine, session_args={"autocommit": False, "autoflush": False}, ) - matrix_garbage_collector.study_service.storage_service.variant_study_service.command_factory.command_context.generator_matrix_constants.get_link = Mock( - side_effect=["matrix1", "matrix2"] - ) with db(): study_id = "study_id" + # TODO: add series to the command blocks command_block1 = CommandBlock( study_id=study_id, command=CommandName.CREATE_LINK.value, @@ -157,9 +155,28 @@ def test_get_matrices_used_in_variant_studies( db.session.add(command_block2) db.session.commit() matrices = matrix_garbage_collector._get_variant_studies_matrices() + assert not matrices + command_block1 = CommandBlock( + study_id=study_id, + command=CommandName.CREATE_LINK.value, + args='{"area1": "area1", "area2": "area2","series": "[[1,2,3]]"}', + index=0, + version=7, + ) + command_block2 = CommandBlock( + study_id=study_id, + command=CommandName.CREATE_LINK.value, + args='{"area1": "area2", "area2": "area3","series": "[[1,2,4]]"}', + index=0, + version=7, + ) + db.session.add(command_block1) + db.session.add(command_block2) + db.session.commit() + matrices = matrix_garbage_collector._get_variant_studies_matrices() assert len(matrices) == 2 - assert "matrix1" in matrices - assert "matrix2" in matrices + assert "[[1,2,3]]" in matrices + assert "[[1,2,4]]" in matrices @pytest.mark.unit_test diff --git a/tests/storage/business/assets/empty_study_820.zip b/tests/storage/business/assets/empty_study_820.zip new file mode 100644 index 0000000000000000000000000000000000000000..1fd8241e8b36c76cff061165736abcaebfdceb82 GIT binary patch literal 64070 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


f)E$0cI^O#0au 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

5oxlTqkbh_RD3rLY~ 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%0AT#XkpzsROgSOD;u;(5tMB8R+?!yo(88+LG4we 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 TZvcQF{o#Ka0LVsvBLMJ!8wH0I literal 0 HcmV?d00001 diff --git a/tests/storage/business/test_arealink_manager.py b/tests/storage/business/test_arealink_manager.py index 28e3a3e706..26f6bd632d 100644 --- a/tests/storage/business/test_arealink_manager.py +++ b/tests/storage/business/test_arealink_manager.py @@ -195,7 +195,6 @@ def test_area_crud( "area1": "test", "area2": "test2", "parameters": None, - "series": "720054535be488afe06e985617709276147195349c34565c63af15e9068364da", }, ), ], diff --git a/tests/variantstudy/model/command/test_alias_decoder.py b/tests/variantstudy/model/command/test_alias_decoder.py new file mode 100644 index 0000000000..0822919110 --- /dev/null +++ b/tests/variantstudy/model/command/test_alias_decoder.py @@ -0,0 +1,43 @@ +from unittest.mock import Mock, patch + +import pytest + +from antarest.study.storage.variantstudy.model.command.utils import ( + AliasDecoder, +) + + +@pytest.mark.unit_test +@pytest.mark.parametrize( + "alias,expected_call", [("@links_series/a/b", "links_series")] +) +def test_alias_decoder_decode(alias: str, expected_call: str): + with patch.object(AliasDecoder, expected_call) as mocked_method: + AliasDecoder.decode(alias, study=Mock()) + mocked_method.assert_called_once() + + +@pytest.mark.unit_test +def test_alias_decoder_decode_raises_error(): + with pytest.raises(NotImplementedError): + AliasDecoder.decode("@non_existent_alias", study=Mock()) + + +@pytest.mark.unit_test +def test_alias_decoder_links_series(): + area_from = "a" + area_to = "b" + alias = f"@links_series/{area_from}/{area_to}" + file_study_mock = Mock() + + file_study_mock.config.version = 800 + assert ( + AliasDecoder.links_series(alias, file_study_mock) + == f"input/links/{area_from}/{area_to}" + ) + + file_study_mock.config.version = 830 + assert ( + AliasDecoder.links_series(alias, file_study_mock) + == f"input/links/{area_from}/{area_to}_parameters" + ) diff --git a/tests/variantstudy/model/command/test_create_link.py b/tests/variantstudy/model/command/test_create_link.py index 17fb73b66a..66e53baa9c 100644 --- a/tests/variantstudy/model/command/test_create_link.py +++ b/tests/variantstudy/model/command/test_create_link.py @@ -137,6 +137,46 @@ def test_apply( == FilteringOptions.FILTER_YEAR_BY_YEAR.value ) + empty_study.config.version = 820 + create_link_command: ICommand = CreateLink( + area1=area2_id, + area2=area3_id, + parameters={}, + command_context=command_context, + series=[[0]], + ) + output = create_link_command.apply( + study_data=empty_study, + ) + assert output.status + empty_study.config.version = 800 + + assert ( + study_path + / "input" + / "links" + / area2_id + / f"{area3_id}_parameters.txt.link" + ).exists() + assert ( + study_path + / "input" + / "links" + / area2_id + / "capacities" + / f"{area3_id}_direct.txt.link" + ).exists() + assert ( + study_path + / "input" + / "links" + / area2_id + / "capacities" + / f"{area3_id}_indirect.txt.link" + ).exists() + + # TODO:assert matrix default content : 1 column, 8760 rows, value = 1 + output = CreateLink.parse_obj( { "area1": area1_id, @@ -281,7 +321,7 @@ def test_create_diff(command_context: CommandContext): command_context=command_context, ), ReplaceMatrix( - target=f"input/links/bar/foo", + target=f"@links_series/bar/foo", matrix="b", command_context=command_context, ), diff --git a/tests/variantstudy/model/command/test_remove_link.py b/tests/variantstudy/model/command/test_remove_link.py index e8fa19c6b3..4ad322bf7e 100644 --- a/tests/variantstudy/model/command/test_remove_link.py +++ b/tests/variantstudy/model/command/test_remove_link.py @@ -1,9 +1,15 @@ -import configparser +import os +import uuid +from pathlib import Path from unittest.mock import Mock +from zipfile import ZipFile +import pytest from checksumdir import dirhash -from antarest.matrixstore.service import MatrixService +from antarest.study.storage.rawstudy.model.filesystem.config.files import ( + ConfigPathBuilder, +) from antarest.study.storage.rawstudy.model.filesystem.config.model import ( transform_name_to_id, ) @@ -11,12 +17,8 @@ from antarest.study.storage.rawstudy.model.filesystem.folder_node import ( ChildNotFoundError, ) -from antarest.study.storage.variantstudy.business.default_values import ( - FilteringOptions, - LinkProperties, -) -from antarest.study.storage.variantstudy.business.matrix_constants_generator import ( - GeneratorMatrixConstants, +from antarest.study.storage.rawstudy.model.filesystem.root.filestudytree import ( + FileStudyTree, ) from antarest.study.storage.variantstudy.model.command.create_area import ( CreateArea, @@ -24,7 +26,6 @@ from antarest.study.storage.variantstudy.model.command.create_link import ( CreateLink, ) -from antarest.study.storage.variantstudy.model.command.icommand import ICommand from antarest.study.storage.variantstudy.model.command.remove_area import ( RemoveArea, ) @@ -40,9 +41,28 @@ class TestRemoveLink: def test_validation(self, empty_study: FileStudy): pass + @staticmethod + def make_study(tmpdir: Path, version: int) -> FileStudy: + study_dir: Path = ( + Path(__file__).parent.parent.parent.parent + / "storage" + / "business" + / "assets" + / f"empty_study_{version}.zip" + ) + study_path = Path(tmpdir / str(uuid.uuid4())) + os.mkdir(study_path) + with ZipFile(study_dir) as zip_output: + zip_output.extractall(path=study_path) + config = ConfigPathBuilder.build(study_path, "1") + return FileStudy(config, FileStudyTree(Mock(), config)) + + @pytest.mark.parametrize("version", [(810), (820)]) + @pytest.mark.unit_test def test_apply( - self, empty_study: FileStudy, command_context: CommandContext + self, tmpdir: Path, command_context: CommandContext, version: int ): + empty_study = self.make_study(tmpdir, version) area1 = "Area1" area1_id = transform_name_to_id(area1) area2 = "Area2" @@ -83,62 +103,62 @@ def test_apply( dirhash(empty_study.config.study_path, "md5") == hash_before_link ) - -def test_match(command_context: CommandContext): - base = RemoveLink( - area1="foo", area2="bar", command_context=command_context - ) - other_match = RemoveLink( - area1="foo", area2="bar", command_context=command_context - ) - other_not_match = RemoveLink( - area1="foo", area2="baz", command_context=command_context - ) - other_other = RemoveArea(id="id", command_context=command_context) - assert base.match(other_match) - assert not base.match(other_not_match) - assert not base.match(other_other) - assert base.match_signature() == "remove_link%foo%bar" - assert base.get_inner_matrices() == [] - - -def test_revert(command_context: CommandContext): - base = RemoveLink( - area1="foo", area2="bar", command_context=command_context - ) - study = FileStudy(config=Mock(), tree=Mock()) - base.command_context.command_extractor.extract_link.side_effect = ( - ChildNotFoundError() - ) - base.revert([], study) - base.command_context.command_extractor.extract_link.assert_called_with( - study, "bar", "foo" - ) - assert base.revert( - [ + @pytest.mark.unit_test + def test_match(self, command_context: CommandContext): + base = RemoveLink( + area1="foo", area2="bar", command_context=command_context + ) + other_match = RemoveLink( + area1="foo", area2="bar", command_context=command_context + ) + other_not_match = RemoveLink( + area1="foo", area2="baz", command_context=command_context + ) + other_other = RemoveArea(id="id", command_context=command_context) + assert base.match(other_match) + assert not base.match(other_not_match) + assert not base.match(other_other) + assert base.match_signature() == "remove_link%foo%bar" + assert base.get_inner_matrices() == [] + + @pytest.mark.unit_test + def test_revert(self, command_context: CommandContext): + base = RemoveLink( + area1="foo", area2="bar", command_context=command_context + ) + study = FileStudy(config=Mock(), tree=Mock()) + base.command_context.command_extractor.extract_link.side_effect = ( + ChildNotFoundError() + ) + base.revert([], study) + base.command_context.command_extractor.extract_link.assert_called_with( + study, "bar", "foo" + ) + assert base.revert( + [ + CreateLink( + area1="foo", + area2="bar", + series=[[0]], + command_context=command_context, + ) + ], + None, + ) == [ CreateLink( area1="foo", area2="bar", series=[[0]], command_context=command_context, ) - ], - None, - ) == [ - CreateLink( - area1="foo", - area2="bar", - series=[[0]], - command_context=command_context, - ) - ] - + ] -def test_create_diff(command_context: CommandContext): - base = RemoveLink( - area1="foo", area2="bar", command_context=command_context - ) - other_match = RemoveLink( - area1="foo", area2="bar", command_context=command_context - ) - assert base.create_diff(other_match) == [] + @pytest.mark.unit_test + def test_create_diff(self, command_context: CommandContext): + base = RemoveLink( + area1="foo", area2="bar", command_context=command_context + ) + other_match = RemoveLink( + area1="foo", area2="bar", command_context=command_context + ) + assert base.create_diff(other_match) == [] From 740d8a5d66566efab366be86ee5c6e1b02218471 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 14 Feb 2022 21:01:40 +0100 Subject: [PATCH 21/23] Generate variant from last command when possible (#738) --- .../f5aed532a99c_add_snapshot_last_command.py | 32 ++++ .../storage/variantstudy/model/dbmodel.py | 2 + .../variantstudy/variant_study_service.py | 147 ++++++++++++++---- antarest/study/web/variant_blueprint.py | 3 +- scripts/rollback.sh | 2 +- .../variantstudy/model/test_variant_model.py | 119 +++++++++++++- webapp/src/services/api/variant.ts | 2 +- 7 files changed, 273 insertions(+), 34 deletions(-) create mode 100644 alembic/versions/f5aed532a99c_add_snapshot_last_command.py diff --git a/alembic/versions/f5aed532a99c_add_snapshot_last_command.py b/alembic/versions/f5aed532a99c_add_snapshot_last_command.py new file mode 100644 index 0000000000..0c591f9a97 --- /dev/null +++ b/alembic/versions/f5aed532a99c_add_snapshot_last_command.py @@ -0,0 +1,32 @@ +"""add_snapshot_last_command + +Revision ID: f5aed532a99c +Revises: 23ff8deddb4a +Create Date: 2022-02-08 11:15:31.796081 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f5aed532a99c' +down_revision = '23ff8deddb4a' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('variant_study_snapshot', schema=None) as batch_op: + batch_op.add_column(sa.Column('last_executed_command', sa.String(), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('variant_study_snapshot', schema=None) as batch_op: + batch_op.drop_column('last_executed_command') + + # ### end Alembic commands ### diff --git a/antarest/study/storage/variantstudy/model/dbmodel.py b/antarest/study/storage/variantstudy/model/dbmodel.py index 59aad1c021..14a16cb757 100644 --- a/antarest/study/storage/variantstudy/model/dbmodel.py +++ b/antarest/study/storage/variantstudy/model/dbmodel.py @@ -26,6 +26,8 @@ class VariantStudySnapshot(Base): # type: ignore primary_key=True, ) created_at = Column(DateTime) + last_executed_command = Column(String(), nullable=True) + __mapper_args__ = { "polymorphic_identity": "variant_study_snapshot", } diff --git a/antarest/study/storage/variantstudy/variant_study_service.py b/antarest/study/storage/variantstudy/variant_study_service.py index 8c863d7be1..e483d98d9d 100644 --- a/antarest/study/storage/variantstudy/variant_study_service.py +++ b/antarest/study/storage/variantstudy/variant_study_service.py @@ -273,6 +273,7 @@ def replace_commands( for i, command in enumerate(commands) ] ) + self._invalidate_snapshot(study) self.repository.save(metadata=study, update_modification_date=True) return str(study.id) @@ -302,6 +303,7 @@ def move_command( study.commands.insert(new_index, command) for idx in range(len(study.commands)): study.commands[idx].index = idx + self._invalidate_snapshot(study) self.repository.save(metadata=study, update_modification_date=True) def remove_command( @@ -323,6 +325,7 @@ def remove_command( study.commands.pop(index) for idx, command in enumerate(study.commands): command.index = idx + self._invalidate_snapshot(study) self.repository.save(metadata=study, update_modification_date=True) def remove_all_commands( @@ -339,6 +342,7 @@ def remove_all_commands( self._check_update_authorization(study) study.commands = [] + self._invalidate_snapshot(study) self.repository.save(metadata=study, update_modification_date=True) def update_command( @@ -365,6 +369,7 @@ def update_command( if index >= 0: study.commands[index].command = command.action study.commands[index].args = json.dumps(command.args) + self._invalidate_snapshot(study) self.repository.save(metadata=study, update_modification_date=True) def _get_variant_study( @@ -391,6 +396,16 @@ def _get_variant_study( assert_permission(params.user, study, StudyPermissionType.READ) return study + def _invalidate_snapshot( + self, variant_study: VariantStudy, save_to_db: bool = False + ) -> None: + if variant_study.snapshot: + variant_study.snapshot.last_executed_command = None + if save_to_db: + self.repository.save( + metadata=variant_study, update_modification_date=True + ) + def get_all_variants_children( self, parent_id: str, params: RequestParameters ) -> VariantTreeDTO: @@ -551,6 +566,7 @@ def generate_task( self, metadata: VariantStudy, denormalize: bool = False, + from_scratch: bool = False, ) -> str: with FileLock( str( @@ -584,6 +600,7 @@ def callback(notifier: TaskUpdateNotifier) -> TaskResult: generate_result = self._generate( variant_study_id=study_id, denormalize=denormalize, + from_scratch=from_scratch, params=RequestParameters(DEFAULT_ADMIN_USER), notifier=notifier, ) @@ -612,6 +629,7 @@ def generate( self, variant_study_id: str, denormalize: bool, + from_scratch: bool, params: RequestParameters, ) -> str: # Get variant study @@ -642,6 +660,7 @@ def _generate( variant_study_id: str, params: RequestParameters, denormalize: bool = True, + from_scratch: bool = False, notifier: TaskUpdateNotifier = noop_notifier, ) -> GenerationResultInfoDTO: logger.info(f"Generating variant study {variant_study_id}") @@ -663,39 +682,84 @@ def _generate( # Remove from cache remove_from_cache(self.cache, variant_study.id) - # Remove snapshot directory if it exist + # Get snapshot directory dest_path = self.get_study_path(variant_study) + # this indicate that the current snapshot is up to date and we can only generate from the next command + last_executed_command_index = ( + VariantStudyService._get_snapshot_last_executed_command_index( + variant_study + ) + ) + last_executed_command_index = ( + None + if ( + isinstance(parent_study, VariantStudy) + and not self.exists(parent_study) + ) + or from_scratch + else last_executed_command_index + ) + variant_study.snapshot = None self.repository.save(variant_study, update_modification_date=False) if dest_path.is_dir(): - shutil.rmtree(dest_path) - - if isinstance(parent_study, VariantStudy): - self._safe_generation(parent_study) - self.export_study_flat( - metadata=parent_study, - dest=dest_path, - outputs=False, - denormalize=False, - ) - else: - self.raw_study_service.export_study_flat( - metadata=parent_study, - dest=dest_path, - outputs=False, - denormalize=False, + # Remove snapshot directory if it exists and last snapshot is out of sync + if last_executed_command_index is None: + logger.info("Removing previous snapshot data") + shutil.rmtree(dest_path) + else: + logger.info("Using previous snapshot data") + elif last_executed_command_index is not None: + # there is no snapshot so last_command_index should be None + logger.warning( + "Previous snapshot with last_executed_command found, but no data found" ) + last_executed_command_index = None + + if last_executed_command_index is None: + # Copy parent study to dest + if isinstance(parent_study, VariantStudy): + self._safe_generation(parent_study) + self.export_study_flat( + metadata=parent_study, + dest=dest_path, + outputs=False, + denormalize=False, + ) + else: + self.raw_study_service.export_study_flat( + metadata=parent_study, + dest=dest_path, + outputs=False, + denormalize=False, + ) - # Copy parent study to dest + command_start_index = ( + last_executed_command_index + 1 + if last_executed_command_index is not None + else 0 + ) + logger.info( + f"Generating study snapshot from command index {command_start_index}" + ) results = self._generate_snapshot( - variant_study=variant_study, dest_path=dest_path, notifier=notifier + variant_study=variant_study, + dest_path=dest_path, + notifier=notifier, + from_command_index=command_start_index, ) if results.success: + last_command_index = len(variant_study.commands) - 1 variant_study.snapshot = VariantStudySnapshot( id=variant_study.id, created_at=datetime.utcnow(), + last_executed_command=variant_study.commands[ + last_command_index + ].id + if last_command_index >= 0 + else None, ) self.repository.save(variant_study) logger.info(f"Saving new snapshot for study {variant_study.id}") @@ -733,10 +797,15 @@ def _generate_study_config( return self._generate_config(metadata, parent_config) def _get_commands_and_notifier( - self, variant_study: VariantStudy, notifier: TaskUpdateNotifier + self, + variant_study: VariantStudy, + notifier: TaskUpdateNotifier, + from_index: int = 0, ) -> Tuple[List[List[ICommand]], Callable[[int, bool, str], None]]: # Generate - commands: List[List[ICommand]] = self._to_icommand(variant_study) + commands: List[List[ICommand]] = self._to_icommand( + variant_study, from_index + ) def notify( command_index: int, command_result: bool, command_message: str @@ -744,7 +813,7 @@ def notify( try: command_result_obj = CommandResultDTO( study_id=variant_study.id, - id=variant_study.commands[command_index].id, + id=variant_study.commands[from_index + command_index].id, success=command_result, message=command_message, ) @@ -765,12 +834,17 @@ def notify( return commands, notify - def _to_icommand(self, metadata: VariantStudy) -> List[List[ICommand]]: + def _to_icommand( + self, metadata: VariantStudy, from_index: int = 0 + ) -> List[List[ICommand]]: commands: List[List[ICommand]] = [] + index = 0 for command_block in metadata.commands: - commands.append( - self.command_factory.to_icommand(command_block.to_dto()) - ) + if from_index <= index: + commands.append( + self.command_factory.to_icommand(command_block.to_dto()) + ) + index += 1 return commands def _generate_config( @@ -792,10 +866,12 @@ def _generate_snapshot( variant_study: VariantStudy, dest_path: Path, notifier: TaskUpdateNotifier = noop_notifier, + from_command_index: int = 0, ) -> GenerationResultInfoDTO: - commands, notify = self._get_commands_and_notifier( - variant_study=variant_study, notifier=notifier + variant_study=variant_study, + notifier=notifier, + from_index=from_command_index, ) return self.generator.generate( commands, dest_path, variant_study, notifier=notify @@ -899,6 +975,21 @@ def _safe_generation( f"Error while generating {metadata.id}" ) + @staticmethod + def _get_snapshot_last_executed_command_index( + study: VariantStudy, + ) -> Optional[int]: + if study.snapshot and study.snapshot.last_executed_command: + last_executed_command_index = [ + command.id for command in study.commands + ].index(study.snapshot.last_executed_command) + return ( + last_executed_command_index + if last_executed_command_index >= 0 + else None + ) + return None + def get_raw( self, metadata: VariantStudy, use_cache: bool = True ) -> FileStudy: diff --git a/antarest/study/web/variant_blueprint.py b/antarest/study/web/variant_blueprint.py index 6a5af271e4..e5df692fa9 100644 --- a/antarest/study/web/variant_blueprint.py +++ b/antarest/study/web/variant_blueprint.py @@ -336,6 +336,7 @@ def remove_all_commands( def generate_variant( uuid: str, denormalize: bool = False, + from_scratch: bool = False, current_user: JWTUser = Depends(auth.get_current_user), ) -> str: logger.info( @@ -345,7 +346,7 @@ def generate_variant( params = RequestParameters(user=current_user) sanitized_uuid = sanitize_uuid(uuid) return variant_study_service.generate( - sanitized_uuid, denormalize, params + sanitized_uuid, denormalize, from_scratch, params ) @bp.get( diff --git a/scripts/rollback.sh b/scripts/rollback.sh index 92cc82524f..a881855d86 100755 --- a/scripts/rollback.sh +++ b/scripts/rollback.sh @@ -4,5 +4,5 @@ CURDIR=$(cd `dirname $0` && pwd) BASEDIR=`dirname $CURDIR` cd $BASEDIR -alembic downgrade 298aecf6ea40 +alembic downgrade 23ff8deddb4a cd - diff --git a/tests/variantstudy/model/test_variant_model.py b/tests/variantstudy/model/test_variant_model.py index 7a87a46443..f635f2d7b6 100644 --- a/tests/variantstudy/model/test_variant_model.py +++ b/tests/variantstudy/model/test_variant_model.py @@ -1,15 +1,19 @@ -from unittest.mock import Mock +import os +from pathlib import Path +from unittest.mock import Mock, ANY from sqlalchemy import create_engine from antarest.core.cache.business.local_chache import LocalCache from antarest.core.config import Config, StorageConfig, WorkspaceConfig from antarest.core.jwt import JWTUser, JWTGroup +from antarest.core.model import PublicMode from antarest.core.persistence import Base from antarest.core.requests import RequestParameters from antarest.core.roles import RoleType from antarest.core.utils.fastapi_sqlalchemy import DBSessionMiddleware, db from antarest.study.model import DEFAULT_WORKSPACE_NAME, RawStudy +from antarest.study.storage.variantstudy.model.dbmodel import VariantStudy from antarest.study.storage.variantstudy.model.model import ( CommandDTO, GenerationResultInfoDTO, @@ -31,7 +35,7 @@ ) -def test_commands_service() -> VariantStudyService: +def test_commands_service(tmp_path: Path) -> VariantStudyService: engine = create_engine("sqlite:///:memory:", echo=True) Base.metadata.create_all(engine) DBSessionMiddleware( @@ -48,7 +52,9 @@ def test_commands_service() -> VariantStudyService: study_factory=Mock(), config=Config( storage=StorageConfig( - workspaces={DEFAULT_WORKSPACE_NAME: WorkspaceConfig()} + workspaces={ + DEFAULT_WORKSPACE_NAME: WorkspaceConfig(path=tmp_path) + } ) ), repository=repository, @@ -123,3 +129,110 @@ def test_commands_service() -> VariantStudyService: results = service._generate(saved_id, SADMIN, False) assert results == expected_result assert study.snapshot.id == study.id + + +def test_smart_generation(tmp_path: Path) -> None: + engine = create_engine( + "sqlite:///:memory:", + echo=True, + connect_args={"check_same_thread": False}, + ) + Base.metadata.create_all(engine) + DBSessionMiddleware( + Mock(), + custom_engine=engine, + session_args={"autocommit": False, "autoflush": False}, + ) + repository = VariantStudyRepository(LocalCache()) + service = VariantStudyService( + raw_study_service=Mock(), + cache=Mock(), + task_service=Mock(), + command_factory=Mock(), + study_factory=Mock(), + config=Config( + storage=StorageConfig( + workspaces={ + DEFAULT_WORKSPACE_NAME: WorkspaceConfig(path=tmp_path) + } + ) + ), + repository=repository, + event_bus=Mock(), + patch_service=Mock(), + ) + service.generator = Mock() + service.generator.generate.side_effect = [ + GenerationResultInfoDTO(success=True, details=[]), + GenerationResultInfoDTO(success=True, details=[]), + GenerationResultInfoDTO(success=True, details=[]), + GenerationResultInfoDTO(success=True, details=[]), + ] + + def export_flat( + metadata: VariantStudy, + dest: Path, + outputs: bool = True, + denormalize: bool = True, + ) -> None: + dest.mkdir(parents=True) + + service.raw_study_service.export_study_flat.side_effect = export_flat + + with db(): + origin_id = "base-study" + origin_study = RawStudy( + id=origin_id, name="my-study", workspace=DEFAULT_WORKSPACE_NAME + ) + repository.save(origin_study) + + variant_id = service.create_variant_study( + origin_id, "my variant", SADMIN + ) + service.append_command( + variant_id, + CommandDTO(action="some action", args={"some-args": "value"}), + SADMIN, + ) + service._generate(variant_id, SADMIN, False) + service.generator.generate.assert_called_with( + [ANY], ANY, ANY, notifier=ANY + ) + + service._generate(variant_id, SADMIN, False) + service.generator.generate.assert_called_with( + [], ANY, ANY, notifier=ANY + ) + + service.append_command( + variant_id, + CommandDTO( + action="some other action", args={"some-args": "value"} + ), + SADMIN, + ) + assert ( + service._get_variant_study( + variant_id, SADMIN + ).snapshot.last_executed_command + is not None + ) + service._generate(variant_id, SADMIN, False) + service.generator.generate.assert_called_with( + [ANY], ANY, ANY, notifier=ANY + ) + + service.replace_commands( + variant_id, + [ + CommandDTO(action="some action", args={"some-args": "value"}), + CommandDTO( + action="some other action 2", args={"some-args": "value"} + ), + ], + SADMIN, + ) + service._generate(variant_id, SADMIN, False) + service.generator.generate.assert_called_with( + [ANY, ANY], ANY, ANY, notifier=ANY + ) diff --git a/webapp/src/services/api/variant.ts b/webapp/src/services/api/variant.ts index 852767cdee..d125090fe5 100644 --- a/webapp/src/services/api/variant.ts +++ b/webapp/src/services/api/variant.ts @@ -63,7 +63,7 @@ export const getCommands = async (studyId: string): Promise> = }; export const applyCommands = async (studyId: string, denormalize = false): Promise => { - const res = await client.put(`/v1/studies/${studyId}/generate?denormalize=${denormalize}`); + const res = await client.put(`/v1/studies/${studyId}/generate?denormalize=${denormalize}&from_scratch=true`); return res.data; }; From ae62f1d9f9b00531315b79e0bde5c8116139c707 Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 21 Feb 2022 15:02:35 +0100 Subject: [PATCH 22/23] Fix output download Signed-off-by: Paul Bui-Quang --- antarest/study/service.py | 14 +++++++++++--- antarest/study/web/studies_blueprint.py | 1 + tests/storage/test_service.py | 6 +++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/antarest/study/service.py b/antarest/study/service.py index d941f93986..6a26b36e4a 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -1,5 +1,6 @@ import base64 import io +import json import logging import os import shutil @@ -12,7 +13,7 @@ from fastapi import HTTPException from markupsafe import escape -from starlette.responses import FileResponse +from starlette.responses import FileResponse, Response from antarest.core.config import Config from antarest.core.exceptions import ( @@ -897,7 +898,7 @@ def download_outputs( filetype: ExportFormat, params: RequestParameters, tmp_export_file: Optional[Path] = None, - ) -> Union[MatrixAggregationResult, FileDownloadTaskDTO, FileResponse]: + ) -> Union[Response, FileDownloadTaskDTO, FileResponse]: """ Download outputs Args: @@ -977,7 +978,14 @@ def export_task(notifier: TaskUpdateNotifier) -> TaskResult: media_type=filetype, ) - return matrix + json_response = json.dumps( + matrix.dict(), + ensure_ascii=False, + allow_nan=True, + indent=None, + separators=(",", ":"), + ).encode("utf-8") + return Response(content=json_response, media_type="application/json") def get_study_sim_result( self, study_id: str, params: RequestParameters diff --git a/antarest/study/web/studies_blueprint.py b/antarest/study/web/studies_blueprint.py index 555f968642..bd6fc53bfd 100644 --- a/antarest/study/web/studies_blueprint.py +++ b/antarest/study/web/studies_blueprint.py @@ -1,4 +1,5 @@ import io +import json import logging from http import HTTPStatus from pathlib import Path diff --git a/tests/storage/test_service.py b/tests/storage/test_service.py index faa0c92b0a..5b5380d396 100644 --- a/tests/storage/test_service.py +++ b/tests/storage/test_service.py @@ -529,7 +529,7 @@ def test_download_output() -> None: filetype=ExportFormat.JSON, params=RequestParameters(JWTUser(id=0, impersonator=0, type="users")), ) - assert result == res_matrix + assert MatrixAggregationResult.parse_raw(result.body) == res_matrix # AREA TYPE - ZIP & TASK export_file_download = FileDownload( @@ -582,7 +582,7 @@ def test_download_output() -> None: filetype=ExportFormat.JSON, params=RequestParameters(JWTUser(id=0, impersonator=0, type="users")), ) - assert result == res_matrix + assert MatrixAggregationResult.parse_raw(result.body) == res_matrix # CLUSTER TYPE input_data.type = StudyDownloadType.DISTRICT @@ -606,7 +606,7 @@ def test_download_output() -> None: filetype=ExportFormat.JSON, params=RequestParameters(JWTUser(id=0, impersonator=0, type="users")), ) - assert result == res_matrix + assert MatrixAggregationResult.parse_raw(result.body) == res_matrix @pytest.mark.unit_test From aeca946a79bf0fb99ff0435c43461d09e86ba50a Mon Sep 17 00:00:00 2001 From: Paul Bui-Quang Date: Mon, 21 Feb 2022 09:40:21 +0100 Subject: [PATCH 23/23] Add db pool recycle conf Signed-off-by: Paul Bui-Quang --- antarest/core/config.py | 2 ++ antarest/main.py | 8 +++++--- resources/application.yaml | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/antarest/core/config.py b/antarest/core/config.py index dbf2fd5236..31a6b200ac 100644 --- a/antarest/core/config.py +++ b/antarest/core/config.py @@ -88,6 +88,7 @@ class DbConfig: db_url: str = "" db_admin_url: Optional[str] = None db_connect_timeout: int = 10 + pool_recycle: Optional[int] = None @staticmethod def from_dict(data: JSON) -> "DbConfig": @@ -95,6 +96,7 @@ def from_dict(data: JSON) -> "DbConfig": db_admin_url=data.get("admin_url", None), db_url=data.get("url", ""), db_connect_timeout=data.get("db_connect_timeout", 10), + pool_recycle=data.get("pool_recycle", None), ) diff --git a/antarest/main.py b/antarest/main.py index dfeec0af23..e0c406b160 100644 --- a/antarest/main.py +++ b/antarest/main.py @@ -153,10 +153,12 @@ def init_db( else: connect_args["connect_timeout"] = config.db.db_connect_timeout + extra = {} + if config.db.pool_recycle: + extra["pool_recycle"] = config.db.pool_recycle + engine = create_engine( - config.db.db_url, - echo=config.debug, - connect_args=connect_args, + config.db.db_url, echo=config.debug, connect_args=connect_args, **extra ) session_args = { diff --git a/resources/application.yaml b/resources/application.yaml index f32fc3a4d8..99e61c887e 100644 --- a/resources/application.yaml +++ b/resources/application.yaml @@ -17,6 +17,7 @@ security: db: url: "sqlite:///database.db" + #pool_recycle: storage: tmp_dir: /tmp