From fbf67e4bf214bb94d87a9fb3b5451362fb59d6cc Mon Sep 17 00:00:00 2001 From: Slyke Date: Tue, 22 Dec 2020 00:00:51 -0800 Subject: [PATCH 001/142] Fixed sudo issue inside bash functions --- menu.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/menu.sh b/menu.sh index 14a6dfaf7..a444fb3c8 100755 --- a/menu.sh +++ b/menu.sh @@ -139,8 +139,8 @@ function install_python3_and_deps() { CURR_PYTHON_VER="${1:-Unknown}" CURR_PYAML_VER="${2:-Unknown}" if (whiptail --title "Python 3 and Dependencies" --yesno "Python 3.6.9 or later (Current = $CURR_PYTHON_VER), ruamel.yaml 0.16.12 or later (Current = $CURR_PYAML_VER), blessed and pip3 are required for IOTstack to function correctly. Install these now?" 20 78); then - sudo apt update - sudo apt install -y python3-pip python3-dev + sudo -E apt update + sudo -E apt install -y python3-pip python3-dev if [ $? -eq 0 ]; then PYTHON_VERSION_GOOD="true" else @@ -159,11 +159,11 @@ function install_python3_and_deps() { } function install_docker() { - sudo bash ./scripts/install_docker.sh install + sudo -E bash ./scripts/install_docker.sh install } function update_docker() { - sudo bash ./scripts/install_docker.sh upgrade + sudo -E bash ./scripts/install_docker.sh upgrade } function update_project() { @@ -241,14 +241,14 @@ function do_env_setup() { echo "User is NOT in 'bluetooth' group. Adding:" >&2 echo "sudo usermod -G bluetooth -a $USER" >&2 echo "You will need to restart your system before the changes take effect." - sudo usermod -G "bluetooth" -a $USER + sudo -E usermod -G "bluetooth" -a $USER fi if [ ! "$(user_in_group docker)" == "true" ]; then echo "User is NOT in 'docker' group. Adding:" >&2 echo "sudo usermod -G docker -a $USER" >&2 echo "You will need to restart your system before the changes take effect." - sudo usermod -G "docker" -a $USER + sudo -E usermod -G "docker" -a $USER fi } @@ -304,14 +304,14 @@ function do_docker_checks() { echo "User is NOT in 'bluetooth' group. Adding:" >&2 echo "sudo usermod -G bluetooth -a $USER" >&2 echo "You will need to restart your system before the changes take effect." - sudo usermod -G "bluetooth" -a $USER + sudo -E usermod -G "bluetooth" -a $USER fi if [ ! "$(user_in_group docker)" == "true" ]; then echo "User is NOT in 'docker' group. Adding:" >&2 echo "sudo usermod -G docker -a $USER" >&2 echo "You will need to restart your system before the changes take effect." - sudo usermod -G "docker" -a $USER + sudo -E usermod -G "docker" -a $USER fi install_docker else @@ -368,7 +368,7 @@ else do_project_checks do_env_checks do_python3_checks - sudo echo "Please enter sudo pasword if prompted" + echo "Please enter sudo pasword if prompted" do_docker_checks if [[ "$DOCKER_VERSION_GOOD" == "true" ]] && \ @@ -392,20 +392,20 @@ do ;; --no-check) echo "" ;; - --run-env-setup) # Sudo cannot be run from inside functions. + --run-env-setup) # Sudo cannot be run from inside functions without -E flag. echo "Setting up environment:" if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then echo "User is NOT in 'bluetooth' group. Adding:" >&2 - echo "sudo usermod -G bluetooth -a $USER" >&2 + echo "sudo -E usermod -G bluetooth -a $USER" >&2 echo "You will need to restart your system before the changes take effect." - sudo usermod -G "bluetooth" -a $USER + sudo -E usermod -G "bluetooth" -a $USER fi if [ ! "$(user_in_group docker)" == "true" ]; then echo "User is NOT in 'docker' group. Adding:" >&2 - echo "sudo usermod -G docker -a $USER" >&2 + echo "sudo -E usermod -G docker -a $USER" >&2 echo "You will need to restart your system before the changes take effect." - sudo usermod -G "docker" -a $USER + sudo -E usermod -G "docker" -a $USER fi ;; --encoding) ENCODING_TYPE=$2 From 3f1ed1b84d853569dc7d4ba906e4811e1791297e Mon Sep 17 00:00:00 2001 From: Slyke Date: Fri, 15 Jan 2021 11:13:36 -0800 Subject: [PATCH 002/142] Added broken wui menu --- .internal/.dockerignore | 1 + .internal/.gitignore | 39 + .internal/IOTstack.postman_collection.json | 757 + .internal/api.Dockerfile | 10 + .internal/api/index.js | 1 + .internal/api/package-lock.json | 1542 ++ .internal/api/package.json | 20 + .internal/api/src/.tmp/.gitignore | 2 + .internal/api/src/controllers/build.js | 561 + .internal/api/src/controllers/configs.js | 139 + .internal/api/src/controllers/health.js | 23 + .internal/api/src/controllers/templates.js | 412 + .internal/api/src/httpInit.js | 30 + .internal/api/src/index.js | 110 + .internal/api/src/logger.js | 13 + .internal/api/src/middlewares/cors.js | 23 + .internal/api/src/middlewares/index.js | 19 + .internal/api/src/routes/build.js | 29 + .internal/api/src/routes/configs.js | 45 + .internal/api/src/routes/health.js | 25 + .internal/api/src/routes/index.js | 17 + .internal/api/src/routes/templates.js | 69 + .internal/api/src/services/builds.js | 70 + .internal/api/src/services/templates.js | 67 + .internal/api/src/services/zip.js | 82 + .internal/api/src/settings.js | 34 + .internal/api/src/utils/date.js | 11 + .internal/api/src/utils/fsUtils.js | 45 + .internal/api/src/utils/interpolate.js | 8 + .internal/api/src/utils/networkUtils.js | 24 + .internal/api/src/utils/pad.js | 18 + .internal/api/src/views/build.js | 117 + .internal/api/src/views/configs.js | 110 + .internal/api/src/views/health.js | 23 + .internal/api/src/views/templates.js | 207 + {scripts => .internal/cli}/backup_restore.py | 0 {scripts => .internal/cli}/buildstack_menu.py | 0 {scripts => .internal/cli}/docker_commands.py | 0 {scripts => .internal/cli}/menu_main.py | 0 {scripts => .internal/cli}/misc_commands.py | 0 {scripts => .internal/cli}/native_installs.py | 0 .internal/ctrl_api.sh | 40 + .internal/ctrl_wui.sh | 28 + .internal/docker_menu.sh | 11 + .internal/saved_builds/.gitignore | 4 + .../networks/iotstack_nw/template.yml | 9 + .../iotstack_nw_internal/template.yml | 9 + .../networks/nextcloud_internal/template.yml | 4 + .../templates/networks/vpn_nw/template.yml | 8 + .internal/templates/scripts/bootstrap.js | 49 + .../templates/scripts/build_installer.js | 168 + .internal/templates/services/adminer/build.js | 73 + .../templates/services/adminer/config.js | 45 + .../templates/services/adminer/template.yml | 12 + .../templates/services/dashmachine/build.js | 73 + .../templates/services/dashmachine/config.js | 45 + .../services/dashmachine/template.yml | 8 + .../templates/services/domoticz/build.js | 73 + .../templates/services/domoticz/config.js | 45 + .../templates/services/domoticz/template.yml | 19 + .internal/templates/services/dozzle/build.js | 73 + .internal/templates/services/dozzle/config.js | 45 + .../templates/services/dozzle/template.yml | 13 + .../templates/services/espruinohub/build.js | 73 + .../templates/services/espruinohub/config.js | 42 + .../services/espruinohub/template.yml | 10 + .internal/templates/services/gitea/build.js | 102 + .internal/templates/services/gitea/config.js | 45 + .../templates/services/gitea/template.yml | 21 + .internal/templates/services/grafana/build.js | 73 + .../templates/services/grafana/config.js | 56 + .../templates/services/grafana/template.yml | 28 + .../templates/services/heimdall/build.js | 73 + .../templates/services/heimdall/config.js | 48 + .../templates/services/heimdall/template.yml | 13 + .../services/home_assistant/build.js | 102 + .../services/home_assistant/config.js | 45 + .../services/home_assistant/template.yml | 14 + .internal/templates/services/homer/build.js | 102 + .internal/templates/services/homer/config.js | 45 + .../templates/services/homer/template.yml | 11 + .../templates/services/influxdb/build.js | 73 + .../templates/services/influxdb/config.js | 51 + .../templates/services/influxdb/template.yml | 26 + .internal/templates/services/mariadb/build.js | 102 + .../templates/services/mariadb/config.js | 64 + .../templates/services/mariadb/template.yml | 23 + .../templates/services/mosquitto/build.js | 95 + .../templates/services/mosquitto/config.js | 43 + .../mosquitto/serviceFiles/mosquitto.conf | 14 + .../templates/services/mosquitto/template.yml | 19 + .../templates/services/motioneye/build.js | 73 + .../templates/services/motioneye/config.js | 46 + .../templates/services/motioneye/template.yml | 19 + .internal/templates/services/nodered/build.js | 118 + .../nodered/buildFiles/Dockerfile.template | 7 + .../services/nodered/buildFiles/addons.json | 62 + .../templates/services/nodered/config.js | 45 + .../templates/services/nodered/template.yml | 24 + .internal/templates/services/openhab/build.js | 73 + .../templates/services/openhab/config.js | 59 + .../templates/services/openhab/template.yml | 30 + .internal/templates/services/pihole/build.js | 102 + .internal/templates/services/pihole/config.js | 67 + .../templates/services/pihole/template.yml | 44 + .internal/templates/services/plex/build.js | 107 + .internal/templates/services/plex/config.js | 51 + .../templates/services/plex/template.yml | 21 + .../templates/services/portainer/build.js | 78 + .../templates/services/portainer/config.js | 45 + .../templates/services/portainer/template.yml | 15 + .../services/portainer_agent/build.js | 73 + .../services/portainer_agent/config.js | 43 + .../services/portainer_agent/template.yml | 9 + .../templates/services/portainer_ce/build.js | 102 + .../templates/services/portainer_ce/config.js | 45 + .../services/portainer_ce/template.yml | 10 + .../templates/services/postgres/build.js | 102 + .../templates/services/postgres/config.js | 56 + .../templates/services/postgres/template.yml | 18 + .../templates/services/qbittorrent/build.js | 107 + .../templates/services/qbittorrent/config.js | 51 + .../services/qbittorrent/template.yml | 16 + .../templates/services/tasmoadmin/build.js | 102 + .../templates/services/tasmoadmin/config.js | 45 + .../services/tasmoadmin/template.yml | 14 + .../templates/services/timescaledb/build.js | 102 + .../templates/services/timescaledb/config.js | 56 + .../services/timescaledb/template.yml | 18 + .../templates/services/transmission/build.js | 112 + .../templates/services/transmission/config.js | 51 + .../services/transmission/template.yml | 22 + .../templates/services/zigbee2mqtt/build.js | 102 + .../templates/services/zigbee2mqtt/config.js | 46 + .../services/zigbee2mqtt/template.yml | 16 + .internal/wui.Dockerfile | 10 + .internal/wui/.eslintcache | 1 + .internal/wui/.gitignore | 23 + .internal/wui/README.md | 68 + .internal/wui/package-lock.json | 17035 ++++++++++++++++ .internal/wui/package.json | 41 + .internal/wui/public/favicon.ico | Bin 0 -> 3585 bytes .internal/wui/public/index.html | 43 + .internal/wui/public/logo192.png | Bin 0 -> 4153 bytes .internal/wui/public/logo512.png | Bin 0 -> 12066 bytes .internal/wui/public/manifest.json | 25 + .internal/wui/public/robots.txt | 2 + .internal/wui/src/App.css | 39 + .internal/wui/src/App.js | 30 + .../wui/src/actions/buildStack.action.js | 15 + .../src/actions/checkBuildIssues.action.js | 15 + .../wui/src/actions/downloadBuild.action.js | 16 + .../src/actions/getBuildHistoryList.action.js | 15 + .../actions/getNetworkTemplateList.action.js | 15 + .internal/wui/src/actions/getScript.action.js | 16 + .../actions/getServiceConfigOptions.action.js | 16 + .../src/actions/getServiceMetadata.action.js | 16 + .../actions/getServiceTemplateList.action.js | 15 + .../src/actions/getServiceTemplates.action.js | 15 + .../src/actions/updateFilterTags.action.js | 27 + .../actions/updateSelectedServices.action.js | 27 + .internal/wui/src/config.js | 6 + .internal/wui/src/constants.js | 10 + .../BuildSidebar/build-sidebar.module.css | 11 + .../wui/src/features/BuildSidebar/index.jsx | 331 + .internal/wui/src/features/Sidebar/index.js | 165 + .../features/buildCompletedModal/index.jsx | 130 + .../build-history-grid-item.module.css | 34 + .../features/buildHistoryGridItem/index.jsx | 129 + .internal/wui/src/features/counter/Counter.js | 60 + .../src/features/counter/Counter.module.css | 74 + .../src/features/serviceConfigModal/index.jsx | 129 + .../serviceUiControls/general/logging.jsx | 64 + .../general/networkConfig.jsx | 97 + .../serviceUiControls/general/portConfig.jsx | 91 + .../src/features/serviceUiControls/index.js | 9 + .../src/features/servicesGridItem/index.jsx | 354 + .../services-grid-item.module.css | 34 + .internal/wui/src/index.css | 13 + .internal/wui/src/index.js | 15 + .internal/wui/src/logo.svg | 1 + .../wui/src/pages/buildHistory/index.jsx | 63 + .internal/wui/src/pages/help/index.jsx | 13 + .internal/wui/src/pages/mainBuild/index.jsx | 111 + .internal/wui/src/pages/notFound/index.js | 13 + .internal/wui/src/pages/scripts/index.jsx | 13 + .../wui/src/reducers/buildStackReducer.js | 39 + .internal/wui/src/reducers/counter.js | 42 + .../reducers/getBuildHistoryListReducer.js | 39 + .../wui/src/reducers/getBuildIssuesReducer.js | 39 + .../reducers/getNetworkTemplateListReducer.js | 39 + .../src/reducers/getScriptTemplatesReducer.js | 57 + .../getServiceConfigOptionsReducer.js | 61 + .../src/reducers/getServiceMetadataReducer.js | 61 + .../reducers/getServiceTemplateListReducer.js | 39 + .../reducers/getServiceTemplatesReducer.js | 40 + .internal/wui/src/reducers/index.js | 37 + .../middlewares/asyncDispatchMiddleware.js | 25 + .../reducers/middlewares/promiseMiddleware.js | 29 + .../updateSelectedFilterTagsReducer.js | 43 + .../reducers/updateSelectedServicesReducer.js | 43 + .internal/wui/src/router.jsx | 48 + .internal/wui/src/services/builds.js | 160 + .internal/wui/src/services/configs.js | 66 + .internal/wui/src/services/templates.js | 134 + .internal/wui/src/utils/buildOptionSync.js | 90 + .../wui/src/utils/configOptionLoader.jsx | 43 + .internal/wui/src/utils/parsers.js | 53 + .../deps/__pycache__/__init__.cpython-36.pyc | Bin 147 -> 0 bytes scripts/deps/__pycache__/chars.cpython-36.pyc | Bin 1563 -> 0 bytes .../common_functions.cpython-36.pyc | Bin 2648 -> 0 bytes .../deps/__pycache__/consts.cpython-36.pyc | Bin 580 -> 0 bytes .../__pycache__/version_check.cpython-36.pyc | Bin 839 -> 0 bytes scripts/deps/buildstack.py | 106 - {duck => scripts/host_installers}/duck.sh | 0 .../host_installers}/hassio_supervisor.sh | 0 .../{ => host_installers}/install_docker.sh | 0 .../{ => host_installers}/install_log2ram.sh | 0 .../{ => host_installers}/install_ssh_keys.sh | 0 .../host_installers}/rpieasy.sh | 0 .../host_installers}/rtl_433.sh | 0 221 files changed, 30096 insertions(+), 106 deletions(-) create mode 100644 .internal/.dockerignore create mode 100644 .internal/.gitignore create mode 100644 .internal/IOTstack.postman_collection.json create mode 100644 .internal/api.Dockerfile create mode 100644 .internal/api/index.js create mode 100644 .internal/api/package-lock.json create mode 100644 .internal/api/package.json create mode 100644 .internal/api/src/.tmp/.gitignore create mode 100644 .internal/api/src/controllers/build.js create mode 100644 .internal/api/src/controllers/configs.js create mode 100644 .internal/api/src/controllers/health.js create mode 100644 .internal/api/src/controllers/templates.js create mode 100644 .internal/api/src/httpInit.js create mode 100644 .internal/api/src/index.js create mode 100644 .internal/api/src/logger.js create mode 100644 .internal/api/src/middlewares/cors.js create mode 100644 .internal/api/src/middlewares/index.js create mode 100644 .internal/api/src/routes/build.js create mode 100644 .internal/api/src/routes/configs.js create mode 100644 .internal/api/src/routes/health.js create mode 100644 .internal/api/src/routes/index.js create mode 100644 .internal/api/src/routes/templates.js create mode 100644 .internal/api/src/services/builds.js create mode 100644 .internal/api/src/services/templates.js create mode 100644 .internal/api/src/services/zip.js create mode 100644 .internal/api/src/settings.js create mode 100644 .internal/api/src/utils/date.js create mode 100644 .internal/api/src/utils/fsUtils.js create mode 100644 .internal/api/src/utils/interpolate.js create mode 100644 .internal/api/src/utils/networkUtils.js create mode 100644 .internal/api/src/utils/pad.js create mode 100644 .internal/api/src/views/build.js create mode 100644 .internal/api/src/views/configs.js create mode 100644 .internal/api/src/views/health.js create mode 100644 .internal/api/src/views/templates.js rename {scripts => .internal/cli}/backup_restore.py (100%) mode change 100755 => 100644 rename {scripts => .internal/cli}/buildstack_menu.py (100%) mode change 100755 => 100644 rename {scripts => .internal/cli}/docker_commands.py (100%) mode change 100755 => 100644 rename {scripts => .internal/cli}/menu_main.py (100%) mode change 100755 => 100644 rename {scripts => .internal/cli}/misc_commands.py (100%) mode change 100755 => 100644 rename {scripts => .internal/cli}/native_installs.py (100%) mode change 100755 => 100644 create mode 100644 .internal/ctrl_api.sh create mode 100644 .internal/ctrl_wui.sh create mode 100644 .internal/docker_menu.sh create mode 100644 .internal/saved_builds/.gitignore create mode 100644 .internal/templates/networks/iotstack_nw/template.yml create mode 100644 .internal/templates/networks/iotstack_nw_internal/template.yml create mode 100644 .internal/templates/networks/nextcloud_internal/template.yml create mode 100644 .internal/templates/networks/vpn_nw/template.yml create mode 100644 .internal/templates/scripts/bootstrap.js create mode 100644 .internal/templates/scripts/build_installer.js create mode 100644 .internal/templates/services/adminer/build.js create mode 100644 .internal/templates/services/adminer/config.js create mode 100644 .internal/templates/services/adminer/template.yml create mode 100644 .internal/templates/services/dashmachine/build.js create mode 100644 .internal/templates/services/dashmachine/config.js create mode 100644 .internal/templates/services/dashmachine/template.yml create mode 100644 .internal/templates/services/domoticz/build.js create mode 100644 .internal/templates/services/domoticz/config.js create mode 100644 .internal/templates/services/domoticz/template.yml create mode 100644 .internal/templates/services/dozzle/build.js create mode 100644 .internal/templates/services/dozzle/config.js create mode 100644 .internal/templates/services/dozzle/template.yml create mode 100644 .internal/templates/services/espruinohub/build.js create mode 100644 .internal/templates/services/espruinohub/config.js create mode 100644 .internal/templates/services/espruinohub/template.yml create mode 100644 .internal/templates/services/gitea/build.js create mode 100644 .internal/templates/services/gitea/config.js create mode 100644 .internal/templates/services/gitea/template.yml create mode 100644 .internal/templates/services/grafana/build.js create mode 100644 .internal/templates/services/grafana/config.js create mode 100644 .internal/templates/services/grafana/template.yml create mode 100644 .internal/templates/services/heimdall/build.js create mode 100644 .internal/templates/services/heimdall/config.js create mode 100644 .internal/templates/services/heimdall/template.yml create mode 100644 .internal/templates/services/home_assistant/build.js create mode 100644 .internal/templates/services/home_assistant/config.js create mode 100644 .internal/templates/services/home_assistant/template.yml create mode 100644 .internal/templates/services/homer/build.js create mode 100644 .internal/templates/services/homer/config.js create mode 100644 .internal/templates/services/homer/template.yml create mode 100644 .internal/templates/services/influxdb/build.js create mode 100644 .internal/templates/services/influxdb/config.js create mode 100644 .internal/templates/services/influxdb/template.yml create mode 100644 .internal/templates/services/mariadb/build.js create mode 100644 .internal/templates/services/mariadb/config.js create mode 100644 .internal/templates/services/mariadb/template.yml create mode 100644 .internal/templates/services/mosquitto/build.js create mode 100644 .internal/templates/services/mosquitto/config.js create mode 100644 .internal/templates/services/mosquitto/serviceFiles/mosquitto.conf create mode 100644 .internal/templates/services/mosquitto/template.yml create mode 100644 .internal/templates/services/motioneye/build.js create mode 100644 .internal/templates/services/motioneye/config.js create mode 100644 .internal/templates/services/motioneye/template.yml create mode 100644 .internal/templates/services/nodered/build.js create mode 100644 .internal/templates/services/nodered/buildFiles/Dockerfile.template create mode 100644 .internal/templates/services/nodered/buildFiles/addons.json create mode 100644 .internal/templates/services/nodered/config.js create mode 100644 .internal/templates/services/nodered/template.yml create mode 100644 .internal/templates/services/openhab/build.js create mode 100644 .internal/templates/services/openhab/config.js create mode 100644 .internal/templates/services/openhab/template.yml create mode 100644 .internal/templates/services/pihole/build.js create mode 100644 .internal/templates/services/pihole/config.js create mode 100644 .internal/templates/services/pihole/template.yml create mode 100644 .internal/templates/services/plex/build.js create mode 100644 .internal/templates/services/plex/config.js create mode 100644 .internal/templates/services/plex/template.yml create mode 100644 .internal/templates/services/portainer/build.js create mode 100644 .internal/templates/services/portainer/config.js create mode 100644 .internal/templates/services/portainer/template.yml create mode 100644 .internal/templates/services/portainer_agent/build.js create mode 100644 .internal/templates/services/portainer_agent/config.js create mode 100644 .internal/templates/services/portainer_agent/template.yml create mode 100644 .internal/templates/services/portainer_ce/build.js create mode 100644 .internal/templates/services/portainer_ce/config.js create mode 100644 .internal/templates/services/portainer_ce/template.yml create mode 100644 .internal/templates/services/postgres/build.js create mode 100644 .internal/templates/services/postgres/config.js create mode 100644 .internal/templates/services/postgres/template.yml create mode 100644 .internal/templates/services/qbittorrent/build.js create mode 100644 .internal/templates/services/qbittorrent/config.js create mode 100644 .internal/templates/services/qbittorrent/template.yml create mode 100644 .internal/templates/services/tasmoadmin/build.js create mode 100644 .internal/templates/services/tasmoadmin/config.js create mode 100644 .internal/templates/services/tasmoadmin/template.yml create mode 100644 .internal/templates/services/timescaledb/build.js create mode 100644 .internal/templates/services/timescaledb/config.js create mode 100644 .internal/templates/services/timescaledb/template.yml create mode 100644 .internal/templates/services/transmission/build.js create mode 100644 .internal/templates/services/transmission/config.js create mode 100644 .internal/templates/services/transmission/template.yml create mode 100644 .internal/templates/services/zigbee2mqtt/build.js create mode 100644 .internal/templates/services/zigbee2mqtt/config.js create mode 100644 .internal/templates/services/zigbee2mqtt/template.yml create mode 100644 .internal/wui.Dockerfile create mode 100644 .internal/wui/.eslintcache create mode 100644 .internal/wui/.gitignore create mode 100644 .internal/wui/README.md create mode 100644 .internal/wui/package-lock.json create mode 100644 .internal/wui/package.json create mode 100644 .internal/wui/public/favicon.ico create mode 100644 .internal/wui/public/index.html create mode 100644 .internal/wui/public/logo192.png create mode 100644 .internal/wui/public/logo512.png create mode 100644 .internal/wui/public/manifest.json create mode 100644 .internal/wui/public/robots.txt create mode 100644 .internal/wui/src/App.css create mode 100644 .internal/wui/src/App.js create mode 100644 .internal/wui/src/actions/buildStack.action.js create mode 100644 .internal/wui/src/actions/checkBuildIssues.action.js create mode 100644 .internal/wui/src/actions/downloadBuild.action.js create mode 100644 .internal/wui/src/actions/getBuildHistoryList.action.js create mode 100644 .internal/wui/src/actions/getNetworkTemplateList.action.js create mode 100644 .internal/wui/src/actions/getScript.action.js create mode 100644 .internal/wui/src/actions/getServiceConfigOptions.action.js create mode 100644 .internal/wui/src/actions/getServiceMetadata.action.js create mode 100644 .internal/wui/src/actions/getServiceTemplateList.action.js create mode 100644 .internal/wui/src/actions/getServiceTemplates.action.js create mode 100644 .internal/wui/src/actions/updateFilterTags.action.js create mode 100644 .internal/wui/src/actions/updateSelectedServices.action.js create mode 100644 .internal/wui/src/config.js create mode 100644 .internal/wui/src/constants.js create mode 100644 .internal/wui/src/features/BuildSidebar/build-sidebar.module.css create mode 100644 .internal/wui/src/features/BuildSidebar/index.jsx create mode 100644 .internal/wui/src/features/Sidebar/index.js create mode 100644 .internal/wui/src/features/buildCompletedModal/index.jsx create mode 100644 .internal/wui/src/features/buildHistoryGridItem/build-history-grid-item.module.css create mode 100644 .internal/wui/src/features/buildHistoryGridItem/index.jsx create mode 100644 .internal/wui/src/features/counter/Counter.js create mode 100644 .internal/wui/src/features/counter/Counter.module.css create mode 100644 .internal/wui/src/features/serviceConfigModal/index.jsx create mode 100644 .internal/wui/src/features/serviceUiControls/general/logging.jsx create mode 100644 .internal/wui/src/features/serviceUiControls/general/networkConfig.jsx create mode 100644 .internal/wui/src/features/serviceUiControls/general/portConfig.jsx create mode 100644 .internal/wui/src/features/serviceUiControls/index.js create mode 100644 .internal/wui/src/features/servicesGridItem/index.jsx create mode 100644 .internal/wui/src/features/servicesGridItem/services-grid-item.module.css create mode 100644 .internal/wui/src/index.css create mode 100644 .internal/wui/src/index.js create mode 100644 .internal/wui/src/logo.svg create mode 100644 .internal/wui/src/pages/buildHistory/index.jsx create mode 100644 .internal/wui/src/pages/help/index.jsx create mode 100644 .internal/wui/src/pages/mainBuild/index.jsx create mode 100644 .internal/wui/src/pages/notFound/index.js create mode 100644 .internal/wui/src/pages/scripts/index.jsx create mode 100644 .internal/wui/src/reducers/buildStackReducer.js create mode 100644 .internal/wui/src/reducers/counter.js create mode 100644 .internal/wui/src/reducers/getBuildHistoryListReducer.js create mode 100644 .internal/wui/src/reducers/getBuildIssuesReducer.js create mode 100644 .internal/wui/src/reducers/getNetworkTemplateListReducer.js create mode 100644 .internal/wui/src/reducers/getScriptTemplatesReducer.js create mode 100644 .internal/wui/src/reducers/getServiceConfigOptionsReducer.js create mode 100644 .internal/wui/src/reducers/getServiceMetadataReducer.js create mode 100644 .internal/wui/src/reducers/getServiceTemplateListReducer.js create mode 100644 .internal/wui/src/reducers/getServiceTemplatesReducer.js create mode 100644 .internal/wui/src/reducers/index.js create mode 100644 .internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js create mode 100644 .internal/wui/src/reducers/middlewares/promiseMiddleware.js create mode 100644 .internal/wui/src/reducers/updateSelectedFilterTagsReducer.js create mode 100644 .internal/wui/src/reducers/updateSelectedServicesReducer.js create mode 100644 .internal/wui/src/router.jsx create mode 100644 .internal/wui/src/services/builds.js create mode 100644 .internal/wui/src/services/configs.js create mode 100644 .internal/wui/src/services/templates.js create mode 100644 .internal/wui/src/utils/buildOptionSync.js create mode 100644 .internal/wui/src/utils/configOptionLoader.jsx create mode 100644 .internal/wui/src/utils/parsers.js delete mode 100644 scripts/deps/__pycache__/__init__.cpython-36.pyc delete mode 100644 scripts/deps/__pycache__/chars.cpython-36.pyc delete mode 100644 scripts/deps/__pycache__/common_functions.cpython-36.pyc delete mode 100644 scripts/deps/__pycache__/consts.cpython-36.pyc delete mode 100644 scripts/deps/__pycache__/version_check.cpython-36.pyc delete mode 100755 scripts/deps/buildstack.py rename {duck => scripts/host_installers}/duck.sh (100%) mode change 100755 => 100644 rename {.native => scripts/host_installers}/hassio_supervisor.sh (100%) mode change 100755 => 100644 rename scripts/{ => host_installers}/install_docker.sh (100%) mode change 100755 => 100644 rename scripts/{ => host_installers}/install_log2ram.sh (100%) mode change 100755 => 100644 rename scripts/{ => host_installers}/install_ssh_keys.sh (100%) mode change 100755 => 100644 rename {.native => scripts/host_installers}/rpieasy.sh (100%) rename {.native => scripts/host_installers}/rtl_433.sh (100%) mode change 100755 => 100644 diff --git a/.internal/.dockerignore b/.internal/.dockerignore new file mode 100644 index 000000000..cf7098890 --- /dev/null +++ b/.internal/.dockerignore @@ -0,0 +1 @@ +**/node_modules diff --git a/.internal/.gitignore b/.internal/.gitignore new file mode 100644 index 000000000..1c7815555 --- /dev/null +++ b/.internal/.gitignore @@ -0,0 +1,39 @@ +.DS_STORE +node_modules +scripts/flow/*/.flowconfig +.flowconfig +*~ +*.pyc +.grunt +_SpecRunner.html +__benchmarks__ +build/ +remote-repo/ +coverage/ +.module-cache +fixtures/dom/public/react-dom.js +fixtures/dom/public/react.js +test/the-files-to-test.generated.js +*.log* +chrome-user-data +*.sublime-project +*.sublime-workspace +.idea +*.iml +.vscode +*.swp +*.swo +.temp + +packages/react-devtools-core/dist +packages/react-devtools-extensions/chrome/build +packages/react-devtools-extensions/chrome/*.crx +packages/react-devtools-extensions/chrome/*.pem +packages/react-devtools-extensions/firefox/build +packages/react-devtools-extensions/firefox/*.xpi +packages/react-devtools-extensions/firefox/*.pem +packages/react-devtools-extensions/shared/build +packages/react-devtools-extensions/.tempUserDataDir +packages/react-devtools-inline/dist +packages/react-devtools-shell/dist +packages/react-devtools-scheduling-profiler/dist \ No newline at end of file diff --git a/.internal/IOTstack.postman_collection.json b/.internal/IOTstack.postman_collection.json new file mode 100644 index 000000000..a048d99a8 --- /dev/null +++ b/.internal/IOTstack.postman_collection.json @@ -0,0 +1,757 @@ +{ + "info": { + "_postman_id": "f9aa4568-fc88-42e4-b005-2f8ddf330e79", + "name": "IOTstack", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Build", + "item": [ + { + "name": "Build", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\"buildOptions\": {\n\t\t\"selectedServices\": [],\n\t\t\"serviceOptions\": {}\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/build/save", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "build", + "save" + ] + }, + "description": "Create build" + }, + "response": [] + }, + { + "name": "Get Previous Build List", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\"buildOptions\": {\n\t\t\"selectedServices\": [],\n\t\t\"serviceOptions\": {}\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/build/list", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "build", + "list" + ] + }, + "description": "Get a list of previous builds stored on file" + }, + "response": [] + }, + { + "name": "Get Previous Build File Details", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\"buildOptions\": {\n\t\t\"selectedServices\": [],\n\t\t\"serviceOptions\": {}\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/build/get/{{buildTime}}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "build", + "get", + "{{buildTime}}" + ] + }, + "description": "Get a file list of specific build" + }, + "response": [] + }, + { + "name": "Get Previous Build File", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\"buildOptions\": {\n\t\t\"selectedServices\": [],\n\t\t\"serviceOptions\": {}\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/build/get/{{buildTime}}/{{type}}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "build", + "get", + "{{buildTime}}", + "{{type}}" + ] + }, + "description": "Get a file list of specific build file. Type can be one of: 'yaml', 'json', 'zip' or 'sh'." + }, + "response": [] + }, + { + "name": "Dry Run (Check Issues)", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\"buildOptions\": {\n\t\t\"selectedServices\": [],\n\t\t\"serviceConfigurations\": {}\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/build/dryrun", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "build", + "dryrun" + ] + }, + "description": "This checks for issues" + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "Configs", + "item": [ + { + "name": "Get Service Config Options", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/config/{{serviceName}}/options", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "config", + "{{serviceName}}", + "options" + ] + } + }, + "response": [] + }, + { + "name": "Get Service Help URIs", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/config/{{serviceName}}/help", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "config", + "{{serviceName}}", + "help" + ] + } + }, + "response": [] + }, + { + "name": "Get Service Scripts", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/config/{{serviceName}}/scripts", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "config", + "{{serviceName}}", + "scripts" + ] + }, + "description": "Get a list of scripts that could e useful for checking your system before building, or for debugging." + }, + "response": [] + }, + { + "name": "Get Specific Service Script", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/config/{{serviceName}}/scripts/{{scriptName}}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "config", + "{{serviceName}}", + "scripts", + "{{scriptName}}" + ] + }, + "description": "Get a specific script, if it exists, that can be piped into bash." + }, + "response": [] + }, + { + "name": "Get Service Metadata", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/config/{{serviceName}}/meta", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "config", + "{{serviceName}}", + "meta" + ] + }, + "description": "Get metadata about a service, such as its tags." + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "Templates", + "item": [ + { + "name": "Services", + "item": [ + { + "name": "Get all services in YAML format", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/services/yaml", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "services", + "yaml" + ] + } + }, + "response": [] + }, + { + "name": "Get specific service in YAML format", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/services/yaml/{{serviceName}}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "services", + "yaml", + "{{serviceName}}" + ] + } + }, + "response": [] + }, + { + "name": "Get specific service in JSON format", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/services/json/{{serviceName}}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "services", + "json", + "{{serviceName}}" + ] + } + }, + "response": [] + }, + { + "name": "Get all services in JSON format", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/services/json", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "services", + "json" + ] + } + }, + "response": [] + }, + { + "name": "List all services", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/services/list", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "services", + "list" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Networks", + "item": [ + { + "name": "Get all networks in JSON format", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/networks/json", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "networks", + "json" + ] + } + }, + "response": [] + }, + { + "name": "Get specific network in YAML format", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/networks/yaml/{{networkName}}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "networks", + "yaml", + "{{networkName}}" + ] + } + }, + "response": [] + }, + { + "name": "Get all networks in YAML format", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/networks/yaml", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "networks", + "yaml" + ] + } + }, + "response": [] + }, + { + "name": "List all networks", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/networks/list", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "networks", + "list" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Scripts", + "item": [ + { + "name": "Get script by name", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"options\": {}\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/scripts/{scriptName}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "scripts", + "{scriptName}" + ] + } + }, + "response": [] + }, + { + "name": "Download script by name", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"options\": {}\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/templates/scripts/download/{scriptName}", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "templates", + "scripts", + "download", + "{scriptName}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "Get API State and Health", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:32128/health", + "host": [ + "localhost" + ], + "port": "32128", + "path": [ + "health" + ] + }, + "description": "Get metadata about a service, such as its tags." + }, + "response": [] + } + ], + "protocolProfileBehavior": {} +} \ No newline at end of file diff --git a/.internal/api.Dockerfile b/.internal/api.Dockerfile new file mode 100644 index 000000000..c8a5aaa35 --- /dev/null +++ b/.internal/api.Dockerfile @@ -0,0 +1,10 @@ +FROM node:14 + +WORKDIR /usr/iotstack_api + +# node_modules is ignored with this copy, as specified in .dockerignore +COPY api ./ +RUN npm install + +EXPOSE 32128 +CMD [ "npm", "start" ] diff --git a/.internal/api/index.js b/.internal/api/index.js new file mode 100644 index 000000000..f2a01fbfa --- /dev/null +++ b/.internal/api/index.js @@ -0,0 +1 @@ +const server = require('./src/index'); diff --git a/.internal/api/package-lock.json b/.internal/api/package-lock.json new file mode 100644 index 000000000..eb33e1454 --- /dev/null +++ b/.internal/api/package-lock.json @@ -0,0 +1,1542 @@ +{ + "name": "iotstack_api", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "archiver": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.1.0.tgz", + "integrity": "sha512-iKuQUP1nuKzBC2PFlGet5twENzCfyODmvkxwDV0cEFXavwcLrIW5ssTuHi9dyTPvpWr6Faweo2eQaQiLIwyXTA==", + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.0", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.1.4", + "zip-stream": "^4.0.4" + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "bl": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", + "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + } + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.0.tgz", + "integrity": "sha512-JgQM9JS92ZbFR4P90EvmzNpSGhpPBGBSj10PILeDyYFwp4h2/D9OM03wsJ4zW1fEp4ka2DGrnUeD7FuvQ2aZ2Q==", + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "compress-commons": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.0.2.tgz", + "integrity": "sha512-qhd32a9xgzmpfoga1VQEiLEwdKZ6Plnpx5UCgIsf89FSolyJ7WnifY4Gtjgv5WR6hWAyRaHxC5MiEhU/38U70A==", + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, + "crc32-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.1.tgz", + "integrity": "sha512-FN5V+weeO/8JaXsamelVYO1PHyeCsuL3HcG4cqsj0ceARcocxalaShCsohZMSAF+db7UYFwBy1rARK/0oFItUw==", + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "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" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz", + "integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==", + "optional": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "requires": { + "ini": "1.3.7" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "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==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "requires": { + "package-json": "^6.3.0" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "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" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-glob": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", + "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", + "requires": { + "minimatch": "^3.0.4" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" + } + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "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==" + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "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==" + } + } + }, + "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==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar-stream": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", + "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "requires": { + "nopt": "~1.0.10" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "requires": { + "debug": "^2.2.0" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "zip-stream": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.4.tgz", + "integrity": "sha512-a65wQ3h5gcQ/nQGWV1mSZCEzCML6EK/vyVPcrPNynySP1j3VBbQKh3nhC8CbORb+jfl2vXvh56Ul5odP1bAHqw==", + "requires": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.0.2", + "readable-stream": "^3.6.0" + } + } + } +} diff --git a/.internal/api/package.json b/.internal/api/package.json new file mode 100644 index 000000000..3ca47c7fb --- /dev/null +++ b/.internal/api/package.json @@ -0,0 +1,20 @@ +{ + "name": "iotstack_api", + "version": "0.0.1", + "description": "IOTstack API", + "repository": "https://github.com/SensorsIot/IOTstack", + "main": "index.js", + "scripts": { + "start": "NODE_ENV=production node index.js", + "dev": "NODE_ENV=dev nodemon index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "archiver": "^5.1.0", + "body-parser": "^1.19.0", + "express": "^4.17.1", + "js-yaml": "^3.14.0", + "nodemon": "^2.0.7" + } +} diff --git a/.internal/api/src/.tmp/.gitignore b/.internal/api/src/.tmp/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/.internal/api/src/.tmp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/.internal/api/src/controllers/build.js b/.internal/api/src/controllers/build.js new file mode 100644 index 000000000..339dd09fc --- /dev/null +++ b/.internal/api/src/controllers/build.js @@ -0,0 +1,561 @@ +const BuildController = ({ server, settings, version, logger }) => { + const BuildsService = require('../services/builds'); + const ZipService = require('../services/zip'); + const TemplatesController = require('./templates'); + const { getDirectoryList, getFileList, emptyDirectory } = require('../utils/fsUtils'); + const { formatDate } = require('../utils/date'); + const { getUniqueNetworkListFromServices } = require('../utils/networkUtils'); + const buildInstallerGenerator = require('../../templates/scripts/build_installer'); + const retr = {}; + + const buildsService = BuildsService({ server, settings, version, logger }); + const zipService = ZipService({ server, settings, version, logger }); + const templatesController = TemplatesController({ server, settings, version, logger }); + const path = require('path'); + const fs = require('fs'); + + retr.init = () => { + templatesController.init(); + buildsService.init(); + zipService.init(); + logger.debug('BuildController:init()'); + }; + + retr.buildStack = async ({ host, buildOptions }) => { + return new Promise(async (resolve, reject) => { + try { + outputStack = { + services: {}, + networks: {} + }; + const currentDate = formatDate(); + const toZip = []; + const prebuildScripts = []; + const postbuildScripts = []; + + const failedStack = { + services: [], + networks: [] + }; + + // Get service templates for processing and output + const serviceTemplatePromises = []; + + buildOptions.selectedServices.forEach((selectedService) => { + serviceTemplatePromises.push(templatesController.getServiceTemplateAsJson(selectedService)); + }); + + await Promise.allSettled(serviceTemplatePromises).then((serviceTemplateResults) => { + serviceTemplateResults.forEach((servicePromiseResult) => { + if (servicePromiseResult.status === 'fulfilled' && servicePromiseResult.value) { + const serviceName = Object.keys(servicePromiseResult.value)[0]; + outputStack.services[serviceName] = servicePromiseResult.value[serviceName]; + } else { + failedStack.services.push(servicePromiseResult); + } + }); + return outputStack; + }); + + const podNetworks = getUniqueNetworkListFromServices({ services: outputStack.services, logger }); + + // Get network templates for processing and output + const networkTemplatePromises = []; + + podNetworks.forEach((networkName) => { + networkTemplatePromises.push(templatesController.getNetworkTemplateAsJson(networkName)); + }); + + await Promise.allSettled(networkTemplatePromises).then((networkTemplateResults) => { + networkTemplateResults.forEach((networkPromiseResult) => { + if (networkPromiseResult.status === 'fulfilled' && networkPromiseResult.value) { + const networkName = Object.keys(networkPromiseResult.value)[0]; + outputStack.networks[networkName] = networkPromiseResult.value[networkName]; + } else { + failedStack.networks.push(networkPromiseResult); + } + }); + return outputStack; + }); + + if (failedStack.services.length > 0 || failedStack.networks.length > 0) { + console.warn('Failed to compile some templates: ', failedStack); + } + + + // All templates gathered and ready for processing by each service. + const templatesBuildLogic = []; + const { + localBuildsDirectory, + buildInstallerFilePostfix, + localTemplatesPath, + localNetworksRelativePath, + localServicesRelativePath, + buildLogicFile, + buildDockerFilePostfix, + buildOptionsFilePostfix, + localTmpPath + } = settings.paths; + + emptyDirectory(localTmpPath, ['.gitignore']); + + const servicesBuildPath = path.join(localTemplatesPath, localServicesRelativePath); + const networksBuildPath = path.join(localTemplatesPath, localNetworksRelativePath); + + // Instantiate each service's build logic + Object.keys(outputStack.services).forEach((serviceName) => { + const serviceBuildScript = path.join(servicesBuildPath, serviceName, buildLogicFile); + if (fs.existsSync(serviceBuildScript)) { + templatesBuildLogic.push(require(serviceBuildScript)({ settings, version, logger })); + } else { + console.log(`BuildController::buildStack: No service build file for '${serviceName}'. Looking in: '${serviceBuildScript}'`) + } + }); + + // Instantiate each network's build logic + Object.keys(outputStack.networks).forEach((networkName) => { + const networkBuildScript = path.join(networksBuildPath, networkName, buildLogicFile); + if (fs.existsSync(networkBuildScript)) { + templatesBuildLogic.push(require(networkBuildScript)({ settings, version, logger })); + } else { + console.log(`BuildController::buildStack: No network build file for '${networkName}'. Looking in: '${networkBuildScript}'`) + } + }); + + const issueList = { + services: [], + networks: [], + other: [] + }; + + await templatesBuildLogic.reduce((prom, buildLogic) => { + return prom.then(async () => { + if (typeof buildLogic.build === 'function') { + await buildLogic.build({ + outputTemplateJson: outputStack, + buildOptions, + tmpPath: localTmpPath, + fileTimePrefix: currentDate, + zipList: toZip, + prebuildScripts, + postbuildScripts + }); + // .then((res) => { + // console.log('Result: ', res); + // }); + } + + if (typeof buildLogic.issues === 'function') { + return buildLogic.issues({ + outputTemplateJson: outputStack, + buildOptions, + tmpPath: localTmpPath + }).then((issueResults) => { + if (Array.isArray(issueResults) && issueResults.length > 0) { + issueResults.forEach((issue) => { + if (issue.type === 'service') { + issueList.services.push(issue); + } else if (issue.type === 'network') { + issueList.networks.push(issue); + } else { + issueList.other.push(issue); + } + }); + } + }); + } + + return Promise.resolve({}); + }); + }, Promise.resolve()).then(() => { + console.debug('BuildController::buildStack: Build Completed'); + }).catch((err) => { + console.error('BuildController::buildStack: Build Error: ', err); + }); + + const { yamlFilename, yamlOutputFilePath } = await buildsService.saveBuildYaml({ buildJson: outputStack, fileTimePrefix: currentDate }); + const { jsonFilename, jsonOutputFilePath } = await buildsService.saveBuildOptions({ buildOptionsJson: buildOptions, fileTimePrefix: currentDate }); + const dockerComposeBaseFilename = buildDockerFilePostfix.split('_')[1]; + const buildInstallerFileBaseFilename = buildInstallerFilePostfix.split('_')[1]; + const buildOptionsBaseFilename = buildOptionsFilePostfix.split('_')[1]; + + buildInstallerFilePostfix + const buildInstallerContents = await buildInstallerGenerator({ + options: { + build: currentDate, + prebuildScripts, + postbuildScripts + }, + logger, + version + }); + + const installerScriptFilename = `${currentDate}${buildInstallerFilePostfix}`; + const installerOutputFilePath = path.join(localBuildsDirectory, installerScriptFilename); + + fs.writeFileSync(installerOutputFilePath, buildInstallerContents.data); + + toZip.push({ + fullPath: installerOutputFilePath, + zipName: buildInstallerFileBaseFilename + }); + + toZip.push({ + fullPath: yamlOutputFilePath, + zipName: dockerComposeBaseFilename + }); + + toZip.push({ + fullPath: jsonOutputFilePath, + zipName: buildOptionsBaseFilename + }); + + const zipDirectories = []; + toZip.forEach((zipEntries) => { + if (Array.isArray(zipEntries.directories) && zipEntries.directories.length > 0) { + zipEntries.directories.forEach((directory) => { + zipDirectories.push(directory); + }); + } + }); + + const zipResults = await zipService.zipFiles({ fileList: toZip, fileTimePrefix: currentDate, archiveDirectoryList: zipDirectories }); + + return resolve({ + issueList, + build: currentDate, + host, + files: { + yamlFilename, + jsonFilename, + zipFilename: zipResults.zipFilename + } + }); + + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'BuildController::buildStack', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.checkIssues = ({ buildOptions }) => { + return new Promise(async (resolve, reject) => { + try { + outputStack = { + services: {}, + networks: {} + }; + + const failedStack = { + services: [], + networks: [] + }; + + // Get service templates for processing and output + const serviceTemplatePromises = []; + + buildOptions.selectedServices.forEach((selectedService) => { + serviceTemplatePromises.push(templatesController.getServiceTemplateAsJson(selectedService)); + }); + + await Promise.allSettled(serviceTemplatePromises).then((serviceTemplateResults) => { + serviceTemplateResults.forEach((servicePromiseResult) => { + if (servicePromiseResult.status === 'fulfilled' && servicePromiseResult.value) { + const serviceName = Object.keys(servicePromiseResult.value)[0]; + outputStack.services[serviceName] = servicePromiseResult.value[serviceName]; + } else { + failedStack.services.push(servicePromiseResult); + } + }); + return outputStack; + }); + + const podNetworks = getUniqueNetworkListFromServices({ services: outputStack.services, logger }); + + // Get network templates for processing and output + const networkTemplatePromises = []; + + podNetworks.forEach((networkName) => { + networkTemplatePromises.push(templatesController.getNetworkTemplateAsJson(networkName)); + }); + + await Promise.allSettled(networkTemplatePromises).then((networkTemplateResults) => { + networkTemplateResults.forEach((networkPromiseResult) => { + if (networkPromiseResult.status === 'fulfilled' && networkPromiseResult.value) { + const networkName = Object.keys(networkPromiseResult.value)[0]; + outputStack.networks[networkName] = networkPromiseResult.value[networkName]; + } else { + failedStack.networks.push(networkPromiseResult); + } + }); + return outputStack; + }); + + if (failedStack.services.length > 0 || failedStack.networks.length > 0) { + console.warn('Failed to compile some templates: ', failedStack); + } + + // All templates gathered and ready for processing by each service. + const templatesBuildLogic = []; + const { + localTemplatesPath, + localNetworksRelativePath, + localServicesRelativePath, + buildLogicFile + } = settings.paths; + const servicesBuildPath = path.join(localTemplatesPath, localServicesRelativePath); + const networksBuildPath = path.join(localTemplatesPath, localNetworksRelativePath); + + // Instantiate each service's build logic + Object.keys(outputStack.services).forEach((serviceName) => { + const serviceBuildScript = path.join(servicesBuildPath, serviceName, buildLogicFile); + if (fs.existsSync(serviceBuildScript)) { + templatesBuildLogic.push(require(serviceBuildScript)({ settings, version, logger })); + } else { + console.log(`BuildController::checkIssues: No service build file for '${serviceName}'. Looking in: '${serviceBuildScript}'`) + } + }); + + // Instantiate each network's build logic + Object.keys(outputStack.networks).forEach((networkName) => { + const networkBuildScript = path.join(networksBuildPath, networkName, buildLogicFile); + if (fs.existsSync(networkBuildScript)) { + templatesBuildLogic.push(require(networkBuildScript)({ settings, version, logger })); + } else { + console.log(`BuildController::checkIssues: No network build file for '${networkName}'. Looking in: '${networkBuildScript}'`) + } + }); + + const issueList = { + services: [], + networks: [], + other: [] + }; + + return templatesBuildLogic.reduce((prom, buildLogic) => { + return prom.then(() => { + if (typeof buildLogic.issues === 'function') { + return buildLogic.issues({ + outputTemplateJson: outputStack, + buildOptions + }).then((issueResults) => { + if (Array.isArray(issueResults) && issueResults.length > 0) { + issueResults.forEach((issue) => { + if (issue.type === 'service') { + issueList.services.push(issue); + } else if (issue.type === 'network') { + issueList.networks.push(issue); + } else { + issueList.other.push(issue); + } + }); + } + }); + } + + return Promise.resolve({ issueList }); + }); + }, Promise.resolve()).then(() => { + console.debug('BuildController::checkIssues: Issue check completed'); + return resolve({ issueList }); + }).catch((err) => { + console.error('BuildController::checkIssues: Issue check error: ', err); + return reject({ issueList }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'BuildController::checkIssues', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getPreviousBuildsList = ({ host, buildTime }) => { + return new Promise(async (resolve, reject) => { + try { + const { + localBuildsDirectory, + buildDockerFilePostfix, + buildOptionsFilePostfix, + buildZipFilePostfix + } = settings.paths; + + const buildFiles = getFileList(localBuildsDirectory); + + const buildsList = {}; + let singleBuild = {}; + + buildFiles.forEach((fileName) => { + const deconstructedFilename = fileName.split('_'); + if (deconstructedFilename.length === 2) { + const checkBuildTime = deconstructedFilename[0]; + if (typeof buildsList[checkBuildTime] === 'undefined') { + buildsList[checkBuildTime] = {}; + } + + if (fileName.endsWith(buildDockerFilePostfix)) { + if (!buildTime) { + buildsList[checkBuildTime] = { + ...buildsList[checkBuildTime], + yaml: fileName + } + } else { + if (checkBuildTime === buildTime) { + singleBuild = { + ...singleBuild, + yaml: fileName + } + } + } + } + + if (fileName.endsWith(buildOptionsFilePostfix)) { + if (!buildTime) { + buildsList[checkBuildTime] = { + ...buildsList[checkBuildTime], + json: fileName + } + } else { + if (checkBuildTime === buildTime) { + singleBuild = { + ...singleBuild, + json: fileName + } + } + } + } + + if (fileName.endsWith(buildZipFilePostfix)) { + if (!buildTime) { + buildsList[checkBuildTime] = { + ...buildsList[checkBuildTime], + zip: fileName + } + } else { + if (checkBuildTime === buildTime) { + singleBuild = { + ...singleBuild, + zip: fileName + } + } + } + } + } + }); + if (!buildTime) { + return resolve({ buildsList, host }); + } else { + return resolve({ buildFiles: singleBuild, host }); + } + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'BuildController::getPreviousBuildsList', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.downloadPreviousBuildsList = ({ host, buildTime, type }) => { + return new Promise(async (resolve, reject) => { + try { + if (!buildTime) { + return reject({ + component: 'BuildController::downloadPreviousBuildsList', + message: 'No build time specified' + }); + } + + if (!type) { + return reject({ + component: 'BuildController::downloadPreviousBuildsList', + message: 'No download type specified' + }); + } + + const { + localBuildsDirectory, + buildDockerFilePostfix, + buildZipFilePostfix, + buildOptionsFilePostfix, + buildInstallerFilePostfix + } = settings.paths; + + const buildFiles = getFileList(localBuildsDirectory); + + let singleBuild = { + otherFiles: [] + }; + + buildFiles.forEach((fileName) => { + if (fileName.startsWith(buildTime)) { + if (fileName.endsWith(buildDockerFilePostfix)) { + singleBuild['yaml'] = fileName; + } else if (fileName.endsWith(buildZipFilePostfix)) { + singleBuild['zip'] = fileName; + } else if (fileName.endsWith(buildOptionsFilePostfix)) { + singleBuild['json'] = fileName; + } else if (fileName.endsWith(buildInstallerFilePostfix)) { + singleBuild['installer'] = fileName; + } else { + singleBuild.otherFiles.push(fileName); + } + } + }); + + if (type === 'yaml' || type === 'yml') { + const fullPath = path.join(localBuildsDirectory, singleBuild['yaml']); + const filename = buildDockerFilePostfix.substring(1); // Removes the prefixed underscope _ on filename + return resolve({ fullPath, filename, path: localBuildsDirectory }); + } + + if (type === 'json') { + const fullPath = path.join(localBuildsDirectory, singleBuild['json']); + const filename = buildOptionsFilePostfix.substring(1); // Removes the prefixed underscope _ on filename + return resolve({ fullPath, filename, path: localBuildsDirectory }); + } + + if (type === 'zip') { + const fullPath = path.join(localBuildsDirectory, singleBuild['zip']); + const filename = buildZipFilePostfix.substring(1); // Removes the prefixed underscope _ on filename + return resolve({ fullPath, filename, path: localBuildsDirectory }); + } + + if (type === 'sh' || type === 'bash' || type === 'bootstrap') { + const fullPath = path.join(localBuildsDirectory, singleBuild['bootstrap']); + const filename = buildInstallerFilePostfix.substring(1); // Removes the prefixed underscope _ on filename + return resolve({ fullPath, filename, path: localBuildsDirectory }); + } + + return reject({ + component: 'BuildController::downloadPreviousBuildsList', + message: `Unknown type '${type}'` + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'BuildController::downloadPreviousBuildsList', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} +module.exports = BuildController; diff --git a/.internal/api/src/controllers/configs.js b/.internal/api/src/controllers/configs.js new file mode 100644 index 000000000..1e9e4ef51 --- /dev/null +++ b/.internal/api/src/controllers/configs.js @@ -0,0 +1,139 @@ +const ConfigsController = ({ server, settings, version, logger }) => { + const { getDirectoryList, getFileList, emptyDirectory } = require('../utils/fsUtils'); + const retr = {}; + + const path = require('path'); + const fs = require('fs'); + + retr.init = () => { + logger.debug('ConfigsController:init()'); + }; + + retr.getConfigOptions = async ({ serviceName }) => { + return new Promise(async (resolve, reject) => { + let serviceBuildScript; + try { + const { + localTemplatesPath, + localServicesRelativePath, + configLogicFile + } = settings.paths; + const servicesBuildPath = path.join(localTemplatesPath, localServicesRelativePath); + serviceBuildScript = path.join(servicesBuildPath, serviceName, configLogicFile); + + const configLogic = require(serviceBuildScript)(); + + return resolve(configLogic.getConfigOptions()); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ serviceName }); + console.debug({ serviceBuildScript }); + return reject({ + component: 'ConfigsController::getConfigOptions', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getHelp = async ({ serviceName }) => { + return new Promise(async (resolve, reject) => { + let serviceBuildScript; + try { + const { + localTemplatesPath, + localServicesRelativePath, + configLogicFile + } = settings.paths; + const servicesBuildPath = path.join(localTemplatesPath, localServicesRelativePath); + serviceBuildScript = path.join(servicesBuildPath, serviceName, configLogicFile); + + const configLogic = require(serviceBuildScript)(); + + return resolve(configLogic.getHelp()); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ serviceName }); + console.debug({ serviceBuildScript }); + return reject({ + component: 'ConfigsController::getHelp', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getScripts = async ({ serviceName, scriptName }) => { + return new Promise(async (resolve, reject) => { + let serviceBuildScript; + try { + const { + localTemplatesPath, + localServicesRelativePath, + configLogicFile + } = settings.paths; + const servicesBuildPath = path.join(localTemplatesPath, localServicesRelativePath); + serviceBuildScript = path.join(servicesBuildPath, serviceName, configLogicFile); + + const configLogic = require(serviceBuildScript)(); + + if (scriptName) { + return resolve(configLogic.getCommands().commands[scriptName]); + } + + return resolve(configLogic.getCommands()); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ serviceName }); + console.debug({ serviceBuildScript }); + console.debug({ scriptName }); + return reject({ + component: 'ConfigsController::getScripts', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getMeta = async ({ serviceName }) => { + return new Promise(async (resolve, reject) => { + let serviceBuildScript; + try { + const { + localTemplatesPath, + localServicesRelativePath, + configLogicFile + } = settings.paths; + const servicesBuildPath = path.join(localTemplatesPath, localServicesRelativePath); + serviceBuildScript = path.join(servicesBuildPath, serviceName, configLogicFile); + + const configLogic = require(serviceBuildScript)(); + + return resolve(configLogic.getMeta()); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ serviceName }); + console.debug({ serviceBuildScript }); + return reject({ + component: 'ConfigsController::getMeta', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} +module.exports = ConfigsController; diff --git a/.internal/api/src/controllers/health.js b/.internal/api/src/controllers/health.js new file mode 100644 index 000000000..d1af89bae --- /dev/null +++ b/.internal/api/src/controllers/health.js @@ -0,0 +1,23 @@ +const HealthController = ({ server, settings, version, logger }) => { + const retr = {}; + + retr.init = () => { + logger.debug('HealthController:init()'); + }; + + retr.healthCheck = () => { + const baseHealthResults = { + server: "online", + api: true, + version + }; + + return new Promise((resolveHealth, rejectHealth) => { + logger.log('HealthController:healthCheck()'); + return resolveHealth(baseHealthResults); + }); + }; + + return retr; +} +module.exports = HealthController; diff --git a/.internal/api/src/controllers/templates.js b/.internal/api/src/controllers/templates.js new file mode 100644 index 000000000..3e8b47b5a --- /dev/null +++ b/.internal/api/src/controllers/templates.js @@ -0,0 +1,412 @@ +const fsUtils = require('../utils/fsUtils'); + +const TemplatesController = ({ server, settings, version, logger }) => { + const TemplatesService = require('../services/templates'); + const { getDirectoryList, filterBadPathStrings } = require('../utils/fsUtils'); + const retr = {}; + + const templatesService = TemplatesService({ server, settings, version, logger }); + const path = require('path'); + const fs = require('fs'); + const yaml = require('js-yaml'); + + retr.init = () => { + templatesService.init(); + logger.debug('TemplatesController:init()'); + }; + + retr.getServiceTemplateAsYaml = (templateName) => { + return new Promise((resolve, reject) => { + try { + if (!templateName) { + return reject({ + component: 'TemplatesController::getServiceTemplateAsYaml', + message: 'No template name passed' + }); + } + return templatesService.getServiceTemplateFromFile(templateName).then((result) => { + return resolve(result); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getServiceTemplateAsYaml', + message: 'Unable to get template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getServiceTemplateAsYaml', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getNetworkTemplateAsYaml = (templateName) => { + return new Promise((resolve, reject) => { + try { + if (!templateName) { + return reject({ + component: 'TemplatesController::getNetworkTemplateAsYaml', + message: 'No template name passed' + }); + } + return templatesService.getNetworkTemplateFromFile(templateName).then((result) => { + return resolve(result); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getNetworkTemplateAsYaml', + message: 'Unable to get template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getNetworkTemplateAsYaml', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getServiceTemplateAsJson = (templateName) => { + return new Promise((resolve, reject) => { + try { + if (!templateName) { + return reject({ + component: 'TemplatesController::getServiceTemplateAsJson', + message: 'No template name passed' + }); + } + return templatesService.getServiceTemplateFromFile(templateName, true).then((result) => { + return resolve(result); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getServiceTemplateAsJson', + message: 'Unable to get template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getServiceTemplateAsJson', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getNetworkTemplateAsJson = (templateName) => { + return new Promise((resolve, reject) => { + try { + if (!templateName) { + return reject({ + component: 'TemplatesController::getNetworkTemplateAsJson', + message: 'No template name passed' + }); + } + return templatesService.getNetworkTemplateFromFile(templateName, true).then((result) => { + return resolve(result); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getNetworkTemplateAsJson', + message: 'Unable to get template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getNetworkTemplateAsJson', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getAllServiceTemplatesAsYaml = () => { + return new Promise((resolve, reject) => { + try { + const { localTemplatesPath, localServicesRelativePath } = settings.paths; + const serviceTemplatesList = getDirectoryList(path.join(localTemplatesPath, localServicesRelativePath)); + const promiseWaitList = []; + serviceTemplatesList.forEach((serviceDirectory) => { + promiseWaitList.push(templatesService.getServiceTemplateFromFile(serviceDirectory, true)); + }); + return Promise.allSettled(promiseWaitList).then((resultList) => { + const serviceList = {}; + resultList.forEach((servicePromiseResult) => { + if (servicePromiseResult.status === 'fulfilled' && servicePromiseResult.value) { + const serviceName = Object.keys(servicePromiseResult.value)[0]; + serviceList[serviceName] = servicePromiseResult.value[serviceName]; + } + }); + return resolve(yaml.dump(serviceList)); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getAllServiceTemplatesAsYaml', + message: 'Unable to get templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getAllServiceTemplatesAsYaml', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getAllNetworkTemplatesAsYaml = () => { + return new Promise((resolve, reject) => { + try { + const { localTemplatesPath, localNetworksRelativePath } = settings.paths; + const networkTemplatesList = getDirectoryList(path.join(localTemplatesPath, localNetworksRelativePath)); + const promiseWaitList = []; + networkTemplatesList.forEach((networkDirectory) => { + promiseWaitList.push(templatesService.getNetworkTemplateFromFile(networkDirectory, true)); + }); + return Promise.allSettled(promiseWaitList).then((resultList) => { + const networkList = {}; + resultList.forEach((networkPromiseResult) => { + if (networkPromiseResult.status === 'fulfilled' && networkPromiseResult.value) { + const networkName = Object.keys(networkPromiseResult.value)[0]; + networkList[networkName] = networkPromiseResult.value[networkName]; + } + }); + return resolve(yaml.dump(networkList)); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getAllNetworkTemplatesAsYaml', + message: 'Unable to get templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getAllNetworkTemplatesAsYaml', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getAllServiceTemplatesAsJson = () => { + return new Promise((resolve, reject) => { + try { + const { localTemplatesPath, localServicesRelativePath } = settings.paths; + const serviceTemplatesList = getDirectoryList(path.join(localTemplatesPath, localServicesRelativePath)); + const promiseWaitList = []; + serviceTemplatesList.forEach((serviceDirectory) => { + promiseWaitList.push(templatesService.getServiceTemplateFromFile(serviceDirectory, true)); + }); + return Promise.allSettled(promiseWaitList).then((resultList) => { + const serviceList = {}; + resultList.forEach((servicePromiseResult) => { + if (servicePromiseResult.status === 'fulfilled' && servicePromiseResult.value) { + const serviceName = Object.keys(servicePromiseResult.value)[0]; + serviceList[serviceName] = servicePromiseResult.value[serviceName]; + } + }); + return resolve(serviceList); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getAllServiceTemplatesAsJson', + message: 'Unable to get templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getAllServiceTemplatesAsJson', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getAllNetworkTemplatesAsJson = () => { + return new Promise((resolve, reject) => { + try { + const { localTemplatesPath, localNetworksRelativePath } = settings.paths; + const networkTemplatesList = getDirectoryList(path.join(localTemplatesPath, localNetworksRelativePath)); + const promiseWaitList = []; + networkTemplatesList.forEach((networkDirectory) => { + promiseWaitList.push(templatesService.getNetworkTemplateFromFile(networkDirectory, true)); + }); + return Promise.allSettled(promiseWaitList).then((resultList) => { + const networkList = {}; + resultList.forEach((networkPromiseResult) => { + if (networkPromiseResult.status === 'fulfilled' && networkPromiseResult.value) { + const networkName = Object.keys(networkPromiseResult.value)[0]; + networkList[networkName] = networkPromiseResult.value[networkName]; + } + }); + return resolve(networkList); + }).catch((err) => { + return reject({ + component: 'TemplatesController::getAllNetworkTemplatesAsJson', + message: 'Unable to get templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getAllNetworkTemplatesAsJson', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getAllServiceTemplatesAsList = () => { + return new Promise((resolve, reject) => { + try { + const { localTemplatesPath, localServicesRelativePath } = settings.paths; + const serviceTemplatesList = getDirectoryList(path.join(localTemplatesPath, localServicesRelativePath)); + return resolve(serviceTemplatesList); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getAllServiceTemplatesAsList', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getAllNetworkTemplatesAsList = () => { + return new Promise((resolve, reject) => { + try { + const { localTemplatesPath, localNetworksRelativePath } = settings.paths; + const networkTemplatesList = getDirectoryList(path.join(localTemplatesPath, localNetworksRelativePath)); + return resolve(networkTemplatesList); + } catch (err) { + console.log(err); + console.trace(); + return reject({ + component: 'TemplatesController::getAllNetworkTemplatesAsList', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getServiceTemplateFile = ({ templateName, filename }) => { + return new Promise((resolve, reject) => { + try { + const useTemplateName = filterBadPathStrings(templateName); + const useFilename = filterBadPathStrings(filename); + const { localTemplatesPath, localServicesRelativePath, serviceFiles } = settings.paths; + const servicePath = path.join(localTemplatesPath, localServicesRelativePath, useTemplateName); + if (!fs.existsSync(servicePath)) { + return reject({ + component: 'TemplatesController::getServiceTemplateFile', + message: `Service '${templateName}' doesn't exist.` + }); + } + + const serviceFilesPath = path.join(servicePath, serviceFiles); + + if (!fs.existsSync(serviceFilesPath)) { + return reject({ + component: 'TemplatesController::getServiceTemplateFile', + message: `Service '${templateName}' doesn't have any files to share.` + }); + } + + const filePath = path.join(serviceFilesPath, useFilename); + + if (fs.existsSync(filePath)) { + return resolve(filePath); + } + return reject({ + component: 'TemplatesController::getServiceTemplateFile', + message: `File '${filename}' doesn't exist for service '${templateName}'` + }); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ templateName }); + console.debug({ filename }); + return reject({ + component: 'TemplatesController::getServiceTemplateFile', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getScriptTemplateFile = ({ scriptName, options, req }) => { + return new Promise(async (resolve, reject) => { + try { + const useScriptTemplateName = filterBadPathStrings(scriptName); + const { localTemplatesPath, localScriptsRelativePath } = settings.paths; + const scriptPath = path.join(localTemplatesPath, localScriptsRelativePath, useScriptTemplateName); + if (!fs.existsSync(`${scriptPath}.js`)) { + return reject({ + component: 'TemplatesController::getScriptTemplateFile', + message: `Script '${scriptName}' doesn't exist.` + }); + } + + delete require.cache[require.resolve(scriptPath)]; + const scriptToSend = require(scriptPath); + + const results = await scriptToSend({ + req, + scriptName, + options, + server, + settings, + version, + logger + }); + + return resolve(results); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ scriptName }); + return reject({ + component: 'TemplatesController::getScriptTemplateFile', + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} +module.exports = TemplatesController; diff --git a/.internal/api/src/httpInit.js b/.internal/api/src/httpInit.js new file mode 100644 index 000000000..ba5ffb2b5 --- /dev/null +++ b/.internal/api/src/httpInit.js @@ -0,0 +1,30 @@ +var serverController = ({ logger, listenInterface, listenPort, settings, version } = {}) => { + const express = require('express'); + const middlewares = require('./middlewares/index'); + const routes = require('./routes/index'); + + return new Promise((resolve, reject) => { + try { + const server = express(); + + server.on('error', (err) => { + logger.error(err); + return reject(err); + }); + + middlewares({ app: server, cors: settings.cors, version, logger }); + routes({ server, settings, version, logger }); + + server.listen(listenPort, listenInterface, () => { + logger.info(`Listening on: ${listenInterface}:${listenPort}`); + return resolve(server); + }); + } catch(err) { + logger.error(JSON.stringify(err, Object.getOwnPropertyNames(err))); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + + }); +} + +module.exports = serverController; \ No newline at end of file diff --git a/.internal/api/src/index.js b/.internal/api/src/index.js new file mode 100644 index 000000000..d19bda475 --- /dev/null +++ b/.internal/api/src/index.js @@ -0,0 +1,110 @@ +let appVersion = require('../package.json').version; + +let listenInterface = '0.0.0.0'; +let listenPort = '32128'; +let additionalCorsList = []; + +const processCliArgs = (args) => { + for (let i = 0; i < args.length; i++) { + switch (args[i]) { + + case '-if': + case '--listen-interface': { + listenInterface = args[i + 1]; + i++; + break; + } + + case '-cors': + case '--cors': { + try { + additionalCorsList = [ + ...additionalCorsList, + ...args[i + 1]?.split(',') ?? [] + ]; + } catch (err) { + console.error('processCliArgs: Error on cors:'); + console.error(err); + process.exit(1); + } + i++; + break; + } + + case '-p': + case '--port': { + try { + if (Number.isFinite(Number.parseInt(args[i + 1]))) { + listenPort = args[i + 1]; + i++; + continue; + } + console.error(`listenPort '${args[i + 1]}' is not a number.`); + } catch (err) { + console.error('processCliArgs: Error on parseInt:'); + console.error(err); + process.exit(1); + } + break; + } + } + } +}; + +const checkCliParams = () => { + const errorList = []; + if (!listenInterface) { + errorList.push(`[-if]: Listen interface not set.`); + } + + if (!listenPort) { + errorList.push(`[-p]: Listen port not set.`); + } + + if (errorList.length > 0) { + throw new Error(errorList.join("\r\n")); + } +}; + +const processEnvVars = (envs) => { + const { cors, CORS } = envs; + + try { + additionalCorsList = [ + ...additionalCorsList, + ...cors?.split(',') ?? [] + ]; + additionalCorsList = [ + ...additionalCorsList, + ...CORS?.split(',') ?? [] + ]; + } catch (err) { + console.error('processEnvVars: Error on cors:'); + console.error(err); + process.exit(1); + } +}; + +const init = () => { + const logger = require('./logger')(); + + logger.info(`IOTstack API Server has started. Version: '${appVersion}', Environment: '${process.env.NODE_ENV}'`); + const settings = require('./settings')({ env: process.env.NODE_ENV, version: appVersion, logger }); + settings.cors.origins = [ + ...settings?.cors?.origins ?? [], + ...additionalCorsList + ]; + const serverSetupPromise = require('./httpInit')({ logger, listenInterface, listenPort, version: appVersion, settings }); + + serverSetupPromise.then((runningServer) => { + logger.info('Server ready.'); + }).catch((err) => { + logger.error({ module: 'Main::Init()', section: 'serverSetupPromise', message: `${err}, stack: ${err.stack}` }); + process.exit(2); + }); +} + +processCliArgs(process.argv); +checkCliParams(); +processEnvVars(process.env) +init(); \ No newline at end of file diff --git a/.internal/api/src/logger.js b/.internal/api/src/logger.js new file mode 100644 index 000000000..a00fd1be6 --- /dev/null +++ b/.internal/api/src/logger.js @@ -0,0 +1,13 @@ +const Logger = () => { + const retr = {}; + + retr.debug = console.debug; + retr.info = console.info; + retr.log = console.log; + retr.warn = console.warn; + retr.error = console.error; + + return retr; +} + +module.exports = Logger; \ No newline at end of file diff --git a/.internal/api/src/middlewares/cors.js b/.internal/api/src/middlewares/cors.js new file mode 100644 index 000000000..94f87a50f --- /dev/null +++ b/.internal/api/src/middlewares/cors.js @@ -0,0 +1,23 @@ +const registerCors = ({ server, corsList, headerList, allowHttp = false, logger } = {}) => { + server.use((req, res, next) => { + const origin = req.headers.origin ? req.headers.origin.replace(/(^\w+:|^)\/\//, '') : ''; + const foundHeader = corsList.indexOf(origin) > -1 ? origin : ''; + + if (foundHeader) { + if (allowHttp) { + res.setHeader('Access-Control-Allow-Origin', `http://${foundHeader}`); + } else { + res.setHeader('Access-Control-Allow-Origin', `https://${foundHeader}`); + } + + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE, HEAD'); + res.setHeader('Access-Control-Allow-Headers', headerList.join(',')); + res.setHeader('Access-Control-Allow-Credentials', true); + } + next(); + }); + + logger.info(`Cors settings loaded: Origins: [${corsList}] Headers: [${headerList}] Allow HTTP: ${allowHttp.toString()}.`); +}; + +module.exports = registerCors; \ No newline at end of file diff --git a/.internal/api/src/middlewares/index.js b/.internal/api/src/middlewares/index.js new file mode 100644 index 000000000..de775a25c --- /dev/null +++ b/.internal/api/src/middlewares/index.js @@ -0,0 +1,19 @@ +const registerMiddlewareHooks = ({ app, cors, logger } = {}) => { + const bodyParser = require('body-parser'); + + app.use(bodyParser.urlencoded({ extended: false })); + app.use(bodyParser.json()); + app.disable('x-powered-by'); + + const corsMiddleware = require('./cors'); + + corsMiddleware({ + server: app, + corsList: cors.origins, + headerList: cors.headers, + allowHttp: process.env.APP_ENV !== 'production', + logger + }); +}; + +module.exports = registerMiddlewareHooks; \ No newline at end of file diff --git a/.internal/api/src/routes/build.js b/.internal/api/src/routes/build.js new file mode 100644 index 000000000..406f44d0e --- /dev/null +++ b/.internal/api/src/routes/build.js @@ -0,0 +1,29 @@ +const registerBuildRoutes = ({ server, settings, version, logger } = {}) => { + const BuildView = require('../views/build'); + + const buildView = BuildView({ server, settings, version, logger }); + + buildView.init(); + + server.post('/build/save', (req, res, next) => { + buildView.buildStack(req, res, next); + }); + + server.post('/build/dryrun', (req, res, next) => { + buildView.checkIssues(req, res, next); + }); + + server.get('/build/list', (req, res, next) => { + buildView.getPreviousBuildsList(req, res, next); + }); + + server.get('/build/get/:buildTime', (req, res, next) => { + buildView.getPreviousBuildsList(req, res, next); + }); + + server.get('/build/get/:buildTime/:type', (req, res, next) => { + buildView.downloadPreviousBuildsList(req, res, next); + }); +}; + +module.exports = registerBuildRoutes; diff --git a/.internal/api/src/routes/configs.js b/.internal/api/src/routes/configs.js new file mode 100644 index 000000000..7b5389e26 --- /dev/null +++ b/.internal/api/src/routes/configs.js @@ -0,0 +1,45 @@ +const registerConfigRoutes = ({ server, settings, version, logger } = {}) => { + const ConfigView = require('../views/configs'); + + const configView = ConfigView({ server, settings, version, logger }); + + configView.init(); + + server.get('/config/:serviceName/options', (req, res, next) => { + configView.getConfigOptions(req, res, next); + }); + + server.get('/config/:serviceName/help', (req, res, next) => { + configView.getHelp(req, res, next); + }); + + server.get('/config/:serviceName/scripts', (req, res, next) => { + configView.getScripts(req, res, next); + }); + + server.get('/config/:serviceName/commands', (req, res, next) => { + configView.getScripts(req, res, next); + }); + + server.get('/config/:serviceName/scripts/:scriptName', (req, res, next) => { + configView.getScripts(req, res, next); + }); + + server.get('/config/:serviceName/script/:scriptName', (req, res, next) => { + configView.getScripts(req, res, next); + }); + + server.get('/config/:serviceName/commands/:scriptName', (req, res, next) => { + configView.getScripts(req, res, next); + }); + + server.get('/config/:serviceName/command/:scriptName', (req, res, next) => { + configView.getScripts(req, res, next); + }); + + server.get('/config/:serviceName/meta', (req, res, next) => { + configView.getMeta(req, res, next); + }); +}; + +module.exports = registerConfigRoutes; diff --git a/.internal/api/src/routes/health.js b/.internal/api/src/routes/health.js new file mode 100644 index 000000000..02b5763fd --- /dev/null +++ b/.internal/api/src/routes/health.js @@ -0,0 +1,25 @@ +const registerHealthRoutes = ({ server, settings, version, logger } = {}) => { + const HealthView = require('../views/health'); + + const healthView = HealthView({ server, settings, version, logger }); + + healthView.init(); + + server.post('/health', (req, res, next) => { + healthView.health(req, res, next); + }); + + server.post('/ping', (req, res, next) => { + healthView.health(req, res, next); + }); + + server.get('/health', (req, res, next) => { + healthView.health(req, res, next); + }); + + server.get('/ping', (req, res, next) => { + healthView.health(req, res, next); + }); +}; + +module.exports = registerHealthRoutes; \ No newline at end of file diff --git a/.internal/api/src/routes/index.js b/.internal/api/src/routes/index.js new file mode 100644 index 000000000..41b04b490 --- /dev/null +++ b/.internal/api/src/routes/index.js @@ -0,0 +1,17 @@ +const registerRouteHooks = ({ server, settings, version, logger } = {}) => { + + const healthRoutes = require('./health'); + healthRoutes({ server, settings, version, logger }); + + const templatesRoutes = require('./templates'); + templatesRoutes({ server, settings, version, logger }); + + const buildRoutes = require('./build'); + buildRoutes({ server, settings, version, logger }); + + const configRoutes = require('./configs'); + configRoutes({ server, settings, version, logger }); + +}; + +module.exports = registerRouteHooks; \ No newline at end of file diff --git a/.internal/api/src/routes/templates.js b/.internal/api/src/routes/templates.js new file mode 100644 index 000000000..cee0c1a24 --- /dev/null +++ b/.internal/api/src/routes/templates.js @@ -0,0 +1,69 @@ +const registerTemplatesRoutes = ({ server, settings, version, logger } = {}) => { + const TemplatesView = require('../views/templates'); + + const templatesView = TemplatesView({ server, settings, version, logger }); + + templatesView.init(); + + server.get('/templates/services/:templateName/file/:filename', (req, res, next) => { + templatesView.getServiceTemplateFile(req, res, next); + }); + + server.get('/templates/services/yaml', (req, res, next) => { + templatesView.getAllServiceTemplatesAsYaml(req, res, next); + }); + + server.get('/templates/services/json', (req, res, next) => { + templatesView.getAllServiceTemplatesAsJson(req, res, next); + }); + + server.get('/templates/services/list', (req, res, next) => { + templatesView.getAllServiceTemplatesAsList(req, res, next); + }); + + server.get('/templates/services/yaml/:templateName', (req, res, next) => { + templatesView.getServiceTemplateAsYaml(req, res, next); + }); + + server.get('/templates/services/json/:templateName', (req, res, next) => { + templatesView.getServiceTemplateAsJson(req, res, next); + }); + + server.get('/templates/networks/yaml', (req, res, next) => { + templatesView.getAllNetworkTemplatesAsYaml(req, res, next); + }); + + server.get('/templates/networks/json', (req, res, next) => { + templatesView.getAllNetworkTemplatesAsJson(req, res, next); + }); + + server.get('/templates/networks/list', (req, res, next) => { + templatesView.getAllNetworkTemplatesAsList(req, res, next); + }); + + server.get('/templates/networks/yaml/:templateName', (req, res, next) => { + templatesView.getNetworkTemplateAsYaml(req, res, next); + }); + + server.get('/templates/networks/json/:templateName', (req, res, next) => { + templatesView.getNetworkTemplateAsJson(req, res, next); + }); + + server.get('/templates/scripts/:scriptName*', (req, res, next) => { + templatesView.getScriptTemplate(req, res, next); + }); + + server.get('/templates/scripts/download/:scriptName*', (req, res, next) => { + templatesView.downloadScriptTemplate(req, res, next); + }); + + server.post('/templates/scripts/:scriptName*', (req, res, next) => { + templatesView.getScriptTemplate(req, res, next); + }); + + server.post('/templates/scripts/download/:scriptName*', (req, res, next) => { + templatesView.downloadScriptTemplate(req, res, next); + }); +}; + +module.exports = registerTemplatesRoutes; \ No newline at end of file diff --git a/.internal/api/src/services/builds.js b/.internal/api/src/services/builds.js new file mode 100644 index 000000000..07b335bd1 --- /dev/null +++ b/.internal/api/src/services/builds.js @@ -0,0 +1,70 @@ +const BuildsService = ({ server, settings, version, logger }) => { + const path = require('path'); + const yaml = require('js-yaml'); + const fs = require('fs'); + const retr = {}; + + retr.init = () => { + logger.debug('BuildsService:init()'); + }; + + retr.saveBuildYaml = ({ buildJson, fileTimePrefix }) => { + return new Promise((resolve, reject) => { + let yamlOutputFilePath; + try { + const { localBuildsDirectory, buildDockerFilePostfix } = settings.paths; + const yamlFilename = `${fileTimePrefix}${buildDockerFilePostfix}`; + yamlOutputFilePath = path.join(localBuildsDirectory, yamlFilename); + + let yamlDoc = yaml.safeDump(buildJson, { scalarQuoteStyle: 'double' }); + yamlDoc = yamlDoc.replace(/'/g, '"'); // { scalarQuoteStyle: 'double' } doesn't seem to be working + + fs.writeFileSync(yamlOutputFilePath, yamlDoc, 'utf8'); + return resolve({ yamlOutputFilePath, yamlFilename }); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ buildJson }); + console.debug({ fileTimePrefix }); + console.debug({ yamlOutputFilePath }); + return reject({ + component: 'BuildsService::saveBuildYaml', + message: 'Error saving yaml to file.', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.saveBuildOptions = ({ buildOptionsJson, fileTimePrefix }) => { + return new Promise((resolve, reject) => { + let jsonOutputFilePath; + try { + const { localBuildsDirectory, buildOptionsFilePostfix } = settings.paths; + const jsonFilename = `${fileTimePrefix}${buildOptionsFilePostfix}`; + jsonOutputFilePath = path.join(localBuildsDirectory, jsonFilename); + + let jsonDoc = JSON.stringify(buildOptionsJson); + + fs.writeFileSync(jsonOutputFilePath, jsonDoc, 'utf8'); + return resolve({ jsonOutputFilePath, jsonFilename }); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ buildOptionsJson }); + console.debug({ fileTimePrefix }); + console.debug({ jsonOutputFilePath }); + return reject({ + component: 'BuildsService::saveBuildOptions', + message: 'Error saving json to file.', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} +module.exports = BuildsService; diff --git a/.internal/api/src/services/templates.js b/.internal/api/src/services/templates.js new file mode 100644 index 000000000..8701fcf65 --- /dev/null +++ b/.internal/api/src/services/templates.js @@ -0,0 +1,67 @@ +const TemplatesService = ({ server, settings, version, logger }) => { + const path = require('path'); + const yaml = require('js-yaml'); + const fs = require('fs'); + const retr = {}; + + retr.init = () => { + logger.debug('TemplatesService:init()'); + }; + + retr.getServiceTemplateFromFile = (templateName, jsonified = false) => { + return new Promise((resolve, reject) => { + let templateYamlPath + try { + const { localTemplatesPath, localServicesRelativePath, localServicesTemplateYamlFilename } = settings.paths; + templateYamlPath = path.join(localTemplatesPath, localServicesRelativePath, templateName, localServicesTemplateYamlFilename); + if (jsonified) { + const yamlDoc = yaml.safeLoad(fs.readFileSync(templateYamlPath, 'utf8')); + return resolve(yamlDoc); + } + const yamlDoc = yaml.dump(yaml.safeLoad(fs.readFileSync(templateYamlPath, 'utf8'))); + return resolve(yamlDoc); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ templateName }); + console.debug({ templateYamlPath }); + return reject({ + component: 'TemplatesService::getServiceTemplateFromFile', + message: 'Error getting yaml template from file.', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.getNetworkTemplateFromFile = (templateName, jsonified = false) => { + return new Promise((resolve, reject) => { + let templateYamlPath + try { + const { localTemplatesPath, localNetworksRelativePath, localNetworkTemplateYamlFilename } = settings.paths; + templateYamlPath = path.join(localTemplatesPath, localNetworksRelativePath, templateName, localNetworkTemplateYamlFilename); + if (jsonified) { + const yamlDoc = yaml.safeLoad(fs.readFileSync(templateYamlPath, 'utf8')); + return resolve(yamlDoc); + } + const yamlDoc = yaml.dump(yaml.safeLoad(fs.readFileSync(templateYamlPath, 'utf8'))); + return resolve(yamlDoc); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ templateName }); + console.debug({ templateYamlPath }); + return reject({ + component: 'TemplatesService::getNetworkTemplateFromFile', + message: 'Error getting yaml template from file.', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} +module.exports = TemplatesService; diff --git a/.internal/api/src/services/zip.js b/.internal/api/src/services/zip.js new file mode 100644 index 000000000..16af97331 --- /dev/null +++ b/.internal/api/src/services/zip.js @@ -0,0 +1,82 @@ +const ZipService = ({ server, settings, version, logger }) => { + const path = require('path'); + const archiver = require('archiver'); + const fs = require('fs'); + const retr = {}; + + retr.init = () => { + logger.debug('ZipService:init()'); + }; + + retr.zipFiles = ({ fileList, fileTimePrefix, archiveDirectoryList = [] }) => { + return new Promise((resolve, reject) => { + let zipOutputFilePath; + try { + const { localBuildsDirectory, buildZipFilePostfix } = settings.paths; + const zipFilename = `${fileTimePrefix}${buildZipFilePostfix}`; + zipOutputFilePath = path.join(localBuildsDirectory, zipFilename); + + const outputStream = fs.createWriteStream(zipOutputFilePath); + const archive = archiver('zip', { + zlib: { level: 9 } // Sets the compression level. + }); + + archive.on('warning', (err) => { + console.log({ + component: 'ZipService::zipFiles', + message: 'A warning was raised', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + + // good practice to catch this error explicitly + archive.on('error', (err) => { + console.error({ + component: 'ZipService::zipFiles', + message: 'A warning was raised', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + return reject({ + component: 'ZipService::zipFiles', + message: 'Error saving zip.', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }) + }); + + outputStream.on('close', () => { + console.debug(`Zip '${zipFilename}' created (${archive.pointer()} bytes) Files given: '${fileList.length}'.`); + return resolve({ zipFilename, zipOutputFilePath }); + }); + + archive.pipe(outputStream); + + if (Array.isArray(archiveDirectoryList) && archiveDirectoryList.length > 0) { + archiveDirectoryList.forEach((directoryName) => { + archive.append(null, { name: directoryName }); + }); + } + + fileList.forEach((filename) => { + archive.file(filename.fullPath, { name: filename.zipName }); + }); + + return archive.finalize(); + } catch (err) { + console.log(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ fileList }); + console.debug({ fileTimePrefix }); + console.debug({ zipOutputFilePath }); + return reject({ + component: 'ZipService::zipFiles', + message: 'Error saving zip.', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} +module.exports = ZipService; diff --git a/.internal/api/src/settings.js b/.internal/api/src/settings.js new file mode 100644 index 000000000..435102ebb --- /dev/null +++ b/.internal/api/src/settings.js @@ -0,0 +1,34 @@ +const Settings = ({ env, logger, version }) => { + const path = require('path'); + + logger.info(`Settings loaded. env: '${env}', AppVersion: '${version}'`); + + const retr = { + cors: { + origins: ["localhost", "127.0.0.1", "localhost:32777", "127.0.0.1:32777"], + headers: ["Content-Type" ,"Origin", "Accept"] + }, + paths: { + localTemplatesPath: path.join(__dirname, '../templates/'), + localTmpPath: path.join(__dirname, '/.tmp/'), + localBuildsDirectory: path.join(__dirname, '../builds/'), + localServicesRelativePath: '/services/', + localNetworksRelativePath: '/networks/', + localScriptsRelativePath: '/scripts/', + localServicesTemplateYamlFilename: 'template.yml', + localNetworkTemplateYamlFilename: 'template.yml', + localServicesTemplateConfig: 'template.js', + buildLogicFile: 'build.js', + configLogicFile: 'config.js', + buildDockerFilePostfix: '_docker-compose-base.yml', + buildOptionsFilePostfix: '_build-options.json', + buildZipFilePostfix: '_build.zip', + buildInstallerFilePostfix: '_installer.sh', + serviceFiles: '/serviceFiles/', + buildFiles: '/buildFiles/' + } + }; + return retr; +} + +module.exports = Settings; diff --git a/.internal/api/src/utils/date.js b/.internal/api/src/utils/date.js new file mode 100644 index 000000000..cfa8d6dd2 --- /dev/null +++ b/.internal/api/src/utils/date.js @@ -0,0 +1,11 @@ +const { pad } = require('./pad'); + +const formatDate = (currentDate) => { + const useDate = Number.isFinite(Date.parse(currentDate)) ? currentDate : new Date(); + + return `${pad(useDate.getFullYear(), 4)}-${pad((useDate.getMonth() + 1), 2)}-${pad(useDate.getDate(), 2)}T${pad(useDate.getHours(), 2)}-${pad(useDate.getMinutes(), 2)}-${pad(useDate.getSeconds(), 2)}`; +}; + +module.exports = { + formatDate +}; diff --git a/.internal/api/src/utils/fsUtils.js b/.internal/api/src/utils/fsUtils.js new file mode 100644 index 000000000..7d17308d4 --- /dev/null +++ b/.internal/api/src/utils/fsUtils.js @@ -0,0 +1,45 @@ +const fs = require('fs'); +const path = require('path'); + +const filterBadPathStrings = (inputPath) => { + let filteredPath = inputPath.split('..').join(''); + filteredPath = inputPath.split('~/').join(''); + + return filteredPath; +} + +const getDirectoryList = (directoryPath) => { + const filteredPath = filterBadPathStrings(directoryPath); + return fs.readdirSync(filteredPath, { withFileTypes: true }) + .filter((dirent) => { return dirent.isDirectory(); }) + .map((dirent) => { return dirent.name; }); +}; + +const getFileList = (directoryPath) => { + const filteredPath = filterBadPathStrings(directoryPath); + return fs.readdirSync(filteredPath, { withFileTypes: true }) + .filter((dirent) => { return !dirent.isDirectory(); }) + .map((dirent) => { return dirent.name; }); +}; + +const emptyDirectory = (directoryPath, ignoreList) => { + fs.readdir(directoryPath, (err, files) => { + if (err) throw err; + files.forEach((file) => { + if (Array.isArray(ignoreList) && ignoreList.indexOf(file) > -1) { + return; + } + + fs.unlink(path.join(directoryPath, file), err => { + if (err) throw err; + }); + }); + }); +}; + +module.exports = { + getDirectoryList, + getFileList, + emptyDirectory, + filterBadPathStrings +}; diff --git a/.internal/api/src/utils/interpolate.js b/.internal/api/src/utils/interpolate.js new file mode 100644 index 000000000..59bfd9eeb --- /dev/null +++ b/.internal/api/src/utils/interpolate.js @@ -0,0 +1,8 @@ +const byName = (formatString, replacements) => Object.keys(replacements).reduce( + (result, name) => result.replace(`{$${name}}`, replacements[name]), + formatString || '' +); + +module.exports = { + byName +}; \ No newline at end of file diff --git a/.internal/api/src/utils/networkUtils.js b/.internal/api/src/utils/networkUtils.js new file mode 100644 index 000000000..e9c14f4f0 --- /dev/null +++ b/.internal/api/src/utils/networkUtils.js @@ -0,0 +1,24 @@ +const getUniqueNetworkListFromServices = ({ services, logger }) => { + try { + const networkList = []; + Object.keys(services).forEach((serviceName) => { + if (Array.isArray(services[serviceName].networks)) { + services[serviceName].networks.forEach((networkName) => { + if (networkList.indexOf(networkName) < 0) { + networkList.push(networkName); + } + }); + } + }); + + return networkList; + } catch (err) { + logger.error(err); + console.trace(); + return []; + } +}; + +module.exports = { + getUniqueNetworkListFromServices +}; diff --git a/.internal/api/src/utils/pad.js b/.internal/api/src/utils/pad.js new file mode 100644 index 000000000..002508392 --- /dev/null +++ b/.internal/api/src/utils/pad.js @@ -0,0 +1,18 @@ +const pad = (str, size, withChar = "0", atEnd = false) => { + let s = str + ""; + if (atEnd) { + while (s.length < size) { + s = s + withChar; + } + } else { + while (s.length < size) { + s = withChar + s; + } + } + + return s; +}; + +module.exports = { + pad +}; diff --git a/.internal/api/src/views/build.js b/.internal/api/src/views/build.js new file mode 100644 index 000000000..956d5a0c1 --- /dev/null +++ b/.internal/api/src/views/build.js @@ -0,0 +1,117 @@ +const BuildView = ({ server, settings, version, logger } = {}) => { + const BuildsController = require('../controllers/build'); + const retr = {}; + + const buildsController = BuildsController({ server, settings, version, logger }); + + retr.init = () => { + buildsController.init(); + }; + + retr.buildStack = (req, res, next) => { + try { + const { buildOptions } = req.body; + buildsController.buildStack({ buildOptions }).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'BuildView::buildStack', + message: 'Error getting yaml template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'BuildView::buildStack', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + retr.checkIssues = (req, res, next) => { + try { + const { buildOptions } = req.body; + buildsController.checkIssues({ buildOptions }).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'BuildView::checkIssues', + message: 'Error getting yaml template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'BuildView::checkIssues', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + retr.getPreviousBuildsList = (req, res, next) => { + const { buildTime } = req.params; + try { + buildsController.getPreviousBuildsList({ host: req.headers.host, buildTime }).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'BuildView::getPreviousBuildsList', + message: 'Error getting build', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'BuildView::getPreviousBuildsList', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + retr.downloadPreviousBuildsList = (req, res, next) => { + const { buildTime, type } = req.params; + try { + buildsController.downloadPreviousBuildsList({ host: req.headers.host, buildTime, type }).then((result) => { + if (!result.filename || !result.fullPath) { + return res.status(500).send({ + component: 'BuildView::downloadPreviousBuildsList', + message: 'Error getting build' + }); + } + + return res.download(result.fullPath, result.filename); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'BuildView::downloadPreviousBuildsList', + message: 'Error getting build', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'BuildView::downloadPreviousBuildsList', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + return retr; +}; + +module.exports = BuildView; diff --git a/.internal/api/src/views/configs.js b/.internal/api/src/views/configs.js new file mode 100644 index 000000000..2625a051d --- /dev/null +++ b/.internal/api/src/views/configs.js @@ -0,0 +1,110 @@ +const ConfigsView = ({ server, settings, version, logger } = {}) => { + const ConfigsController = require('../controllers/configs'); + const retr = {}; + + const configsController = ConfigsController({ server, settings, version, logger }); + + retr.init = () => { + configsController.init(); + }; + + retr.getConfigOptions = (req, res, next) => { + try { + const { serviceName } = req.params; + configsController.getConfigOptions({ serviceName }).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'ConfigsView::getConfigOptions', + message: 'Error getting config options', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'ConfigsView::getConfigOptions', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + retr.getHelp = (req, res, next) => { + try { + const { serviceName } = req.params; + configsController.getHelp({ serviceName }).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'ConfigsView::getHelp', + message: 'Error getting help', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'ConfigsView::getHelp', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + retr.getScripts = (req, res, next) => { + try { + const { serviceName, scriptName } = req.params; + configsController.getScripts({ serviceName, scriptName }).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'ConfigsView::getScripts', + message: 'Error getting scripts', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'ConfigsView::getScripts', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + retr.getMeta = (req, res, next) => { + try { + const { serviceName } = req.params; + configsController.getMeta({ serviceName }).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'ConfigsView::getMeta', + message: 'Error getting help', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + } catch (err) { + logger.error(err); + logger.log(req.body); + return res.status(500).send({ + component: 'ConfigsView::getMeta', + message: 'Unhandled error', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }; + + return retr; +}; + +module.exports = ConfigsView; diff --git a/.internal/api/src/views/health.js b/.internal/api/src/views/health.js new file mode 100644 index 000000000..09fd3b547 --- /dev/null +++ b/.internal/api/src/views/health.js @@ -0,0 +1,23 @@ +const HealthView = ({ server, settings, version, logger } = {}) => { + const HealthController = require('../controllers/health'); + const retr = {}; + + const healthController = HealthController({ server, settings, version, logger }); + + retr.init = () => { + healthController.init(); + }; + + retr.health = (req, res, next) => { + healthController.healthCheck().then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send(result); + }); + }; + + return retr; +}; + +module.exports = HealthView; diff --git a/.internal/api/src/views/templates.js b/.internal/api/src/views/templates.js new file mode 100644 index 000000000..b2c686d57 --- /dev/null +++ b/.internal/api/src/views/templates.js @@ -0,0 +1,207 @@ +const TemplatesView = ({ server, settings, version, logger } = {}) => { + const TemplatesController = require('../controllers/templates'); + const retr = {}; + + const templatesController = TemplatesController({ server, settings, version, logger }); + + retr.init = () => { + templatesController.init(); + }; + + retr.getServiceTemplateAsYaml = (req, res, next) => { + const { templateName } = req.params; + templatesController.getServiceTemplateAsYaml(templateName).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getServiceTemplateAsYaml', + message: 'Error getting yaml template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getServiceTemplateAsJson = (req, res, next) => { + const { templateName } = req.params; + templatesController.getServiceTemplateAsJson(templateName).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getServiceTemplateAsJson', + message: 'Error getting json template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getAllServiceTemplatesAsYaml = (req, res, next) => { + templatesController.getAllServiceTemplatesAsYaml().then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getAllServiceTemplatesAsYaml', + message: 'Error getting yaml templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getAllServiceTemplatesAsJson = (req, res, next) => { + templatesController.getAllServiceTemplatesAsJson().then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getAllServiceTemplatesAsJson', + message: 'Error getting json templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getAllServiceTemplatesAsList = (req, res, next) => { + templatesController.getAllServiceTemplatesAsList().then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getAllServiceTemplatesAsList', + message: 'Error getting templates list', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getNetworkTemplateAsYaml = (req, res, next) => { + const { templateName } = req.params; + templatesController.getNetworkTemplateAsYaml(templateName).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getNetworkTemplateAsYaml', + message: 'Error getting yaml template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getNetworkTemplateAsJson = (req, res, next) => { + const { templateName } = req.params; + templatesController.getNetworkTemplateAsJson(templateName).then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getNetworkTemplateAsJson', + message: 'Error getting json template', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getAllNetworkTemplatesAsYaml = (req, res, next) => { + templatesController.getAllNetworkTemplatesAsYaml().then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getAllNetworkTemplatesAsYaml', + message: 'Error getting yaml templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getAllNetworkTemplatesAsJson = (req, res, next) => { + templatesController.getAllNetworkTemplatesAsJson().then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getAllNetworkTemplatesAsJson', + message: 'Error getting json templates', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getAllNetworkTemplatesAsList = (req, res, next) => { + templatesController.getAllNetworkTemplatesAsList().then((result) => { + return res.send(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getAllNetworkTemplatesAsList', + message: 'Error getting templates list', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getServiceTemplateFile = (req, res, next) => { + const { templateName, filename } = req.params; + templatesController.getServiceTemplateFile({ templateName, filename }).then((result) => { + return res.download(result); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getServiceTemplateFile', + message: `Error getting template '${templateName}' file '${filename}'`, + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.getScriptTemplate = (req, res, next) => { + const { scriptName } = req.params; + const { options } = req.body; + templatesController.getScriptTemplateFile({ scriptName, options, req }).then((result) => { + return res.send(result.data); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::getScriptTemplate', + message: `Error getting script template '${scriptName}''`, + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + retr.downloadScriptTemplate = (req, res, next) => { + const { scriptName } = req.params; + const { options, contentTypeRequest } = req.body; + const allowedContentTypes = [ + 'text/plain', + 'text/csv', + 'text/html', + 'application/json' + ]; + + templatesController.getScriptTemplateFile({ scriptName, options, req }).then((result) => { + const buildFilename = (typeof result.filename !== 'string' || !result.filename) ? scriptName : result.filename; + + const useContentType = allowedContentTypes.includes(contentTypeRequest) ? contentTypeRequest : 'text/plain'; + res.set({ + 'Content-Disposition': `attachment; filename="${buildFilename}"`, + 'Content-Type': useContentType, + }); + + return res.send(result.data); + }).catch((err) => { + logger.error(err); + return res.status(500).send({ + component: 'TemplatesView::downloadScriptTemplate', + message: `Error getting script template '${scriptName}''`, + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + }); + }; + + return retr; +}; + +module.exports = TemplatesView; diff --git a/scripts/backup_restore.py b/.internal/cli/backup_restore.py old mode 100755 new mode 100644 similarity index 100% rename from scripts/backup_restore.py rename to .internal/cli/backup_restore.py diff --git a/scripts/buildstack_menu.py b/.internal/cli/buildstack_menu.py old mode 100755 new mode 100644 similarity index 100% rename from scripts/buildstack_menu.py rename to .internal/cli/buildstack_menu.py diff --git a/scripts/docker_commands.py b/.internal/cli/docker_commands.py old mode 100755 new mode 100644 similarity index 100% rename from scripts/docker_commands.py rename to .internal/cli/docker_commands.py diff --git a/scripts/menu_main.py b/.internal/cli/menu_main.py old mode 100755 new mode 100644 similarity index 100% rename from scripts/menu_main.py rename to .internal/cli/menu_main.py diff --git a/scripts/misc_commands.py b/.internal/cli/misc_commands.py old mode 100755 new mode 100644 similarity index 100% rename from scripts/misc_commands.py rename to .internal/cli/misc_commands.py diff --git a/scripts/native_installs.py b/.internal/cli/native_installs.py old mode 100755 new mode 100644 similarity index 100% rename from scripts/native_installs.py rename to .internal/cli/native_installs.py diff --git a/.internal/ctrl_api.sh b/.internal/ctrl_api.sh new file mode 100644 index 000000000..18fe48604 --- /dev/null +++ b/.internal/ctrl_api.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +VERSION=v0.0.1 +DNAME=iostack_api +FULL_NAME="$DNAME:$VERSION" + +if [[ $IOTENV == "development" ]]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker build --no-cache -t $FULL_NAME -f api.Dockerfile . +else + docker build -t $FULL_NAME -f api.Dockerfile . +fi + +if [ "$1" = "stop" ]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) +else + if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then + echo "Starting IOTstack API Server" + docker run -d -p 32128:32128 \ + --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ + --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds \ + --restart unless-stopped \ + $FULL_NAME + + # docker run -p 32128:32128 \ + # --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ + # --mount type=bind,source="$(pwd)"/builds,target=/usr/iotstack_api/builds,readonly \ + # -e cors="yourLanIpHere:32777" \ + # --restart unless-stopped \ + # $FULL_NAME + + # docker run -p 32128:32128 \ + # --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ + # --mount type=bind,source="$(pwd)"/builds,target=/usr/iotstack_api/builds,readonly \ + # --restart unless-stopped \ + # -it $FULL_NAME /bin/bash + else + echo "IOTstack API Server is running" + fi +fi diff --git a/.internal/ctrl_wui.sh b/.internal/ctrl_wui.sh new file mode 100644 index 000000000..f9a6a9525 --- /dev/null +++ b/.internal/ctrl_wui.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +VERSION=v0.0.1 +DNAME=iostack_wui +FULL_NAME="$DNAME:$VERSION" + +if [[ $IOTENV == "development" ]]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker build --no-cache -t $FULL_NAME -f wui.Dockerfile . +else + docker build -t $FULL_NAME -f wui.Dockerfile . +fi + +if [ "$1" = "stop" ]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) +else + if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then + echo "Starting IOTstack WUI Server" + docker run -d -p 32777:32777 -e PORT=32777 --restart unless-stopped $FULL_NAME + else + echo "IOTstack WUI Server is running" + fi + + # docker run -d -p 32777:32777 $FULL_NAME + # docker run -p 32777:32777 -e PORT=32777 $FULL_NAME + + # docker run -p 32777:32777 -it $FULL_NAME /bin/bash +fi diff --git a/.internal/docker_menu.sh b/.internal/docker_menu.sh new file mode 100644 index 000000000..345b7b0ce --- /dev/null +++ b/.internal/docker_menu.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +if [ "$1" = "stop" ]; then + bash ./ctrl_api.sh stop + bash ./ctrl_wui.sh stop + # bash ./ctrl_cli.sh stop +else + bash ./ctrl_api.sh + bash ./ctrl_wui.sh + # bash ./ctrl_cli.sh +fi diff --git a/.internal/saved_builds/.gitignore b/.internal/saved_builds/.gitignore new file mode 100644 index 000000000..3ae28ac87 --- /dev/null +++ b/.internal/saved_builds/.gitignore @@ -0,0 +1,4 @@ +*.yml +*.zip +*.sh +*.json diff --git a/.internal/templates/networks/iotstack_nw/template.yml b/.internal/templates/networks/iotstack_nw/template.yml new file mode 100644 index 000000000..96855f24b --- /dev/null +++ b/.internal/templates/networks/iotstack_nw/template.yml @@ -0,0 +1,9 @@ +iotstack_nw: # Exposed by your host. + # external: true + name: IOTstack_Net + driver: bridge + ipam: + driver: default + config: + - subnet: 10.77.60.0/24 + # - gateway: 10.77.60.1 diff --git a/.internal/templates/networks/iotstack_nw_internal/template.yml b/.internal/templates/networks/iotstack_nw_internal/template.yml new file mode 100644 index 000000000..613ad9cbe --- /dev/null +++ b/.internal/templates/networks/iotstack_nw_internal/template.yml @@ -0,0 +1,9 @@ +iotstack_nw_internal: # For interservice communication. No access to outside + name: IOTstack_Net_Internal + driver: bridge + internal: true + ipam: + driver: default + config: + - subnet: 10.77.76.0/24 + # - gateway: 10.77.76.1 diff --git a/.internal/templates/networks/nextcloud_internal/template.yml b/.internal/templates/networks/nextcloud_internal/template.yml new file mode 100644 index 000000000..9ec2b4436 --- /dev/null +++ b/.internal/templates/networks/nextcloud_internal/template.yml @@ -0,0 +1,4 @@ +nextcloud_internal: # Network for NextCloud service + name: IOTstack_NextCloud + driver: bridge + internal: true diff --git a/.internal/templates/networks/vpn_nw/template.yml b/.internal/templates/networks/vpn_nw/template.yml new file mode 100644 index 000000000..eb0d2031d --- /dev/null +++ b/.internal/templates/networks/vpn_nw/template.yml @@ -0,0 +1,8 @@ +vpn_nw: # Network specifically for VPN + name: IOTstack_VPN + driver: bridge + ipam: + driver: default + config: + - subnet: 10.77.88.0/24 + # - gateway: 192.18.200.1 diff --git a/.internal/templates/scripts/bootstrap.js b/.internal/templates/scripts/bootstrap.js new file mode 100644 index 000000000..eca665fe1 --- /dev/null +++ b/.internal/templates/scripts/bootstrap.js @@ -0,0 +1,49 @@ +const BootstrapScript = ({ + req, + scriptName, + options, + server, + settings, + version, + logger +}) => { + return new Promise((resolve, reject) => { + try { + const result = { + filename: 'scripts', + data: 'No Data' + }; + + if (!options) { + result.data = 'No options given'; + } + result.data = `Options given for ${scriptName} and ${options?.build}`; + + result.data = ` +# Download, extract and execute: +# Ensure you are in IOTstack's main directory. +$ curl http://${req.get('host')}/build/get/${options?.build}/zip \\ +--output iotstack_build_${options?.build}.zip \\ +&& unzip -o ./iotstack_build_${options?.build}.zip \\ +&& bash installer.sh --from-net --overwrite +`; + + return resolve(result); + } catch (err) { + console.error(err); + console.trace(); + console.trace(); + console.debug("\nParams:"); + console.debug({ scriptName }); + console.debug({ version }); + console.debug({ options }); + return reject({ + component: `BootstrapScript: - '${scriptName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); +}; + +module.exports = BootstrapScript; diff --git a/.internal/templates/scripts/build_installer.js b/.internal/templates/scripts/build_installer.js new file mode 100644 index 000000000..52a4343ce --- /dev/null +++ b/.internal/templates/scripts/build_installer.js @@ -0,0 +1,168 @@ +const renderPostbuildScripts = (scripts) => { + let contents = ''; + + if (Array.isArray(scripts)) { + scripts.forEach((script) => { + contents += ` +# Postbuild Service script: +# Injected by: ${script?.serviceName} +# Comment: ${script?.comment}`; + +if (script?.multilineComment) { + contents += ` +: <<'END_COMMENT' + +${script?.multilineComment} + +END_COMMENT + +`; +} +contents += ` +${script?.code} + +# End script (${script?.serviceName})`; + }); + } + + return contents; +}; + +const renderPrebuildScripts = (scripts) => { + let contents = ''; + + if (Array.isArray(scripts)) { + scripts.forEach((script) => { + contents += ` +# Prebuild Service script: +# Injected by: ${script?.serviceName} +# Comment: ${script?.comment}`; + +if (script?.multilineComment) { + contents += ` +: <<'END_COMMENT' + +${script?.multilineComment} + +END_COMMENT + +`; +} +contents += ` +${script?.code} + +# End script (${script?.serviceName})`; + }); + } + + return contents; +}; + +const BuildInstaller = ({ + scriptName, + options, + server, + settings, + version, + logger +}) => { + return new Promise((resolve, reject) => { + try { + const result = { + filename: 'scripts', + data: 'No Data' + }; + + result.data = ` +#!/bin/bash + +# IOTstack build installer +# Build: ${options?.build} +# API Version: ${version} + +# This script is automatically generated during build time +# To be executed at install time. + +FROM_NET="false" +PREREQ_CHECK="true" +OVERWRITE_EXISTING_ASK="true" +CLEAN_CURRENT="false" +DISPLAY_WARNINGS="true" +BAD_OPTION_TRIGGER="false" + +# Process input args +while test $# -gt 0 +do + case "$1" in + --from-net) FROM_NET="true" + ;; + --no-check) PREREQ_CHECK="false" + ;; + --overwrite) OVERWRITE_EXISTING_ASK="false" + ;; + --clean-current) CLEAN_CURRENT="true" + ;; + --no-warnings) DISPLAY_WARNINGS="false" + ;; + --*) echo "bad option $1" && BAD_OPTION_TRIGGER="true" + ;; + esac + shift +done + +if [[ $BAD_OPTION_TRIGGER == "true" ]]; then + if [[ $DISPLAY_WARNINGS == "true" ]]; then + echo "Bad option detected." + read -n 1 -t 5 -s -r -p "Press any key within 5 seconds to cancel build and exit " READIN + if [[ ! -z "$READIN" ]]; then + echo "" + echo "Exiting..." + exit 0 + fi + else + # Automatically exit if bad option detected and warnings are disabled. + exit 1 + fi +fi + +if [[ ! -f ./menu.sh ]]; then + echo "Couldn't detect menu.sh file for IOTstack. Ensure you are in the correct directory:" + pwd + exit 2 +fi + +#### Prebuild service scripts +${renderPrebuildScripts(options?.prebuildScripts)} + +#### End prebuild service scripts + + +# Merge docker-compose and docker-compose-overrides + + +#### Postbuild service scripts +${renderPostbuildScripts(options?.postbuildScripts)} + +#### End postbuild service scripts + +`; + + return resolve(result); + } catch (err) { + console.error(err); + console.trace(); + console.trace(); + console.debug("\nParams:"); + console.debug({ scriptName }); + console.debug({ version }); + console.debug({ options }); + return reject({ + component: `BuildInstaller: - '${scriptName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); +}; + +module.exports = BuildInstaller; diff --git a/.internal/templates/services/adminer/build.js b/.internal/templates/services/adminer/build.js new file mode 100644 index 000000000..0f67b61da --- /dev/null +++ b/.internal/templates/services/adminer/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'adminer'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/adminer/config.js b/.internal/templates/services/adminer/config.js new file mode 100644 index 000000000..74310bb8a --- /dev/null +++ b/.internal/templates/services/adminer/config.js @@ -0,0 +1,45 @@ +const adminer = () => { + const retr = {}; + + const serviceName = 'adminer'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9080:8080": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Adminer', + serviceTypeTags: ['wui', 'database manager'] + }; + }; + + return retr; +}; + +module.exports = adminer; diff --git a/.internal/templates/services/adminer/template.yml b/.internal/templates/services/adminer/template.yml new file mode 100644 index 000000000..15eb773f0 --- /dev/null +++ b/.internal/templates/services/adminer/template.yml @@ -0,0 +1,12 @@ +adminer: + container_name: adminer + image: adminer + restart: unless-stopped + ports: + - "9080:8080" + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/dashmachine/build.js b/.internal/templates/services/dashmachine/build.js new file mode 100644 index 000000000..e32e55905 --- /dev/null +++ b/.internal/templates/services/dashmachine/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'dashmachine'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/dashmachine/config.js b/.internal/templates/services/dashmachine/config.js new file mode 100644 index 000000000..35227a91a --- /dev/null +++ b/.internal/templates/services/dashmachine/config.js @@ -0,0 +1,45 @@ +const dashmachine = () => { + const retr = {}; + + const serviceName = 'dashmachine'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "5000:5000": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'DashMachine', + serviceTypeTags: ['wui', 'dashboard'] + }; + }; + + return retr; +}; + +module.exports = dashmachine; diff --git a/.internal/templates/services/dashmachine/template.yml b/.internal/templates/services/dashmachine/template.yml new file mode 100644 index 000000000..096cb36b6 --- /dev/null +++ b/.internal/templates/services/dashmachine/template.yml @@ -0,0 +1,8 @@ +dashmachine: + image: rmountjoy/dashmachine:latest + container_name: dashmachine + volumes: + - ./volumes/dashmachine/user_data:/dashmachine/dashmachine/user_data + ports: + - "5000:5000" + restart: unless-stopped diff --git a/.internal/templates/services/domoticz/build.js b/.internal/templates/services/domoticz/build.js new file mode 100644 index 000000000..ee67fd9a7 --- /dev/null +++ b/.internal/templates/services/domoticz/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'domoticz'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/domoticz/config.js b/.internal/templates/services/domoticz/config.js new file mode 100644 index 000000000..e3257d1ee --- /dev/null +++ b/.internal/templates/services/domoticz/config.js @@ -0,0 +1,45 @@ +const domoticz = () => { + const retr = {}; + + const serviceName = 'domoticz'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8080:8080": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Domoticz', + serviceTypeTags: ['wui', 'dashboard', 'home automation', 'iot', 'z-wave'] + }; + }; + + return retr; +}; + +module.exports = domoticz; diff --git a/.internal/templates/services/domoticz/template.yml b/.internal/templates/services/domoticz/template.yml new file mode 100644 index 000000000..1ec55e016 --- /dev/null +++ b/.internal/templates/services/domoticz/template.yml @@ -0,0 +1,19 @@ +domoticz: + container_name: domoticz + image: linuxserver/domoticz:stable + ports: + - "8080:8080" + - "6144:6144" + - "1443:1443" + volumes: + - ./volumes/domoticz/data:/config + env_file: + - ./services/domoticz/domoticz.env + restart: unless-stopped + network_mode: bridge + environment: + PUID=1000 + PGID=1000 + #TZ= + #WEBROOT=domoticz #optional + diff --git a/.internal/templates/services/dozzle/build.js b/.internal/templates/services/dozzle/build.js new file mode 100644 index 000000000..61e6bab5d --- /dev/null +++ b/.internal/templates/services/dozzle/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'dozzle'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/dozzle/config.js b/.internal/templates/services/dozzle/config.js new file mode 100644 index 000000000..eab3f2e1d --- /dev/null +++ b/.internal/templates/services/dozzle/config.js @@ -0,0 +1,45 @@ +const dozzle = () => { + const retr = {}; + + const serviceName = 'dozzle'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8888:8080": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Dozzle', + serviceTypeTags: ['logs', 'docker', 'container manager', 'wui'] + }; + }; + + return retr; +}; + +module.exports = dozzle; diff --git a/.internal/templates/services/dozzle/template.yml b/.internal/templates/services/dozzle/template.yml new file mode 100644 index 000000000..614dea9e7 --- /dev/null +++ b/.internal/templates/services/dozzle/template.yml @@ -0,0 +1,13 @@ +dozzle: + container_name: dozzle + image: amir20/dozzle:latest + restart: unless-stopped + network_mode: host + ports: + - "8888:8080" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/espruinohub/build.js b/.internal/templates/services/espruinohub/build.js new file mode 100644 index 000000000..b9501e6a0 --- /dev/null +++ b/.internal/templates/services/espruinohub/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'espruinohub'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/espruinohub/config.js b/.internal/templates/services/espruinohub/config.js new file mode 100644 index 000000000..25df42fe5 --- /dev/null +++ b/.internal/templates/services/espruinohub/config.js @@ -0,0 +1,42 @@ +const espruinohub = () => { + const retr = {}; + + const serviceName = 'espruinohub'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'EspruinoHub', + serviceTypeTags: ['mqtt', 'ble', 'rpi only'] + }; + }; + + return retr; +}; + +module.exports = espruinohub; diff --git a/.internal/templates/services/espruinohub/template.yml b/.internal/templates/services/espruinohub/template.yml new file mode 100644 index 000000000..572ba46fe --- /dev/null +++ b/.internal/templates/services/espruinohub/template.yml @@ -0,0 +1,10 @@ +espruinohub: + container_name: espruinohub + image: humbertosales/espruinohub-docker-rpi + network_mode: host + privileged: true + restart: unless-stopped + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/gitea/build.js b/.internal/templates/services/gitea/build.js new file mode 100644 index 000000000..56ad28e47 --- /dev/null +++ b/.internal/templates/services/gitea/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'gitea'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/gitea/data +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/gitea/data ]]; then + echo "Gitea data directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/gitea/config.js b/.internal/templates/services/gitea/config.js new file mode 100644 index 000000000..b32b4b73a --- /dev/null +++ b/.internal/templates/services/gitea/config.js @@ -0,0 +1,45 @@ +const gitea = () => { + const retr = {}; + + const serviceName = 'gitea'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9080:8080": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Gitea', + serviceTypeTags: ['wui', 'git'] + }; + }; + + return retr; +}; + +module.exports = gitea; diff --git a/.internal/templates/services/gitea/template.yml b/.internal/templates/services/gitea/template.yml new file mode 100644 index 000000000..d851d2de8 --- /dev/null +++ b/.internal/templates/services/gitea/template.yml @@ -0,0 +1,21 @@ +gitea: + container_name: gitea + image: "kunde21/gitea-arm:latest" + # image: "gitea/gitea" # x64 + restart: unless-stopped + ports: + - "7920:3000/tcp" + - "2222:22/tcp" + environment: + - USER_UID=1000 + - USER_GID=1000 + volumes: + - ./volumes/gitea/data:/data + - /etc/timezone:/etc/timezone:ro + # - /etc/localtime:/etc/localtime:ro + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/grafana/build.js b/.internal/templates/services/grafana/build.js new file mode 100644 index 000000000..5b915e6f7 --- /dev/null +++ b/.internal/templates/services/grafana/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'grafana'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/grafana/config.js b/.internal/templates/services/grafana/config.js new file mode 100644 index 000000000..205343fe0 --- /dev/null +++ b/.internal/templates/services/grafana/config.js @@ -0,0 +1,56 @@ +const grafana = () => { + const retr = {}; + + const serviceName = 'grafana'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "3000:3000": 'http' + }, + modifyableEnvironment: [ + { + key: 'GF_PATHS_DATA', + value: '/var/lib/grafana' + }, + { + key: 'GF_PATHS_LOGS', + value: '/var/log/grafana' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Grafana', + serviceTypeTags: ['aggregator', 'wui', 'graphs', 'dashboard'], + iconUri: 'https://grafana.com/static/img/logos/grafana_logo_swirl-events.svg' + }; + }; + + return retr; +}; + +module.exports = grafana; diff --git a/.internal/templates/services/grafana/template.yml b/.internal/templates/services/grafana/template.yml new file mode 100644 index 000000000..10b9de5cb --- /dev/null +++ b/.internal/templates/services/grafana/template.yml @@ -0,0 +1,28 @@ +grafana: + container_name: grafana + image: grafana/grafana + restart: unless-stopped + user: "0" + ports: + - "3000:3000" + environment: + - GF_PATHS_DATA=/var/lib/grafana + - GF_PATHS_LOGS=/var/log/grafana + # - TZ=Etc/UTC + ## [SERVER] + # - GF_SERVER_ROOT_URL=http://localhost:3000/grafana + # - GF_SERVER_SERVE_FROM_SUB_PATH=true + ## [SECURITY] + # - GF_SECURITY_ADMIN_USER=admin + # - GF_SECURITY_ADMIN_PASSWORD=admin + # - GF_SECURITY_ALLOW_EMBEDDING=true # Allows embedding externally + # - GF_AUTH_ANONYMOUS_ENABLED=true # Allows public read access to graphs + volumes: + - ./volumes/grafana/data:/var/lib/grafana + - ./volumes/grafana/log:/var/log/grafana + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/heimdall/build.js b/.internal/templates/services/heimdall/build.js new file mode 100644 index 000000000..2f2e4edea --- /dev/null +++ b/.internal/templates/services/heimdall/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'heimdall'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/heimdall/config.js b/.internal/templates/services/heimdall/config.js new file mode 100644 index 000000000..d0e7c36ae --- /dev/null +++ b/.internal/templates/services/heimdall/config.js @@ -0,0 +1,48 @@ +const heimdall = () => { + const retr = {}; + + const serviceName = 'heimdall'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + modifyableEnvironment: [ + { + key: 'INFLUXDB_UDP_BIND_ADDRESS', + value: '0.0.0.0:8086' + } + ], + volumes: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Heimdall', + serviceTypeTags: ['wui', 'database manager'] + }; + }; + + return retr; +}; + +module.exports = heimdall; diff --git a/.internal/templates/services/heimdall/template.yml b/.internal/templates/services/heimdall/template.yml new file mode 100644 index 000000000..b88e0e23b --- /dev/null +++ b/.internal/templates/services/heimdall/template.yml @@ -0,0 +1,13 @@ +heimdall: + image: ghcr.io/linuxserver/heimdall + container_name: heimdall + volumes: + - ./volumes/heimdall/config:/config + environment: + - PUID=1000 + - PGID=1000 + - TZ=Etc/UTC + ports: + - 8880:80 + - 8883:443 + restart: unless-stopped diff --git a/.internal/templates/services/home_assistant/build.js b/.internal/templates/services/home_assistant/build.js new file mode 100644 index 000000000..039338d02 --- /dev/null +++ b/.internal/templates/services/home_assistant/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'home_assistant'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/home_assistant +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/home_assistant ]]; then + echo "Home Assistant directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/home_assistant/config.js b/.internal/templates/services/home_assistant/config.js new file mode 100644 index 000000000..cf816d880 --- /dev/null +++ b/.internal/templates/services/home_assistant/config.js @@ -0,0 +1,45 @@ +const home_assistant = () => { + const retr = {}; + + const serviceName = 'home_assistant'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8123:8123": 'http' + }, + volumes: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Home Assistant', + serviceTypeTags: ['wui', 'dashboard', 'home automation', 'iot'] + }; + }; + + return retr; +}; + +module.exports = home_assistant; diff --git a/.internal/templates/services/home_assistant/template.yml b/.internal/templates/services/home_assistant/template.yml new file mode 100644 index 000000000..bfcd9c11e --- /dev/null +++ b/.internal/templates/services/home_assistant/template.yml @@ -0,0 +1,14 @@ +home_assistant: + container_name: home_assistant + image: homeassistant/home-assistant:stable + restart: unless-stopped + ports: + - "8123:8123" + volumes: + - /etc/localtime:/etc/localtime:ro + - ./volumes/home_assistant:/config + network_mode: host + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/homer/build.js b/.internal/templates/services/homer/build.js new file mode 100644 index 000000000..28050d425 --- /dev/null +++ b/.internal/templates/services/homer/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'homer'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/homer/assets +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/homer/assets ]]; then + echo "Homer assets directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/homer/config.js b/.internal/templates/services/homer/config.js new file mode 100644 index 000000000..d975ce488 --- /dev/null +++ b/.internal/templates/services/homer/config.js @@ -0,0 +1,45 @@ +const homer = () => { + const retr = {}; + + const serviceName = 'homer'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8881:8080": 'http' + }, + volumes: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Homer', + serviceTypeTags: ['wui', 'dashboard'] + }; + }; + + return retr; +}; + +module.exports = homer; diff --git a/.internal/templates/services/homer/template.yml b/.internal/templates/services/homer/template.yml new file mode 100644 index 000000000..20dad142f --- /dev/null +++ b/.internal/templates/services/homer/template.yml @@ -0,0 +1,11 @@ +homer: + image: b4bz/homer:latest + container_name: homer + environment: + - UID=1000 + - GID=1000 + volumes: + - ./volumes/homer/assets:/www/assets + ports: + - "8881:8080" + restart: unless-stopped diff --git a/.internal/templates/services/influxdb/build.js b/.internal/templates/services/influxdb/build.js new file mode 100644 index 000000000..0c42af767 --- /dev/null +++ b/.internal/templates/services/influxdb/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'influxdb'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/influxdb/config.js b/.internal/templates/services/influxdb/config.js new file mode 100644 index 000000000..3dda4e2d6 --- /dev/null +++ b/.internal/templates/services/influxdb/config.js @@ -0,0 +1,51 @@ +const influxDb = () => { + const retr = {}; + + const serviceName = 'influxdb'; + + retr.getConfigOptions = () => { + return { + serviceName: 'influxdb', // Required + labeledPorts: { + "8086:8086": 'http' + }, + modifyableEnvironment: [ + { + key: 'INFLUXDB_UDP_BIND_ADDRESS', + value: '0.0.0.0:8086' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'InfluxDB', + serviceTypeTags: ['database', 'timeseries', 'sql'] + }; + }; + + return retr; +}; + +module.exports = influxDb; diff --git a/.internal/templates/services/influxdb/template.yml b/.internal/templates/services/influxdb/template.yml new file mode 100644 index 000000000..1e148331d --- /dev/null +++ b/.internal/templates/services/influxdb/template.yml @@ -0,0 +1,26 @@ +influxdb: + container_name: influxdb + image: "influxdb:latest" + restart: unless-stopped + ports: + - "8086:8086" + - "8083:8083" + - "2003:2003" + environment: + - INFLUXDB_HTTP_FLUX_ENABLED=false + - INFLUXDB_REPORTING_DISABLED=false + - INFLUXDB_HTTP_AUTH_ENABLED=false + - INFLUX_USERNAME=dba + - INFLUX_PASSWORD=supremo + - INFLUXDB_UDP_ENABLED=false + - INFLUXDB_UDP_BIND_ADDRESS=0.0.0.0:8086 + - INFLUXDB_UDP_DATABASE=udp + volumes: + - ./volumes/influxdb/data:/var/lib/influxdb + - ./backups/influxdb/db:/var/lib/influxdb/backup + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/mariadb/build.js b/.internal/templates/services/mariadb/build.js new file mode 100644 index 000000000..81dff46a4 --- /dev/null +++ b/.internal/templates/services/mariadb/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'mariadb'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/mariadb/config +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/mariadb/config ]]; then + echo "MariaDB config directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/mariadb/config.js b/.internal/templates/services/mariadb/config.js new file mode 100644 index 000000000..98e4b1289 --- /dev/null +++ b/.internal/templates/services/mariadb/config.js @@ -0,0 +1,64 @@ +const mariadb = () => { + const retr = {}; + + const serviceName = 'mariadb'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + modifyableEnvironment: [ + { + key: 'TZ', + value: 'Etc/UTC' + }, + { + key: 'MYSQL_ROOT_PASSWORD', + value: 'PASSword' + }, + { + key: 'MYSQL_DATABASE', + value: 'default' + }, + { + key: 'MYSQL_USER', + value: 'mariadbuser' + }, + { + key: 'MYSQL_PASSWORD', + value: 'PASSword' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'MariaDB', + serviceTypeTags: ['database', 'sql'] + }; + }; + + return retr; +}; + +module.exports = mariadb; diff --git a/.internal/templates/services/mariadb/template.yml b/.internal/templates/services/mariadb/template.yml new file mode 100644 index 000000000..ac0f163a0 --- /dev/null +++ b/.internal/templates/services/mariadb/template.yml @@ -0,0 +1,23 @@ +mariadb: + image: linuxserver/mariadb + container_name: mariadb + environment: + - TZ=Etc/UTC + - PUID=1000 + - PGID=1000 + - MYSQL_ROOT_PASSWORD=%randomAdminPassword% + - MYSQL_DATABASE=default + - MYSQL_USER=mariadbuser + - MYSQL_PASSWORD=%randomPassword% + volumes: + - ./volumes/mariadb/config:/config + ports: + - "3306:3306" + restart: unless-stopped + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" + diff --git a/.internal/templates/services/mosquitto/build.js b/.internal/templates/services/mosquitto/build.js new file mode 100644 index 000000000..5c88c5c01 --- /dev/null +++ b/.internal/templates/services/mosquitto/build.js @@ -0,0 +1,95 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const path = require('path'); + const retr = {}; + const serviceName = 'mosquitto'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const checkServiceFilesCopied = () => { + return ` +if [[ ! -f ./services/mosquitto/mosquitto.conf ]]; then + echo "Mosquitto config file is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + const mosquittoConfFilePath = path.join(__dirname, settings.paths.serviceFiles, 'mosquitto.conf'); + zipList.push({ + fullPath: mosquittoConfFilePath, + zipName: '/services/mosquitto/mosquitto.conf' + }); + console.debug(`ServiceBuilder:build() - '${serviceName}' Added '${mosquittoConfFilePath}' to zip`); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service files exist for launch', + multilineComment: null, + code: checkServiceFilesCopied() + }); + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/mosquitto/config.js b/.internal/templates/services/mosquitto/config.js new file mode 100644 index 000000000..c5c52e48e --- /dev/null +++ b/.internal/templates/services/mosquitto/config.js @@ -0,0 +1,43 @@ +const mosquitto = () => { + const retr = {}; + + const serviceName = 'mosquitto'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: {}, + volumes: true, + networks: true, + logging: true + }; + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Mosquitto', + serviceTypeTags: ['mqtt', 'server'] + }; + }; + + return retr; +}; + +module.exports = mosquitto; diff --git a/.internal/templates/services/mosquitto/serviceFiles/mosquitto.conf b/.internal/templates/services/mosquitto/serviceFiles/mosquitto.conf new file mode 100644 index 000000000..c6a41d973 --- /dev/null +++ b/.internal/templates/services/mosquitto/serviceFiles/mosquitto.conf @@ -0,0 +1,14 @@ +persistence true +persistence_location /mosquitto/data/ +#log_dest file /mosquitto/log/mosquitto.log +# To avoid flash wearing +log_dest stdout + +#Uncomment to enable passwords +#password_file /mosquitto/pwfile/pwfile +#allow_anonymous false + +#Uncomment to enable filters +#acl_file /mosquitto/config/filter.acl + +log_timestamp_format %Y-%m-%dT%H:%M:%S diff --git a/.internal/templates/services/mosquitto/template.yml b/.internal/templates/services/mosquitto/template.yml new file mode 100644 index 000000000..c7d6e12fb --- /dev/null +++ b/.internal/templates/services/mosquitto/template.yml @@ -0,0 +1,19 @@ +mosquitto: + container_name: mosquitto + image: eclipse-mosquitto + restart: unless-stopped + user: "1883" + ports: + - "1883:1883" + volumes: + - ./volumes/mosquitto/data:/mosquitto/data + - ./volumes/mosquitto/log:/mosquitto/log + - ./volumes/mosquitto/pwfile:/mosquitto/pwfile + - ./services/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf + - ./services/mosquitto/filter.acl:/mosquitto/config/filter.acl + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/motioneye/build.js b/.internal/templates/services/motioneye/build.js new file mode 100644 index 000000000..30b108610 --- /dev/null +++ b/.internal/templates/services/motioneye/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'motioneye'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/motioneye/config.js b/.internal/templates/services/motioneye/config.js new file mode 100644 index 000000000..3c9f4ab8f --- /dev/null +++ b/.internal/templates/services/motioneye/config.js @@ -0,0 +1,46 @@ +const motioneye = () => { + const retr = {}; + + const serviceName = 'motioneye'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8765:8765": 'http', + "8081:8081": 'streaming' + }, + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Motion Eye', + serviceTypeTags: ['wui', 'physical security', 'video'] + }; + }; + + return retr; +}; + +module.exports = motioneye; diff --git a/.internal/templates/services/motioneye/template.yml b/.internal/templates/services/motioneye/template.yml new file mode 100644 index 000000000..5d0f80637 --- /dev/null +++ b/.internal/templates/services/motioneye/template.yml @@ -0,0 +1,19 @@ +motioneye: + image: "ccrisan/motioneye:master-armhf" + container_name: "motioneye" + restart: unless-stopped + ports: + - "8765:8765" + - "8081:8081" + volumes: + - /etc/localtime:/etc/localtime:ro + - ./volumes/motioneye/etc_motioneye:/etc/motioneye + - ./volumes/motioneye/var_lib_motioneye:/var/lib/motioneye + #devices: + # - "/dev/video0:/dev/video0" + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/nodered/build.js b/.internal/templates/services/nodered/build.js new file mode 100644 index 000000000..cefcd2618 --- /dev/null +++ b/.internal/templates/services/nodered/build.js @@ -0,0 +1,118 @@ +const fs = require('fs'); +const path = require('path'); +const { byName } = require('../../../src/utils/interpolate'); + +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'nodered'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + fileTimePrefix, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + const addonsList = buildOptions?.services?.nodered?.addons ?? []; + const noderedDockerfileTemplate = path.join(__dirname, settings.paths.buildFiles, 'Dockerfile.template'); + const noderedDockerfileCommandTemplate = require(path.join(__dirname, settings.paths.buildFiles, 'addons.json')); + const tempDockerfileName = `${fileTimePrefix}_Dockerfile.template`; + + const templateData = fs.readFileSync(noderedDockerfileTemplate, { encoding: 'utf8', flag: 'r' }); + let addonDockerCommandOutput = noderedDockerfileCommandTemplate.data.dockerFileInstallCommand; + + if (addonsList.length > 0) { + addonsList.forEach((addon) => { + addonDockerCommandOutput += `${addon} ` + }); + } else { + addonDockerCommandOutput = ''; + } + + const outputDockerFile = byName(templateData, { + 'npmInstallModulesList': addonDockerCommandOutput + }); + + const tempBuildFile = path.join(tmpPath, tempDockerfileName); + + fs.writeFileSync(tempBuildFile, outputDockerFile); + + zipList.push({ + fullPath: tempBuildFile, + zipName: '/services/nodered/Dockerfile' + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + let addonsSelected = false; + const addonsList = buildOptions?.services?.nodered?.addons ?? []; + if (addonsList.length > 0) { + addonsSelected = true; + } + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + if (!addonsSelected) { + return resolve([{ + type: 'service', + name: serviceName, + issueType: 'no addons', + message: 'No pallette addons selected for NodeRed. Select addons in options to remove this warning. This is optional.' + }]); + } + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/nodered/buildFiles/Dockerfile.template b/.internal/templates/services/nodered/buildFiles/Dockerfile.template new file mode 100644 index 000000000..56fe0dbc7 --- /dev/null +++ b/.internal/templates/services/nodered/buildFiles/Dockerfile.template @@ -0,0 +1,7 @@ +FROM nodered/node-red:latest +USER root +RUN apk update +RUN apk upgrade +RUN apk add --no-cache eudev-dev + +{$npmInstallModulesList} diff --git a/.internal/templates/services/nodered/buildFiles/addons.json b/.internal/templates/services/nodered/buildFiles/addons.json new file mode 100644 index 000000000..e95c5ceef --- /dev/null +++ b/.internal/templates/services/nodered/buildFiles/addons.json @@ -0,0 +1,62 @@ +{ + "version": "1.0.0", + "application": "IOTstack", + "service": "nodered", + "comment": "Addons available for NodeRed", + "data": { + "dockerFileInstallCommand": "RUN cd /usr/src/node-red && npm install --save ", + "addons": { + "defaultOn": [ + "node-red-node-pi-gpiod", + "node-red-contrib-influxdb", + "node-red-contrib-boolean-logic", + "node-red-node-rbe", + "node-red-configurable-ping", + "node-red-dashboard" + ], + "defaultOff": [ + "node-red-node-openweathermap", + "node-red-contrib-discord", + "node-red-node-email", + "node-red-node-google", + "node-red-node-emoncms", + "node-red-node-geofence", + "node-red-node-ping", + "node-red-node-random", + "node-red-node-smooth", + "node-red-node-darksky", + "node-red-node-sqlite", + "node-red-node-serialport", + "node-red-contrib-config", + "node-red-contrib-grove", + "node-red-contrib-diode", + "node-red-contrib-sunevents", + "node-red-contrib-bigtimer", + "node-red-contrib-esplogin", + "node-red-contrib-timeout", + "node-red-contrib-moment", + "node-red-contrib-telegrambot", + "node-red-contrib-particle", + "node-red-contrib-web-worldmap", + "node-red-contrib-ramp-thermostat", + "node-red-contrib-isonline", + "node-red-contrib-npm", + "node-red-contrib-file-function", + "node-red-contrib-home-assistant-websocket", + "node-red-contrib-blynk-ws", + "node-red-contrib-owntracks", + "node-red-contrib-alexa-local", + "node-red-contrib-heater-controller", + "node-red-contrib-deconz", + "node-red-contrib-generic-ble", + "node-red-contrib-zigbee2mqtt", + "node-red-contrib-vcgencmd", + "node-red-contrib-themes/midnight-red", + "node-red-contrib-tf-function", + "node-red-contrib-tf-model", + "node-red-contrib-post-object-detection", + "node-red-contrib-bert-tokenizer" + ] + } + } +} diff --git a/.internal/templates/services/nodered/config.js b/.internal/templates/services/nodered/config.js new file mode 100644 index 000000000..982072153 --- /dev/null +++ b/.internal/templates/services/nodered/config.js @@ -0,0 +1,45 @@ +const nodered = () => { + const retr = {}; + + const serviceName = 'nodered'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "1880:1880": 'http' + }, + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'NodeRed', + serviceTypeTags: ['wui', 'dashboard', 'low code', 'graphs', 'aggregator', 'iot', 'server'] + }; + }; + + return retr; +}; + +module.exports = nodered; diff --git a/.internal/templates/services/nodered/template.yml b/.internal/templates/services/nodered/template.yml new file mode 100644 index 000000000..93f2a155b --- /dev/null +++ b/.internal/templates/services/nodered/template.yml @@ -0,0 +1,24 @@ +nodered: + container_name: nodered + build: ./services/nodered/. + restart: unless-stopped + user: "0" + privileged: true + environment: + - TZ=Etc/UTC + ports: + - "1880:1880" + volumes: + - ./volumes/nodered/data:/data + - /var/run/docker.sock:/var/run/docker.sock + - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket + devices: + - "/dev/ttyAMA0:/dev/ttyAMA0" + - "/dev/vcio:/dev/vcio" + - "/dev/gpiomem:/dev/gpiomem" + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/openhab/build.js b/.internal/templates/services/openhab/build.js new file mode 100644 index 000000000..0f67b61da --- /dev/null +++ b/.internal/templates/services/openhab/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'adminer'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/openhab/config.js b/.internal/templates/services/openhab/config.js new file mode 100644 index 000000000..6b56fe605 --- /dev/null +++ b/.internal/templates/services/openhab/config.js @@ -0,0 +1,59 @@ +const adminer = () => { + const retr = {}; + + const serviceName = 'adminer'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "4050:4050": 'http' + }, + modifyableEnvironment: [ + { + key: 'OPENHAB_HTTP_PORT', + value: '4050' + }, + { + key: 'OPENHAB_HTTPS_PORT', + value: '4051' + }, + { + key: 'EXTRA_JAVA_OPTS', + value: '-Duser.timezone=Etc/UTC' + } + ], + volumes: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Adminer', + serviceTypeTags: ['wui', 'dashboard', 'home automation'] + }; + }; + + return retr; +}; + +module.exports = adminer; diff --git a/.internal/templates/services/openhab/template.yml b/.internal/templates/services/openhab/template.yml new file mode 100644 index 000000000..31052bf26 --- /dev/null +++ b/.internal/templates/services/openhab/template.yml @@ -0,0 +1,30 @@ +openhab: + image: "openhab/openhab:latest" + container_name: openhab + restart: unless-stopped + network_mode: host + # networks: + # - hosts_nw +# cap_add: +# - NET_ADMIN +# - NET_RAW + ports: # Changing this won't do anything. Change the port below under environment. Ensure values are synced + - "4050:4050" + - "4051:4051" + volumes: + - "/etc/localtime:/etc/localtime:ro" + - "/etc/timezone:/etc/timezone:ro" + - "./volumes/openhab/addons:/openhab/addons" + - "./volumes/openhab/conf:/openhab/conf" + - "./volumes/openhab/userdata:/openhab/userdata" + environment: + - OPENHAB_HTTP_PORT=4050 + - OPENHAB_HTTPS_PORT=4051 + - EXTRA_JAVA_OPTS=-Duser.timezone=Etc/UTC" +# # The command node is very important. It overrides +# # the "gosu openhab tini -s ./start.sh" command from Dockerfile and runs as root! +# command: "tini -s ./start.sh server" + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/pihole/build.js b/.internal/templates/services/pihole/build.js new file mode 100644 index 000000000..75eebb93c --- /dev/null +++ b/.internal/templates/services/pihole/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'pihole'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/pihole/etc-pihole +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/pihole/etc-pihole ]]; then + echo "PiHole config directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/pihole/config.js b/.internal/templates/services/pihole/config.js new file mode 100644 index 000000000..4fbaaf89c --- /dev/null +++ b/.internal/templates/services/pihole/config.js @@ -0,0 +1,67 @@ +const pihole = () => { + const retr = {}; + + const serviceName = 'pihole'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8089:80": 'http' + }, + modifyableEnvironment: [ + { + key: 'TZ', + value: 'Etc/UTC' + }, + { + key: 'WEBPASSWORD', + value: 'password' + }, + { + key: 'DNS1', + value: '8.8.8.8' + }, + { + key: 'DNS2', + value: '8.8.4.4' + }, + { + key: 'INTERFACE', + value: 'eth0' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'PiHole', + serviceTypeTags: ['wui', 'dns', 'dashboard'] + }; + }; + + return retr; +}; + +module.exports = pihole; diff --git a/.internal/templates/services/pihole/template.yml b/.internal/templates/services/pihole/template.yml new file mode 100644 index 000000000..e8082f9d5 --- /dev/null +++ b/.internal/templates/services/pihole/template.yml @@ -0,0 +1,44 @@ +pihole: + container_name: pihole + image: pihole/pihole:latest + ports: + - "8089:80/tcp" + - "53:53/tcp" + - "53:53/udp" + - "67:67/udp" + # - "443:443/tcp" + environment: + - TZ=Etc/UTC + - WEBPASSWORD=%randomAdminPassword% + - DNS1=8.8.8.8 + - DNS2=8.8.4.4 + # - DNSSEC=false + # - DNS_BOGUS_PRIV=True + # - CONDITIONAL_FORWARDING=False + # - CONDITIONAL_FORWARDING_IP=your_router_ip_here (only if CONDITIONAL_FORWARDING=true) + # - CONDITIONAL_FORWARDING_DOMAIN=optional + # - CONDITIONAL_FORWARDING_REVERSE=optional + # - ServerIP=your_Pi's_IP_here << recommended + # - ServerIPv6= your_Pi's_ipv6_here << Required if using ipv6 + # - VIRTUAL_HOST=$ServerIP + # - IPv6=True + - INTERFACE=eth0 + # - DNSMASQ_LISTENING=local + volumes: + - ./volumes/pihole/etc-pihole/:/etc/pihole/ + - ./volumes/pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/ + dns: + - 127.0.0.1 + - 1.1.1.1 + # Recommended but not required (DHCP needs NET_ADMIN) + # https://github.com/pi-hole/docker-pi-hole#note-on-capabilities + cap_add: + - NET_ADMIN + restart: unless-stopped + networks: + - iotstack_nw + - vpn_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/plex/build.js b/.internal/templates/services/plex/build.js new file mode 100644 index 000000000..5a74cea9d --- /dev/null +++ b/.internal/templates/services/plex/build.js @@ -0,0 +1,107 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'plex'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/plex/config +mkdir -p ./volumes/plex/transcode +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/plex/config ]]; then + echo "Plex config directory is missing!" + sleep 2 +fi +if [[ ! -d ./volumes/plex/transcode ]]; then + echo "Plex transcode directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/plex/config.js b/.internal/templates/services/plex/config.js new file mode 100644 index 000000000..75f037929 --- /dev/null +++ b/.internal/templates/services/plex/config.js @@ -0,0 +1,51 @@ +const plex = () => { + const retr = {}; + + const serviceName = 'plex'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9080:8080": 'http' + }, + modifyableEnvironment: [ + { + key: 'VERSION', + value: 'docker' + } + ], + volumes: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Plex', + serviceTypeTags: ['wui', 'database manager'] + }; + }; + + return retr; +}; + +module.exports = plex; diff --git a/.internal/templates/services/plex/template.yml b/.internal/templates/services/plex/template.yml new file mode 100644 index 000000000..ef3264e23 --- /dev/null +++ b/.internal/templates/services/plex/template.yml @@ -0,0 +1,21 @@ +plex: + image: linuxserver/plex + container_name: plex + network_mode: host + # networks: + # - hosts_nw + environment: + - PUID=1000 + - PGID=1000 + - VERSION=docker + #- UMASK_SET=022 #optional + volumes: + - ./volumes/plex/config:/config + #- ~/mnt/HDD/tvseries:/tv + #- ~/mnt/HDD/movies:/movies + - ./volumes/plex/transcode:/transcode + restart: unless-stopped + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/portainer/build.js b/.internal/templates/services/portainer/build.js new file mode 100644 index 000000000..dee901df6 --- /dev/null +++ b/.internal/templates/services/portainer/build.js @@ -0,0 +1,78 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'portainer'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([{ + type: 'service', + name: serviceName, + issueType: 'deprecation', + message: 'Portainer is deprecated and may be removed from IOTstack at any time. Use Portainer-CE instead.' + }]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/portainer/config.js b/.internal/templates/services/portainer/config.js new file mode 100644 index 000000000..ee1d48cc5 --- /dev/null +++ b/.internal/templates/services/portainer/config.js @@ -0,0 +1,45 @@ +const portainer = () => { + const retr = {}; + + const serviceName = 'portainer'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9002:9000": 'http' + }, + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Portainer', + serviceTypeTags: ['container manager', 'wui', 'deprecated', 'dashboard'] + }; + }; + + return retr; +}; + +module.exports = portainer; diff --git a/.internal/templates/services/portainer/template.yml b/.internal/templates/services/portainer/template.yml new file mode 100644 index 000000000..fb1fd5c43 --- /dev/null +++ b/.internal/templates/services/portainer/template.yml @@ -0,0 +1,15 @@ +portainer: + container_name: portainer + image: portainer/portainer + restart: unless-stopped + ports: + - "9002:9000" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./volumes/portainer/data:/data + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/portainer_agent/build.js b/.internal/templates/services/portainer_agent/build.js new file mode 100644 index 000000000..2faf2b6f0 --- /dev/null +++ b/.internal/templates/services/portainer_agent/build.js @@ -0,0 +1,73 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'portainer_agent'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/portainer_agent/config.js b/.internal/templates/services/portainer_agent/config.js new file mode 100644 index 000000000..2b1b33354 --- /dev/null +++ b/.internal/templates/services/portainer_agent/config.js @@ -0,0 +1,43 @@ +const portainer_agent = () => { + const retr = {}; + + const serviceName = 'portainer_agent'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: {}, + volumes: false, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Portainer Agent', + serviceTypeTags: ['container manager', 'docker'] + }; + }; + + return retr; +}; + +module.exports = portainer_agent; diff --git a/.internal/templates/services/portainer_agent/template.yml b/.internal/templates/services/portainer_agent/template.yml new file mode 100644 index 000000000..baaccc55a --- /dev/null +++ b/.internal/templates/services/portainer_agent/template.yml @@ -0,0 +1,9 @@ +portainer_agent: + image: portainer/agent + container_name: portainer-agent + ports: + - 9001:9001 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /var/lib/docker/volumes:/var/lib/docker/volumes + restart: unless-stopped diff --git a/.internal/templates/services/portainer_ce/build.js b/.internal/templates/services/portainer_ce/build.js new file mode 100644 index 000000000..ad71c817c --- /dev/null +++ b/.internal/templates/services/portainer_ce/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'portainer_ce'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/portainer-ce/data +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/portainer-ce/data ]]; then + echo "Portainer-CE data directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/portainer_ce/config.js b/.internal/templates/services/portainer_ce/config.js new file mode 100644 index 000000000..063d1e182 --- /dev/null +++ b/.internal/templates/services/portainer_ce/config.js @@ -0,0 +1,45 @@ +const portainer_ce = () => { + const retr = {}; + + const serviceName = 'portainer_ce'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8000:8000": 'http' + }, + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Portainer-CE', + serviceTypeTags: ['wui', 'container manager', 'docker'] + }; + }; + + return retr; +}; + +module.exports = portainer_ce; diff --git a/.internal/templates/services/portainer_ce/template.yml b/.internal/templates/services/portainer_ce/template.yml new file mode 100644 index 000000000..f680bacbf --- /dev/null +++ b/.internal/templates/services/portainer_ce/template.yml @@ -0,0 +1,10 @@ +portainer-ce: + container_name: portainer-ce + image: portainer/portainer-ce + restart: unless-stopped + ports: + - "8000:8000" + - "9000:9000" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./volumes/portainer-ce/data:/data diff --git a/.internal/templates/services/postgres/build.js b/.internal/templates/services/postgres/build.js new file mode 100644 index 000000000..005744634 --- /dev/null +++ b/.internal/templates/services/postgres/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'postgres'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/postgres/data +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/postgres/data ]]; then + echo "Postgres data directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/postgres/config.js b/.internal/templates/services/postgres/config.js new file mode 100644 index 000000000..098a86289 --- /dev/null +++ b/.internal/templates/services/postgres/config.js @@ -0,0 +1,56 @@ +const postgres = () => { + const retr = {}; + + const serviceName = 'postgres'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + modifyableEnvironment: [ + { + key: 'POSTGRES_USER', + value: 'postuser' + }, + { + key: 'POSTGRES_PASSWORD', + value: 'PAsssword' + }, + { + key: 'POSTGRES_DB', + value: 'postdb' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Postgres', + serviceTypeTags: ['database'] + }; + }; + + return retr; +}; + +module.exports = postgres; diff --git a/.internal/templates/services/postgres/template.yml b/.internal/templates/services/postgres/template.yml new file mode 100644 index 000000000..ba78bca0b --- /dev/null +++ b/.internal/templates/services/postgres/template.yml @@ -0,0 +1,18 @@ +postgres: + container_name: postgres + image: postgres + restart: unless-stopped + environment: + - POSTGRES_USER=postuser + - POSTGRES_PASSWORD=%randomPassword% + - POSTGRES_DB=postdb + ports: + - "5432:5432" + volumes: + - ./volumes/postgres/data:/var/lib/postgresql/data + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/qbittorrent/build.js b/.internal/templates/services/qbittorrent/build.js new file mode 100644 index 000000000..0030cecd5 --- /dev/null +++ b/.internal/templates/services/qbittorrent/build.js @@ -0,0 +1,107 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'qbittorrent'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/qbittorrent/config +mkdir -p ./volumes/qbittorrent/downloads +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/qbittorrent/config ]]; then + echo "qBittorrent config directory is missing!" + sleep 2 +fi +if [[ ! -d ./volumes/qbittorrent/downloads ]]; then + echo "qBittorrent downloads directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/qbittorrent/config.js b/.internal/templates/services/qbittorrent/config.js new file mode 100644 index 000000000..27f811dee --- /dev/null +++ b/.internal/templates/services/qbittorrent/config.js @@ -0,0 +1,51 @@ +const qbittorrent = () => { + const retr = {}; + + const serviceName = 'qbittorrent'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "15080:15080": 'http' + }, + modifyableEnvironment: [ + { + key: 'WEBUI_PORT', + value: '15080' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Q Bittorrent', + serviceTypeTags: ['bittorrent'] + }; + }; + + return retr; +}; + +module.exports = qbittorrent; diff --git a/.internal/templates/services/qbittorrent/template.yml b/.internal/templates/services/qbittorrent/template.yml new file mode 100644 index 000000000..c04a0bb05 --- /dev/null +++ b/.internal/templates/services/qbittorrent/template.yml @@ -0,0 +1,16 @@ +qbittorrent: + image: linuxserver/qbittorrent + container_name: qbittorrent + environment: + - PUID=1000 + - PGID=1000 + - UMASK_SET=022 + - WEBUI_PORT=15080 + volumes: + - ./volumes/qbittorrent/config:/config + - ./volumes/qbittorrent/downloads:/downloads + ports: + - "15080:15080" + - "6881:6881" + - "6881:6881/udp" + - "1080:1080" diff --git a/.internal/templates/services/tasmoadmin/build.js b/.internal/templates/services/tasmoadmin/build.js new file mode 100644 index 000000000..4653bf72f --- /dev/null +++ b/.internal/templates/services/tasmoadmin/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'tasmoadmin'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/tasmoadmin/data +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/tasmoadmin/data ]]; then + echo "TasmoAdmin data directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/tasmoadmin/config.js b/.internal/templates/services/tasmoadmin/config.js new file mode 100644 index 000000000..00fcc219e --- /dev/null +++ b/.internal/templates/services/tasmoadmin/config.js @@ -0,0 +1,45 @@ +const tasmoadmin = () => { + const retr = {}; + + const serviceName = 'tasmoadmin'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8088:80": 'http' + }, + volumes: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'TasmoAdmin', + serviceTypeTags: ['wui', 'iot'] + }; + }; + + return retr; +}; + +module.exports = tasmoadmin; diff --git a/.internal/templates/services/tasmoadmin/template.yml b/.internal/templates/services/tasmoadmin/template.yml new file mode 100644 index 000000000..323f1f3d4 --- /dev/null +++ b/.internal/templates/services/tasmoadmin/template.yml @@ -0,0 +1,14 @@ +tasmoadmin: + container_name: tasmoadmin + image: raymondmm/tasmoadmin + restart: unless-stopped + ports: + - "8088:80" + volumes: + - ./volumes/tasmoadmin/data:/data + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/timescaledb/build.js b/.internal/templates/services/timescaledb/build.js new file mode 100644 index 000000000..7d39824a8 --- /dev/null +++ b/.internal/templates/services/timescaledb/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'timescaledb'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/timescaledb/data +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/timescaledb/data ]]; then + echo "TimescaleDB data directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/timescaledb/config.js b/.internal/templates/services/timescaledb/config.js new file mode 100644 index 000000000..d195cc8ed --- /dev/null +++ b/.internal/templates/services/timescaledb/config.js @@ -0,0 +1,56 @@ +const timescaledb = () => { + const retr = {}; + + const serviceName = 'timescaledb'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + modifyableEnvironment: [ + { + key: 'POSTGRES_USER', + value: 'timescaleuser' + }, + { + key: 'POSTGRES_PASSWORD', + value: 'PASSword' + }, + { + key: 'POSTGRES_DB', + value: 'postdb' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Timescale DB', + serviceTypeTags: ['timeseries', 'database'] + }; + }; + + return retr; +}; + +module.exports = timescaledb; diff --git a/.internal/templates/services/timescaledb/template.yml b/.internal/templates/services/timescaledb/template.yml new file mode 100644 index 000000000..e0c1fd3b1 --- /dev/null +++ b/.internal/templates/services/timescaledb/template.yml @@ -0,0 +1,18 @@ +timescaledb: + container_name: timescaledb + image: timescale/timescaledb:latest-pg12 + restart: unless-stopped + environment: + POSTGRES_USER=timescaleuser + POSTGRES_PASSWORD=%randomPassword% + POSTGRES_DB=postdb + ports: + - "5432:5432" + volumes: + - ./volumes/timescaledb/data:/var/lib/postgresql/data + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" \ No newline at end of file diff --git a/.internal/templates/services/transmission/build.js b/.internal/templates/services/transmission/build.js new file mode 100644 index 000000000..09504313f --- /dev/null +++ b/.internal/templates/services/transmission/build.js @@ -0,0 +1,112 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'transmission'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/transmission/config +mkdir -p ./volumes/transmission/downloads +mkdir -p ./volumes/transmission/watch +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/transmission/config ]]; then + echo "Transmission config directory is missing!" + sleep 2 +fi +if [[ ! -d ./volumes/transmission/downloads ]]; then + echo "Transmission downloads directory is missing!" + sleep 2 +fi +if [[ ! -d ./volumes/transmission/watch ]]; then + echo "Transmission watch directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/transmission/config.js b/.internal/templates/services/transmission/config.js new file mode 100644 index 000000000..699551166 --- /dev/null +++ b/.internal/templates/services/transmission/config.js @@ -0,0 +1,51 @@ +const transmission = () => { + const retr = {}; + + const serviceName = 'transmission'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9091:9091": 'http' + }, + modifyableEnvironment: [ + { + key: 'TZ', + value: 'Etc/UTC' + } + ], + volumes: true, + networks: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Transmission', + serviceTypeTags: ['bittorrent'] + }; + }; + + return retr; +}; + +module.exports = transmission; diff --git a/.internal/templates/services/transmission/template.yml b/.internal/templates/services/transmission/template.yml new file mode 100644 index 000000000..7d03e9159 --- /dev/null +++ b/.internal/templates/services/transmission/template.yml @@ -0,0 +1,22 @@ +transmission: + image: linuxserver/transmission + container_name: transmission + environment: + - PUID=1000 + - PGID=1000 + - TZ=Etc/UTC + volumes: + - ./volumes/transmission/config:/config + - ./volumes/transmission/downloads:/downloads + - ./volumes/transmission/watch:/watch + ports: + - "9091:9091" + - "51413:51413" + - "51413:51413/udp" + restart: unless-stopped + networks: + - iotstack_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/templates/services/zigbee2mqtt/build.js b/.internal/templates/services/zigbee2mqtt/build.js new file mode 100644 index 000000000..754a570aa --- /dev/null +++ b/.internal/templates/services/zigbee2mqtt/build.js @@ -0,0 +1,102 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'zigbee2mqtt'; + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const createVolumesDirectory = () => { + return ` +mkdir -p ./volumes/zigbee2mqtt/data +`; + }; + + const checkVolumesDirectory = () => { + return ` +if [[ ! -d ./volumes/zigbee2mqtt/data ]]; then + echo "zigbee2mqtt data directory is missing!" + sleep 2 +fi +`; + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve(); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/zigbee2mqtt/config.js b/.internal/templates/services/zigbee2mqtt/config.js new file mode 100644 index 000000000..6fdc1a536 --- /dev/null +++ b/.internal/templates/services/zigbee2mqtt/config.js @@ -0,0 +1,46 @@ +const zigbee2mqtt = () => { + const retr = {}; + + const serviceName = 'zigbee2mqtt'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9080:8080": 'http' + }, + volumes: true, + devices: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'zigbee2mqtt', + serviceTypeTags: ['zigbee', 'mqtt'] + }; + }; + + return retr; +}; + +module.exports = zigbee2mqtt; diff --git a/.internal/templates/services/zigbee2mqtt/template.yml b/.internal/templates/services/zigbee2mqtt/template.yml new file mode 100644 index 000000000..8fe633e00 --- /dev/null +++ b/.internal/templates/services/zigbee2mqtt/template.yml @@ -0,0 +1,16 @@ +zigbee2mqtt: + container_name: zigbee2mqtt + image: koenkk/zigbee2mqtt + volumes: + - ./volumes/zigbee2mqtt/data:/app/data + devices: + - /dev/ttyAMA0:/dev/ttyACM0 + #- /dev/ttyACM0:/dev/ttyACM0 + restart: unless-stopped + network_mode: host + # networks: + # - hosts_nw + logging: + options: + max-size: "5m" + max-file: "3" diff --git a/.internal/wui.Dockerfile b/.internal/wui.Dockerfile new file mode 100644 index 000000000..b8f744005 --- /dev/null +++ b/.internal/wui.Dockerfile @@ -0,0 +1,10 @@ +FROM node:alpine + +WORKDIR /usr/iotstack_wui + +# node_modules is ignored with this copy, as specified in .dockerignore +COPY wui ./ +RUN npm install + +EXPOSE 32777 +CMD [ "npm", "start" ] diff --git a/.internal/wui/.eslintcache b/.internal/wui/.eslintcache new file mode 100644 index 000000000..8ee4bccb1 --- /dev/null +++ b/.internal/wui/.eslintcache @@ -0,0 +1 @@ +[{"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/index.js":"1","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/App.js":"2","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/counter/Counter.js":"3","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/index.js":"4","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/counter.js":"5","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/router.jsx":"6","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/asyncDispatchMiddleware.js":"7","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/promiseMiddleware.js":"8","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/constants.js":"9","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/templates.js":"10","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/config.js":"11","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/servicesGridItem/index.jsx":"12","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceMetadataReducer.js":"13","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceMetadata.action.js":"14","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/configs.js":"15","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedServicesReducer.js":"16","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateSelectedServices.action.js":"17","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/Sidebar/index.js":"18","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/notFound/index.js":"19","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/buildHistory/index.jsx":"20","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/help/index.jsx":"21","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/scripts/index.jsx":"22","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildHistoryListReducer.js":"23","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getBuildHistoryList.action.js":"24","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/builds.js":"25","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildHistoryGridItem/index.jsx":"26","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/BuildSidebar/index.jsx":"27","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateFilterTags.action.js":"28","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedFilterTagsReducer.js":"29","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildIssuesReducer.js":"30","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/checkBuildIssues.action.js":"31","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/buildStackReducer.js":"32","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/buildStack.action.js":"33","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildCompletedModal/index.jsx":"34","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getScript.action.js":"35","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getScriptTemplatesReducer.js":"36","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/downloadBuild.action.js":"37","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceConfigModal/index.jsx":"38","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/index.js":"39","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/portConfig.jsx":"40","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/buildOptionSync.js":"41","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceConfigOptionsReducer.js":"42","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceConfigOptions.action.js":"43","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/configOptionLoader.jsx":"44","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/parsers.js":"45","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/mainBuild/index.jsx":"46","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplateList.action.js":"47","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplateListReducer.js":"48","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getNetworkTemplateListReducer.js":"49","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getNetworkTemplateList.action.js":"50","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplatesReducer.js":"51","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplates.action.js":"52","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/networkConfig.jsx":"53","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/logging.jsx":"54"},{"size":353,"mtime":1606908594887,"results":"55","hashOfConfig":"56"},{"size":789,"mtime":1607430281547,"results":"57","hashOfConfig":"56"},{"size":1634,"mtime":1607288886088,"results":"58","hashOfConfig":"59"},{"size":1612,"mtime":1610356071552,"results":"60","hashOfConfig":"56"},{"size":1551,"mtime":1606908622214,"results":"61","hashOfConfig":"56"},{"size":1231,"mtime":1610350276543,"results":"62","hashOfConfig":"56"},{"size":607,"mtime":1607109560543,"results":"63","hashOfConfig":"56"},{"size":711,"mtime":1607260096944,"results":"64","hashOfConfig":"56"},{"size":160,"mtime":1607109631094,"results":"65","hashOfConfig":"56"},{"size":5035,"mtime":1610354111429,"results":"66","hashOfConfig":"56"},{"size":98,"mtime":1607121110848,"results":"67","hashOfConfig":"56"},{"size":11600,"mtime":1610356264839,"results":"68","hashOfConfig":"56"},{"size":1878,"mtime":1607294201436,"results":"69","hashOfConfig":"56"},{"size":375,"mtime":1607260125923,"results":"70","hashOfConfig":"56"},{"size":2528,"mtime":1609913218191,"results":"71","hashOfConfig":"56"},{"size":1105,"mtime":1607294167538,"results":"72","hashOfConfig":"56"},{"size":534,"mtime":1607292532075,"results":"73","hashOfConfig":"56"},{"size":4770,"mtime":1607430353516,"results":"74","hashOfConfig":"56"},{"size":206,"mtime":1607342162060,"results":"75","hashOfConfig":"56"},{"size":1626,"mtime":1610349813009,"results":"76","hashOfConfig":"56"},{"size":204,"mtime":1607342542038,"results":"77","hashOfConfig":"56"},{"size":213,"mtime":1607342531957,"results":"78","hashOfConfig":"56"},{"size":947,"mtime":1607430599186,"results":"79","hashOfConfig":"56"},{"size":340,"mtime":1607430711272,"results":"80","hashOfConfig":"56"},{"size":5471,"mtime":1608852677675,"results":"81","hashOfConfig":"56"},{"size":3558,"mtime":1610347837498,"results":"82","hashOfConfig":"56"},{"size":10365,"mtime":1610350599948,"results":"83","hashOfConfig":"56"},{"size":540,"mtime":1607529608604,"results":"84","hashOfConfig":"56"},{"size":1079,"mtime":1607529487594,"results":"85","hashOfConfig":"56"},{"size":894,"mtime":1607816383799,"results":"86","hashOfConfig":"56"},{"size":358,"mtime":1607816378529,"results":"87","hashOfConfig":"56"},{"size":902,"mtime":1608450868778,"results":"88","hashOfConfig":"56"},{"size":394,"mtime":1608448546580,"results":"89","hashOfConfig":"56"},{"size":3624,"mtime":1610275595190,"results":"90","hashOfConfig":"56"},{"size":390,"mtime":1608850637136,"results":"91","hashOfConfig":"56"},{"size":1714,"mtime":1608802587649,"results":"92","hashOfConfig":"56"},{"size":318,"mtime":1608852934388,"results":"93","hashOfConfig":"56"},{"size":3907,"mtime":1610440735107,"results":"94","hashOfConfig":"56"},{"size":203,"mtime":1610613848946,"results":"95","hashOfConfig":"56"},{"size":2975,"mtime":1610540007725,"results":"96","hashOfConfig":"56"},{"size":2379,"mtime":1610267137497,"results":"97","hashOfConfig":"56"},{"size":1922,"mtime":1609913154250,"results":"98","hashOfConfig":"56"},{"size":419,"mtime":1609913346831,"results":"99","hashOfConfig":"56"},{"size":1244,"mtime":1610614282569,"results":"100","hashOfConfig":"56"},{"size":1299,"mtime":1610540194952,"results":"101","hashOfConfig":"56"},{"size":3836,"mtime":1610356472899,"results":"102","hashOfConfig":"56"},{"size":369,"mtime":1610350419464,"results":"103","hashOfConfig":"56"},{"size":972,"mtime":1610350671817,"results":"104","hashOfConfig":"56"},{"size":972,"mtime":1610352205750,"results":"105","hashOfConfig":"56"},{"size":369,"mtime":1610351960667,"results":"106","hashOfConfig":"56"},{"size":962,"mtime":1610356100446,"results":"107","hashOfConfig":"56"},{"size":340,"mtime":1610354130554,"results":"108","hashOfConfig":"56"},{"size":2716,"mtime":1610613869470,"results":"109","hashOfConfig":"56"},{"size":1630,"mtime":1610614530760,"results":"110","hashOfConfig":"56"},{"filePath":"111","messages":"112","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},"d20lrd",{"filePath":"114","messages":"115","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"116","messages":"117","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"118"},"9qp08d",{"filePath":"119","messages":"120","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"121","messages":"122","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"123","messages":"124","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"125","messages":"126","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"127","messages":"128","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"129","messages":"130","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"131","messages":"132","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"133","messages":"134","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"135","messages":"136","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"137","usedDeprecatedRules":"113"},{"filePath":"138","messages":"139","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"140","messages":"141","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"142","messages":"143","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"144","messages":"145","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"146","messages":"147","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"148","messages":"149","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"150","messages":"151","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"152","messages":"153","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"154","usedDeprecatedRules":"113"},{"filePath":"155","messages":"156","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"157","messages":"158","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"159","messages":"160","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"161","messages":"162","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"163","messages":"164","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"165","messages":"166","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"167","messages":"168","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"169","usedDeprecatedRules":"113"},{"filePath":"170","messages":"171","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"172","messages":"173","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"174","messages":"175","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"176","messages":"177","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"178","messages":"179","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"180","messages":"181","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"182","messages":"183","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"184","messages":"185","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"186","messages":"187","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"188","messages":"189","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"190","messages":"191","errorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"192","usedDeprecatedRules":"113"},{"filePath":"193","messages":"194","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"195","messages":"196","errorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":"197","usedDeprecatedRules":"113"},{"filePath":"198","messages":"199","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"200","messages":"201","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"202","messages":"203","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"204","messages":"205","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"206","messages":"207","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"208","messages":"209","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"210","usedDeprecatedRules":"113"},{"filePath":"211","messages":"212","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"213","messages":"214","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"215","messages":"216","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"217","messages":"218","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"219","messages":"220","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"221","messages":"222","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"223","messages":"224","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"225","messages":"226","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/index.js",[],["227","228"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/App.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/counter/Counter.js",[],["229","230"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/index.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/counter.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/router.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/asyncDispatchMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/promiseMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/constants.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/templates.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/config.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/servicesGridItem/index.jsx",["231"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Skeleton from '@material-ui/lab/Skeleton';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Button from '@material-ui/core/Button';\nimport Link from '@material-ui/core/Link';\nimport ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ServiceConfigModal from '../serviceConfigModal';\nimport { useTheme } from '@material-ui/core/styles';\nimport {\n getBuildIssuesAction\n} from '../../actions/checkBuildIssues.action';\nimport {\n getServiceMetadataAction\n} from '../../actions/getServiceMetadata.action';\nimport {\n getServiceConfigOptionsAction\n} from '../../actions/getServiceConfigOptions.action';\nimport {\n addSelectedService,\n removeSelectedService\n} from '../../actions/updateSelectedServices.action';\nimport styles from './services-grid-item.module.css';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceMetadata: (serviceName) => dispatch(getServiceMetadataAction(serviceName)),\n dispatchGetServiceConfigOptions: (serviceName) => dispatch(getServiceConfigOptionsAction(serviceName)),\n dispatchGetBuildIssues: (selectedServices, serviceConfigurations) => dispatch(getBuildIssuesAction(selectedServices, serviceConfigurations)),\n dispatchAddSelectedService: (serviceName) => dispatch(addSelectedService(serviceName)),\n dispatchRemoveSelectedService: (serviceName) => dispatch(removeSelectedService(serviceName))\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n templateList: selector(state => state.templateList),\n configServiceMetadata: selector(state => state.configServiceMetadata),\n configServiceConfigOptions: selector(state => state.configServiceConfigOptions),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues)\n };\n};\n\nconst useStyles = makeStyles({\n serviceCard: {\n \"&:hover\": {\n borderColor: ({ theme }) => theme.palette.text.primary\n }\n }\n});\n\nconst ServiceItem = (props) => {\n const theme = useTheme();\n const classes = useStyles({ props, theme });\n // console.log('theme.palette', theme.palette)\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n serviceName,\n networkTemplateList,\n serviceTemplates,\n dispatchGetServiceMetadata,\n dispatchGetServiceConfigOptions,\n dispatchAddSelectedService,\n dispatchRemoveSelectedService,\n dispatchGetBuildIssues,\n configServiceMetadata,\n configServiceConfigOptions,\n selectedServices,\n hideServiceTags,\n buildIssues,\n buildOptions,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const [isLoading, setIsLoading] = useState(false);\n const [serviceMetadata, setServiceMetadata] = useState({});\n const [serviceMetadataError, setServiceMetadataError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceMetadata.services.completed[serviceName] === 'undefined'\n && typeof configServiceMetadata.services.failed[serviceName] === 'undefined'\n && !configServiceMetadata.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceMetadata(serviceName);\n }\n\n setIsLoading(false);\n\n if (typeof configServiceMetadata.services.completed[serviceName] === 'object') {\n setServiceMetadata(configServiceMetadata.services.completed[serviceName].payload);\n } else if (!configServiceMetadata.services.pending.includes(serviceName)) {\n setServiceMetadataError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceMetadata,\n configServiceMetadata.services.completed,\n configServiceMetadata.services.pending,\n configServiceMetadata.services.failed\n ]);\n\n const [serviceConfigOptions, setServiceConfigOptions] = useState({});\n const [serviceConfigOptionsError, setServiceConfigOptionsError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceConfigOptions.services.completed[serviceName] === 'undefined'\n && typeof configServiceConfigOptions.services.failed[serviceName] === 'undefined'\n && !configServiceConfigOptions.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceConfigOptions(serviceName);\n }\n\n // setIsLoading(false);\n\n if (typeof configServiceConfigOptions.services.completed[serviceName] === 'object') {\n setServiceConfigOptions(configServiceConfigOptions.services.completed[serviceName].payload);\n } else if (!configServiceConfigOptions.services.pending.includes(serviceName)) {\n setServiceConfigOptionsError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceConfigOptions,\n configServiceConfigOptions.services.completed,\n configServiceConfigOptions.services.pending,\n configServiceConfigOptions.services.failed\n ]);\n\n const [updated, setIsUpdated] = useState(false);\n useEffect(() => {\n if (updated) {\n dispatchGetBuildIssues(selectedServices.selectedServices, {});\n }\n setIsUpdated(false);\n }, [\n updated,\n serviceName,\n selectedServices.selectedServices,\n dispatchGetBuildIssues\n ]);\n\n const [hasIssue, setHasIssue] = useState(false);\n useEffect(() => {\n if (!selectedServices.selectedServices.includes(serviceName)) {\n return void setHasIssue(false);\n }\n const issueList = buildIssues?.payload?.issueList ?? {};\n if (Array.isArray(issueList.services)) {\n issueList.services.forEach((service) => {\n if (service.name === serviceName) {\n return void setHasIssue(true);\n }\n });\n }\n }, [buildIssues, selectedServices.selectedServices, serviceName]);\n\n const handleBuildSelectChange = (evt) => {\n setIsUpdated(true);\n if (evt.target.checked) {\n return dispatchAddSelectedService(serviceName);\n }\n return dispatchRemoveSelectedService(serviceName);\n }\n\n const [modalOpen, setModalOpen] = useState(false);\n\n const serviceComponent = () => {\n return (\n \n setModalOpen(false)}\n serviceMetadata={serviceMetadata}\n serviceConfigOptions={serviceConfigOptions}\n serviceName={serviceName}\n buildOptions={buildOptions}\n setBuildOptions={setBuildOptions}\n setServiceOptions={setServiceOptions}\n getBuildOptions={getBuildOptions}\n buildOptionsInit={buildOptionsInit}\n setTemporaryBuildOptions={setTemporaryBuildOptions}\n getTemporaryBuildOptions={getTemporaryBuildOptions}\n setTemporaryServiceOptions={setTemporaryServiceOptions}\n setupTemporaryBuildOptions={setupTemporaryBuildOptions}\n saveTemporaryBuildOptions={saveTemporaryBuildOptions}\n networkTemplateList={networkTemplateList}\n serviceTemplates={serviceTemplates}\n />\n {serviceMetadata.displayName}\n \n {!serviceMetadata.iconUri\n && (\n \n \n \n )}\n {serviceMetadata.iconUri\n && (\n \n
\n {`${serviceMetadata.displayName}\n
\n
\n )}\n
\n \n \n \n \n \n }\n label={`Add ${serviceMetadata.displayName} to build`}\n />\n \n \n \n {serviceMetadata.displayName} Help and Docs\n \n \n \n )\n };\n\n const errorComponent = () => {\n return (\n \n
Error loading: {serviceName}
\n
Try refreshing, and ensuring the API server is running correctly.
\n
\n )\n };\n\n const loadingComponent = () => {\n return (\n \n Loading '{serviceName}' metadata...\n \n \n \n \n \n \n \n \n \n \n \n \n \n )\n };\n\n const highlightClass = () => {\n if (selectedServices.selectedServices.includes(serviceName)) {\n if (hasIssue) {\n return styles.serviceError;\n } else {\n return styles.selectedForBuild;\n }\n }\n\n return '';\n };\n\n const tagIsHidden = (hiddenTags, serviceTags) => {\n let hide = false;\n\n hiddenTags.forEach((hiddenTag) => {\n serviceTags.forEach((serviceTag) => {\n if (hiddenTag === serviceTag) {\n hide = true;\n }\n });\n });\n\n return hide;\n }\n\n if (!isLoading && tagIsHidden(hideServiceTags.hideServiceTags, serviceMetadata.serviceTypeTags)) {\n return null;\n }\n\n return (\n \n \n {isLoading\n && (loadingComponent())}\n {!isLoading\n && serviceMetadata.displayName\n && (\n serviceComponent()\n )}\n {!isLoading\n && serviceMetadataError.hasError === true\n && (\n errorComponent()\n )}\n \n \n );\n};\n\nexport default ServiceItem;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceMetadataReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceMetadata.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/configs.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedServicesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateSelectedServices.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/Sidebar/index.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/notFound/index.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/buildHistory/index.jsx",["232"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport BuildHistoryGridItem from '../../features/buildHistoryGridItem'\nimport {\n getBuildHistoryListAction\n} from '../../actions/getBuildHistoryList.action';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetBuildHistoryList: () => dispatch(getBuildHistoryListAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n buildHistory: selector(state => state.buildHistory)\n };\n};\n\nconst Main = (props) => {\n\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const { dispatchGetBuildHistoryList, buildHistory } = props;\n\n useEffect(() => {\n dispatchGetBuildHistoryList();\n }, []);\n\n return (\n \n
\n \n {typeof buildHistory.payload !== 'undefined' && Object.keys(buildHistory.payload.buildsList).map((buildDetailsTime) => {\n return (\n \n \n \n );\n })}\n \n
\n
\n );\n}\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/help/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/scripts/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildHistoryListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getBuildHistoryList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/builds.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildHistoryGridItem/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/BuildSidebar/index.jsx",["233","234"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\n// import Tooltip from '@material-ui/core/Tooltip';\nimport Button from '@material-ui/core/Button';\n// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport Divider from '@material-ui/core/Divider';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n// import { makeStyles, useTheme } from '@material-ui/core/styles';\nimport styles from './build-sidebar.module.css';\nimport {\n addTagToHideListAction,\n removeTagFromHideListAction\n} from '../../actions/updateFilterTags.action';\nimport {\n createAndBuildStackAction\n} from '../../actions/buildStack.action';\nimport {\n getScriptFromTemplateAction\n} from '../../actions/getScript.action';\nimport {\n downloadBuildFile\n} from '../../actions/downloadBuild.action';\nimport BuildCompletedModal from '../buildCompletedModal';\nimport { API_STATUS } from '../../constants'\n\n// const useStyles = makeStyles({\n// serviceCard: {\n// \"&:hover\": {\n// borderColor: ({ theme }) => theme.palette.text.primary\n// }\n// }\n// });\n\nconst getUniqueTagsFromTemplates = ({ serviceTemplateListPayload, metadataList }) => {\n const tagList = [];\n if (Array.isArray(serviceTemplateListPayload)) {\n serviceTemplateListPayload.forEach((service) => {\n if (metadataList[service] && metadataList[service].payload && Array.isArray(metadataList[service].payload.serviceTypeTags)) {\n metadataList[service].payload.serviceTypeTags.forEach((tag) => {\n if (!tagList.includes(tag)) {\n tagList.push(tag);\n }\n });\n }\n });\n }\n tagList.sort();\n return tagList;\n};\n\nconst buildIssueListItem = (name, issueType, issueText) => {\n return (\n {name} [{issueType}] - {issueText}\n );\n};\n\nconst buildIssuesRender = (issues) => {\n const unknownError = !(\n issues.payload\n && issues.payload.issueList\n && Array.isArray(issues.payload.issueList.services)\n && Array.isArray(issues.payload.issueList.networks)\n && Array.isArray(issues.payload.issueList.other)\n );\n\n const noIssues = (\n !unknownError\n && issues.payload.issueList.services.length === 0\n && issues.payload.issueList.networks.length === 0\n && issues.payload.issueList.other.length === 0\n );\n\n return (\n \n Build Issues:\n \n {issues.status === API_STATUS.SUCCESS\n && (\n \n {Array.isArray(issues.payload.issueList.services)\n && issues.payload.issueList.services.length > 0\n && (\n \n \n Services:\n \n
    \n {issues.payload.issueList.services.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.networks)\n && issues.payload.issueList.networks.length > 0\n && (\n \n \n Networks:\n \n
    \n {issues.payload.issueList.networks.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.other)\n && issues.payload.issueList.other.length > 0\n && (\n \n \n Other Issues:\n \n
    \n {issues.payload.issueList.other.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {noIssues\n && (\n \n \n No build issues\n \n \n )}\n {!noIssues\n && (\n \n \n You can still attempt to build when issues are reported.\n \n \n )}\n {unknownError\n && (\n \n \n An unknown error occured retrieving build issues\n \n \n )}\n
\n )}\n {issues.status === API_STATUS.PENDING\n && (\n Loading...\n )}\n {issues.status === API_STATUS.FAILURE\n && (\n Failed to get build issues from API\n )}\n {issues.status === API_STATUS.UNINIT\n && (\n No changes detected\n )}\n
\n
\n );\n};\n\nconst buildList = (selectedServices) => {\n return (\n \n Building Services:\n \n {selectedServices.join(', ')}\n \n \n );\n};\n\nconst buildServices = (dispatchBuildStack) => {\n return (\n \n Build:\n \n \n \n \n );\n};\n\nconst Sidebar = (props) => {\n // const theme = useTheme();\n // const classes = useStyles({ props, theme });\n\n const mapStateToProps = (selector) => {\n return {\n configServiceMetadata: selector(state => state.configServiceMetadata),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues),\n buildStack: selector(state => state.buildStack),\n scriptTemplates: selector(state => state.scriptTemplates)\n };\n };\n const mapDispatchToProps = (dispatch) => {\n return {\n dispatchAddTagToHideList: (tag) => dispatch(addTagToHideListAction(tag)),\n dispatchRemoveTagFromHideList: (tag) => dispatch(removeTagFromHideListAction(tag)),\n dispatchBuildStack: (selectedServices, serviceConfigurations) => dispatch(createAndBuildStackAction(selectedServices, serviceConfigurations)),\n dispatchGetScriptTemplates: ({ scriptName, options, linkRef }) => dispatch(getScriptFromTemplateAction({ scriptName, options, linkRef })),\n dispatchDownloadBuildFile: ({ build, type, linkRef }) => dispatch(downloadBuildFile({ build, type, linkRef }))\n };\n };\n \n props = {\n ...props,\n ...mapStateToProps(useSelector),\n ...mapDispatchToProps(useDispatch()),\n };\n\n const [modalOpen, setModalOpen] = useState(false);\n useEffect(() => {\n if (props.buildStack.status === API_STATUS.SUCCESS) {\n setModalOpen(true);\n }\n }, [\n props.buildStack\n ]);\n\n const {\n serviceTemplateList,\n configServiceMetadata,\n selectedServices,\n buildIssues,\n hideServiceTags,\n dispatchRemoveTagFromHideList,\n dispatchAddTagToHideList,\n dispatchBuildStack,\n dispatchGetScriptTemplates,\n dispatchDownloadBuildFile,\n buildStack,\n scriptTemplates\n } = props;\n\n const downloadLinkRef = React.useRef(null);\n\n const handleBuildSelectChange = (evt, tagName) => {\n if (evt.target.checked) {\n return dispatchAddTagToHideList(tagName);\n }\n return dispatchRemoveTagFromHideList(tagName);\n };\n\n const serviceFilter = (serviceTemplateListPayload, servicesMetadata) => {\n return (\n \n Hide by tag:\n \n {\n getUniqueTagsFromTemplates({ serviceTemplateListPayload, metadataList: servicesMetadata }).map((tag) => {\n return (\n -1}\n onChange={(evt) => handleBuildSelectChange(evt, tag)}\n name=\"checkedB\"\n color=\"primary\"\n />\n }\n label={tag}\n />\n );\n })\n }\n \n \n );\n };\n \n return (\n \n \n setModalOpen(false)}\n buildStack={buildStack}\n scriptTemplates={scriptTemplates}\n dispatchGetScriptTemplates={dispatchGetScriptTemplates}\n dispatchDownloadBuildFile={dispatchDownloadBuildFile}\n downloadLinkRef={downloadLinkRef}\n />\n \n {serviceFilter(serviceTemplateList.payload, configServiceMetadata.services.completed)}\n \n {buildIssuesRender(buildIssues)}\n \n {buildList(selectedServices.selectedServices)}\n \n {buildServices(() => {\n if (Array.isArray(selectedServices.selectedServices) && selectedServices.selectedServices.length > 0) {\n dispatchBuildStack(selectedServices.selectedServices);\n }\n })}\n \n \n );\n};\n\nexport default Sidebar;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateFilterTags.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedFilterTagsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildIssuesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/checkBuildIssues.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/buildStackReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/buildStack.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildCompletedModal/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getScript.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getScriptTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/downloadBuild.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceConfigModal/index.jsx",["235","236","237","238"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Modal from '@material-ui/core/Modal';\nimport Grid from '@material-ui/core/Grid';\nimport Button from \"@material-ui/core/Button\";\nimport Box from '@material-ui/core/Box';\nimport getConfigComponents from '../../utils/configOptionLoader';\nimport {\n deleteTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst getModalStyle = () => {\n const top = 10;\n const left = 50;\n\n return {\n top: `${top}%`,\n left: `${left}%`,\n maxHeight: '75%',\n overflow: 'hidden',\n overflowY: 'scroll',\n transform: `translate(-50%, 0%)`,\n };\n};\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n position: 'absolute',\n width: '50%',\n backgroundColor: theme.palette.background.paper,\n border: '2px solid #000',\n boxShadow: theme.shadows[5],\n padding: theme.spacing(2, 4, 3),\n },\n}));\n\nconst ServiceConfigModal = (props) => {\n const {\n isOpen,\n handleClose,\n serviceName,\n networkTemplateList,\n serviceMetadata,\n serviceConfigOptions,\n buildOptions,\n serviceTemplates,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const closeModal = (event) => {\n deleteTemporaryBuildOptions();\n if (typeof handleClose === 'function') {\n handleClose(event);\n }\n }\n\n const classes = useStyles();\n const [modalStyle] = React.useState(getModalStyle);\n const body = (\n
\n

{serviceMetadata ? serviceMetadata.displayName : ''} ({serviceName}) Configuration

\n \n {getConfigComponents(serviceConfigOptions ?? []).map((ConfigComponent, index) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n \n \n \n \n \n \n
\n );\n\n return (\n \n {body}\n \n );\n};\n\nexport default ServiceConfigModal;","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/index.js",["239"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/portConfig.jsx",["240","241","242","243","244","245","246"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getExternalPort,\n replaceExternalPort,\n getInternalPort\n} from '../../../utils/parsers';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [portSettings, setPortSettings] = useState(getBuildOptions()?.services?.[serviceName]?.ports || {});\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n ports: portSettings\n });\n }, [\n portSettings\n ]);\n\n const onChangeCb = (portKey, portLabelValue, event) => {\n const newPort = event.target.value;\n // const defaultTemplatePort = defaultValue(portKey, portKey);\n setPortSettings({\n ...portSettings,\n [portKey]: replaceExternalPort((portSettings[portKey] || portKey), newPort)\n });\n if (typeof(onChange) === 'function') {\n onChange(portKey, portLabelValue, newPort);\n }\n };\n\n const defaultValue = (portValueKey, defaultValue) => {\n const servicePorts = tempBuildOptions?.services?.[serviceName] ?? {};\n return servicePorts?.ports?.[portValueKey] ?? defaultValue;\n };\n\n return (\n \n \n {serviceConfigOptions && Object.keys(serviceConfigOptions.labeledPorts).map((portValueKey) => {\n const currentPortSetting = portSettings[portValueKey] || defaultValue(portValueKey, portValueKey);\n if ((serviceTemplates[serviceName]?.ports?.[portValueKey] ?? []).indexOf(portValueKey)) { // Only show ports that exist in the YAML template\n return (\n \n { onChangeCb(portValueKey, serviceConfigOptions.labeledPorts[portValueKey], event) }}\n value={getExternalPort(currentPortSetting)}\n />\n \n );\n }\n\n return null;\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/buildOptionSync.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceConfigOptionsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceConfigOptions.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/configOptionLoader.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/parsers.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/mainBuild/index.jsx",["247"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport Box from '@material-ui/core/Box';\nimport ServiceGridItem from '../../features/servicesGridItem';\nimport BuildSidebar from '../../features/BuildSidebar';\nimport { getServiceTemplateListAction } from '../../actions/getServiceTemplateList.action';\nimport { getServiceTemplatesAction } from '../../actions/getServiceTemplates.action';\nimport { getNetworkTemplateListAction } from '../../actions/getNetworkTemplateList.action';\nimport {\n getBuildOptions,\n setBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceTemplatesList: () => dispatch(getServiceTemplateListAction()),\n dispatchGetNetworkTemplatesList: () => dispatch(getNetworkTemplateListAction()),\n dispatchGetServiceTemplates: () => dispatch(getServiceTemplatesAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n serviceTemplateList: selector(state => state.serviceTemplateList),\n networkTemplateList: selector(state => state.networkTemplateList),\n serviceTemplates: selector(state => state.serviceTemplates)\n };\n};\n\nconst Main = (props) => {\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n dispatchGetServiceTemplatesList,\n dispatchGetNetworkTemplatesList,\n dispatchGetServiceTemplates,\n serviceTemplateList,\n networkTemplateList,\n serviceTemplates\n } = props;\n const buildOptions = getBuildOptions();\n\n useEffect(() => {\n dispatchGetServiceTemplatesList();\n dispatchGetNetworkTemplatesList();\n dispatchGetServiceTemplates();\n }, []);\n\n return (\n \n
\n \n \n \n {Array.isArray(serviceTemplateList.payload) && serviceTemplateList.payload.map((templateName) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n\n
\n
\n );\n};\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getNetworkTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getNetworkTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplates.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/networkConfig.jsx",["248","249","250","251","252","253","254","255","256","257"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/logging.jsx",["258","259","260","261","262","263","264","265","266","267"],{"ruleId":"268","replacedBy":"269"},{"ruleId":"270","replacedBy":"271"},{"ruleId":"268","replacedBy":"272"},{"ruleId":"270","replacedBy":"273"},{"ruleId":"274","severity":1,"message":"275","line":127,"column":10,"nodeType":"276","messageId":"277","endLine":127,"endColumn":35},{"ruleId":"278","severity":1,"message":"279","line":34,"column":6,"nodeType":"280","endLine":34,"endColumn":8,"suggestions":"281"},{"ruleId":"282","severity":1,"message":"283","line":300,"column":7,"nodeType":"284","endLine":300,"endColumn":34},{"ruleId":"285","severity":1,"message":"286","line":300,"column":7,"nodeType":"284","endLine":300,"endColumn":34},{"ruleId":"274","severity":1,"message":"287","line":1,"column":27,"nodeType":"276","messageId":"277","endLine":1,"endColumn":35},{"ruleId":"274","severity":1,"message":"288","line":1,"column":37,"nodeType":"276","messageId":"277","endLine":1,"endColumn":46},{"ruleId":"274","severity":1,"message":"289","line":10,"column":3,"nodeType":"276","messageId":"277","endLine":10,"endColumn":28},{"ruleId":"274","severity":1,"message":"290","line":46,"column":5,"nodeType":"276","messageId":"277","endLine":46,"endColumn":17},{"ruleId":"291","severity":1,"message":"292","line":5,"column":1,"nodeType":"293","endLine":9,"endColumn":3},{"ruleId":"274","severity":1,"message":"294","line":16,"column":5,"nodeType":"276","messageId":"277","endLine":16,"endColumn":20},{"ruleId":"274","severity":1,"message":"295","line":18,"column":5,"nodeType":"276","messageId":"277","endLine":18,"endColumn":21},{"ruleId":"274","severity":1,"message":"296","line":19,"column":5,"nodeType":"276","messageId":"277","endLine":19,"endColumn":22},{"ruleId":"274","severity":1,"message":"297","line":20,"column":5,"nodeType":"276","messageId":"277","endLine":20,"endColumn":29},{"ruleId":"274","severity":1,"message":"298","line":23,"column":5,"nodeType":"276","messageId":"277","endLine":23,"endColumn":31},{"ruleId":"274","severity":1,"message":"299","line":24,"column":5,"nodeType":"276","messageId":"277","endLine":24,"endColumn":30},{"ruleId":"278","severity":1,"message":"300","line":37,"column":6,"nodeType":"280","endLine":39,"endColumn":4,"suggestions":"301"},{"ruleId":"278","severity":1,"message":"302","line":60,"column":6,"nodeType":"280","endLine":60,"endColumn":8,"suggestions":"303"},{"ruleId":"274","severity":1,"message":"304","line":9,"column":5,"nodeType":"276","messageId":"277","endLine":9,"endColumn":25},{"ruleId":"274","severity":1,"message":"294","line":11,"column":5,"nodeType":"276","messageId":"277","endLine":11,"endColumn":20},{"ruleId":"274","severity":1,"message":"295","line":13,"column":5,"nodeType":"276","messageId":"277","endLine":13,"endColumn":21},{"ruleId":"274","severity":1,"message":"296","line":14,"column":5,"nodeType":"276","messageId":"277","endLine":14,"endColumn":22},{"ruleId":"274","severity":1,"message":"297","line":16,"column":5,"nodeType":"276","messageId":"277","endLine":16,"endColumn":29},{"ruleId":"274","severity":1,"message":"298","line":19,"column":5,"nodeType":"276","messageId":"277","endLine":19,"endColumn":31},{"ruleId":"274","severity":1,"message":"299","line":20,"column":5,"nodeType":"276","messageId":"277","endLine":20,"endColumn":30},{"ruleId":"274","severity":1,"message":"305","line":25,"column":9,"nodeType":"276","messageId":"277","endLine":25,"endColumn":25},{"ruleId":"278","severity":1,"message":"306","line":36,"column":6,"nodeType":"280","endLine":36,"endColumn":8,"suggestions":"307"},{"ruleId":"278","severity":1,"message":"300","line":43,"column":6,"nodeType":"280","endLine":45,"endColumn":4,"suggestions":"308"},{"ruleId":"274","severity":1,"message":"304","line":10,"column":5,"nodeType":"276","messageId":"277","endLine":10,"endColumn":25},{"ruleId":"274","severity":1,"message":"294","line":12,"column":5,"nodeType":"276","messageId":"277","endLine":12,"endColumn":20},{"ruleId":"274","severity":1,"message":"295","line":14,"column":5,"nodeType":"276","messageId":"277","endLine":14,"endColumn":21},{"ruleId":"274","severity":1,"message":"296","line":15,"column":5,"nodeType":"276","messageId":"277","endLine":15,"endColumn":22},{"ruleId":"274","severity":1,"message":"297","line":16,"column":5,"nodeType":"276","messageId":"277","endLine":16,"endColumn":29},{"ruleId":"274","severity":1,"message":"298","line":19,"column":5,"nodeType":"276","messageId":"277","endLine":19,"endColumn":31},{"ruleId":"274","severity":1,"message":"299","line":20,"column":5,"nodeType":"276","messageId":"277","endLine":20,"endColumn":30},{"ruleId":"274","severity":1,"message":"309","line":21,"column":5,"nodeType":"276","messageId":"277","endLine":21,"endColumn":21},{"ruleId":"274","severity":1,"message":"305","line":25,"column":9,"nodeType":"276","messageId":"277","endLine":25,"endColumn":25},{"ruleId":"278","severity":1,"message":"300","line":33,"column":6,"nodeType":"280","endLine":35,"endColumn":4,"suggestions":"310"},"no-native-reassign",["311"],"no-negated-in-lhs",["312"],["311"],["312"],"no-unused-vars","'serviceConfigOptionsError' is assigned a value but never used.","Identifier","unusedVar","react-hooks/exhaustive-deps","React Hook useEffect has a missing dependency: 'dispatchGetBuildHistoryList'. Either include it or remove the dependency array.","ArrayExpression",["313"],"jsx-a11y/anchor-has-content","Anchors must have content and the content must be accessible by a screen reader.","JSXOpeningElement","jsx-a11y/anchor-is-valid","The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md","'useState' is defined but never used.","'useEffect' is defined but never used.","'saveTemporaryBuildOptions' is defined but never used.","'buildOptions' is assigned a value but never used.","import/no-anonymous-default-export","Assign object to a variable before exporting as module default","ExportDefaultDeclaration","'setBuildOptions' is assigned a value but never used.","'buildOptionsInit' is assigned a value but never used.","'setServiceOptions' is assigned a value but never used.","'setTemporaryBuildOptions' is assigned a value but never used.","'setupTemporaryBuildOptions' is assigned a value but never used.","'saveTemporaryBuildOptions' is assigned a value but never used.","React Hook useEffect has missing dependencies: 'getTemporaryBuildOptions', 'serviceName', and 'setTemporaryServiceOptions'. Either include them or remove the dependency array.",["314"],"React Hook useEffect has missing dependencies: 'dispatchGetNetworkTemplatesList', 'dispatchGetServiceTemplates', and 'dispatchGetServiceTemplatesList'. Either include them or remove the dependency array.",["315"],"'serviceConfigOptions' is assigned a value but never used.","'tempBuildOptions' is assigned a value but never used.","React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceName', and 'serviceTemplates'. Either include them or remove the dependency array.",["316"],["317"],"'serviceTemplates' is assigned a value but never used.",["318"],"no-global-assign","no-unsafe-negation",{"desc":"319","fix":"320"},{"desc":"321","fix":"322"},{"desc":"323","fix":"324"},{"desc":"325","fix":"326"},{"desc":"327","fix":"328"},{"desc":"329","fix":"330"},"Update the dependencies array to be: [dispatchGetBuildHistoryList]",{"range":"331","text":"332"},"Update the dependencies array to be: [getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",{"range":"333","text":"334"},"Update the dependencies array to be: [dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",{"range":"335","text":"336"},"Update the dependencies array to be: [getBuildOptions, serviceName, serviceTemplates]",{"range":"337","text":"338"},"Update the dependencies array to be: [getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",{"range":"339","text":"340"},"Update the dependencies array to be: [getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",{"range":"341","text":"342"},[893,895],"[dispatchGetBuildHistoryList]",[1020,1042],"[getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",[2011,2013],"[dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",[1109,1111],"[getBuildOptions, serviceName, serviceTemplates]",[1298,1327],"[getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",[991,1015],"[getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]"] \ No newline at end of file diff --git a/.internal/wui/.gitignore b/.internal/wui/.gitignore new file mode 100644 index 000000000..c0676348c --- /dev/null +++ b/.internal/wui/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/.internal/wui/README.md b/.internal/wui/README.md new file mode 100644 index 000000000..88116513e --- /dev/null +++ b/.internal/wui/README.md @@ -0,0 +1,68 @@ +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app), using the [Redux](https://redux.js.org/) and [Redux Toolkit](https://redux-toolkit.js.org/) template. + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.
+It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting + +### Analyzing the Bundle Size + +This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size + +### Making a Progressive Web App + +This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app + +### Advanced Configuration + +This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration + +### Deployment + +This section has moved here: https://facebook.github.io/create-react-app/docs/deployment + +### `npm run build` fails to minify + +This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify diff --git a/.internal/wui/package-lock.json b/.internal/wui/package-lock.json new file mode 100644 index 000000000..5d1f1a2e0 --- /dev/null +++ b/.internal/wui/package-lock.json @@ -0,0 +1,17035 @@ +{ + "name": "iotstack_ui", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/compat-data": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", + "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==" + }, + "@babel/core": { + "version": "7.12.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", + "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.1", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.1", + "@babel/parser": "^7.12.3", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "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==" + } + } + }, + "@babel/generator": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "requires": { + "@babel/types": "^7.12.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-react-jsx": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz", + "integrity": "sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-react-jsx-experimental": { + "version": "7.12.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.12.4.tgz", + "integrity": "sha512-AjEa0jrQqNk7eDQOo0pTfUOwQBMF+xVqrausQwT9/rTKy0g04ggFNaJpaE09IQMn9yExluigWMJcj0WC7bq+Og==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-module-imports": "^7.12.1", + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", + "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "requires": { + "@babel/compat-data": "^7.12.5", + "@babel/helper-validator-option": "^7.12.1", + "browserslist": "^4.14.5", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", + "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", + "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", + "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", + "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "requires": { + "@babel/types": "^7.12.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "requires": { + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", + "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/helper-validator-identifier": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "lodash": "^4.17.19" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", + "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", + "requires": { + "@babel/types": "^7.12.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", + "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-replace-supers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", + "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", + "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", + "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" + }, + "@babel/helper-validator-option": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", + "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==" + }, + "@babel/helper-wrap-function": { + "version": "7.12.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", + "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helpers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", + "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==" + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", + "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", + "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.12.1.tgz", + "integrity": "sha512-knNIuusychgYN8fGJHONL0RbFxLGawhXOJNLBk75TniTsZZeA+wdkDuv6wp4lGwzQEKjZi6/WYtnb3udNPmQmQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-decorators": "^7.12.1" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", + "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", + "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", + "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", + "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", + "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", + "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", + "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", + "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", + "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", + "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", + "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.12.1.tgz", + "integrity": "sha512-ir9YW5daRrTYiy9UJ2TzdNIJEZu8KclVzDcfSt4iEmOtwQ4llPtWInNKJyKnVXp1vE4bbVd5S31M/im3mYMO1w==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.1.tgz", + "integrity": "sha512-1lBLLmtxrwpm4VKmtVFselI/P3pX+G63fAtUUt6b2Nzgao77KNDwyuRt90Mj2/9pKobtt68FdvjfqohZjg/FCA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", + "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.1.tgz", + "integrity": "sha512-UZNEcCY+4Dp9yYRCAHrHDU+9ZXLYaY9MgBXSRLkB9WjYFRR6quJBumfVrEkUxrePPBwFcpWfNKXqVRQQtm7mMA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", + "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", + "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", + "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", + "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", + "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", + "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", + "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", + "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", + "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", + "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.1.tgz", + "integrity": "sha512-8hAtkmsQb36yMmEtk2JZ9JnVyDSnDOdlB+0nEGzIDLuK4yR3JcEjfuFPYkdEPSh8Id+rAMeBEn+X0iVEyho6Hg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", + "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", + "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", + "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", + "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", + "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", + "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.12.1", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", + "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "requires": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-identifier": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", + "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", + "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", + "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", + "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", + "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", + "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.12.1.tgz", + "integrity": "sha512-KOHd0tIRLoER+J+8f9DblZDa1fLGPwaaN1DI1TVHuQFOpjHV22C3CUB3obeC4fexHY9nx+fH0hQNvLFFfA1mxA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz", + "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.7.tgz", + "integrity": "sha512-YFlTi6MEsclFAPIDNZYiCRbneg1MFGao9pPG9uD5htwE0vDbPaMUMeYd6itWjw7K4kro4UbdQf3ljmFl9y48dQ==", + "requires": { + "@babel/helper-builder-react-jsx": "^7.10.4", + "@babel/helper-builder-react-jsx-experimental": "^7.12.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "^7.12.1" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.7.tgz", + "integrity": "sha512-Rs3ETtMtR3VLXFeYRChle5SsP/P9Jp/6dsewBQfokDSzKJThlsuFcnzLTDRALiUmTC48ej19YD9uN1mupEeEDg==", + "requires": { + "@babel/helper-builder-react-jsx-experimental": "^7.12.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "^7.12.1" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.12.1.tgz", + "integrity": "sha512-FbpL0ieNWiiBB5tCldX17EtXgmzeEZjFrix72rQYeq9X6nUK38HCaxexzVQrZWXanxKJPKVVIU37gFjEQYkPkA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.12.1.tgz", + "integrity": "sha512-keQ5kBfjJNRc6zZN1/nVHCd6LLIHq4aUKcVnvE/2l+ZZROSbqoiGFRtT5t3Is89XJxBQaP7NLZX2jgGHdZvvFQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz", + "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", + "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", + "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz", + "integrity": "sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg==", + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "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.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", + "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", + "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", + "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", + "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz", + "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.12.1.tgz", + "integrity": "sha512-VrsBByqAIntM+EYMqSm59SiMEf7qkmI9dqMt6RbD/wlwueWmYcI0FFK5Fj47pP6DRZm+3teXjosKlwcZJ5lIMw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-typescript": "^7.12.1" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", + "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", + "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/preset-env": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.7.tgz", + "integrity": "sha512-OnNdfAr1FUQg7ksb7bmbKoby4qFOHw6DKWWUNB9KqnnCldxhxJlP+21dpyaWFmf2h0rTbOkXJtAGevY3XW1eew==", + "requires": { + "@babel/compat-data": "^7.12.7", + "@babel/helper-compilation-targets": "^7.12.5", + "@babel/helper-module-imports": "^7.12.5", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-option": "^7.12.1", + "@babel/plugin-proposal-async-generator-functions": "^7.12.1", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-dynamic-import": "^7.12.1", + "@babel/plugin-proposal-export-namespace-from": "^7.12.1", + "@babel/plugin-proposal-json-strings": "^7.12.1", + "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.7", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.7", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.12.1", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-async-to-generator": "^7.12.1", + "@babel/plugin-transform-block-scoped-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-computed-properties": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-dotall-regex": "^7.12.1", + "@babel/plugin-transform-duplicate-keys": "^7.12.1", + "@babel/plugin-transform-exponentiation-operator": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-function-name": "^7.12.1", + "@babel/plugin-transform-literals": "^7.12.1", + "@babel/plugin-transform-member-expression-literals": "^7.12.1", + "@babel/plugin-transform-modules-amd": "^7.12.1", + "@babel/plugin-transform-modules-commonjs": "^7.12.1", + "@babel/plugin-transform-modules-systemjs": "^7.12.1", + "@babel/plugin-transform-modules-umd": "^7.12.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", + "@babel/plugin-transform-new-target": "^7.12.1", + "@babel/plugin-transform-object-super": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-property-literals": "^7.12.1", + "@babel/plugin-transform-regenerator": "^7.12.1", + "@babel/plugin-transform-reserved-words": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-sticky-regex": "^7.12.7", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.1", + "@babel/plugin-transform-unicode-escapes": "^7.12.1", + "@babel/plugin-transform-unicode-regex": "^7.12.1", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.12.7", + "core-js-compat": "^3.7.0", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.7.tgz", + "integrity": "sha512-wKeTdnGUP5AEYCYQIMeXMMwU7j+2opxrG0WzuZfxuuW9nhKvvALBjl67653CWamZJVefuJGI219G591RSldrqQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-react-display-name": "^7.12.1", + "@babel/plugin-transform-react-jsx": "^7.12.7", + "@babel/plugin-transform-react-jsx-development": "^7.12.7", + "@babel/plugin-transform-react-jsx-self": "^7.12.1", + "@babel/plugin-transform-react-jsx-source": "^7.12.1", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + } + }, + "@babel/preset-typescript": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.12.1.tgz", + "integrity": "sha512-hNK/DhmoJPsksdHuI/RVrcEws7GN5eamhi28JkO52MqIxU8Z0QpmiSOQxZHWOHV7I3P4UjHV97ay4TcamMA6Kw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.12.1" + } + }, + "@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz", + "integrity": "sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==", + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + }, + "@babel/traverse": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", + "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", + "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@csstools/convert-colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", + "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==" + }, + "@csstools/normalize.css": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", + "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@eslint/eslintrc": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.1.tgz", + "integrity": "sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA==", + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "requires": { + "type-fest": "^0.8.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + } + } + }, + "@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==" + }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" + }, + "@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==" + }, + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "requires": { + "@hapi/hoek": "^8.3.0" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==" + }, + "@jest/console": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/core": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/environment": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "requires": { + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2" + } + }, + "@jest/fake-timers": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "requires": { + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", + "@types/node": "*", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + } + }, + "@jest/globals": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "requires": { + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + } + }, + "@jest/reporters": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "node-notifier": "^8.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "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": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/source-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/test-result": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "requires": { + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + } + }, + "@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "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": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@material-ui/core": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.2.tgz", + "integrity": "sha512-/D1+AQQeYX/WhT/FUk78UCRj8ch/RCglsQLYujYTIqPSJlwZHKcvHidNeVhODXeApojeXjkl0tWdk5C9ofwOkQ==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.2", + "@material-ui/system": "^4.11.2", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.11.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/icons": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz", + "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==", + "requires": { + "@babel/runtime": "^7.4.4" + } + }, + "@material-ui/lab": { + "version": "4.0.0-alpha.57", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.57.tgz", + "integrity": "sha512-qo/IuIQOmEKtzmRD2E4Aa6DB4A87kmY6h0uYhjUmrrgmEAgbbw9etXpWPVXuRK6AGIQCjFzV6WO2i21m1R4FCw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.2", + "clsx": "^1.0.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, + "@material-ui/styles": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.2.tgz", + "integrity": "sha512-xbItf8zkfD3FuGoD9f2vlcyPf9jTEtj9YTJoNNV+NMWaSAHXgrW6geqRoo/IwBuMjqpwqsZhct13e2nUyU9Ljw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.11.2", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.0.3", + "jss-plugin-camel-case": "^10.0.3", + "jss-plugin-default-unit": "^10.0.3", + "jss-plugin-global": "^10.0.3", + "jss-plugin-nested": "^10.0.3", + "jss-plugin-props-sort": "^10.0.3", + "jss-plugin-rule-value-function": "^10.0.3", + "jss-plugin-vendor-prefixer": "^10.0.3", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.14.tgz", + "integrity": "sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==" + } + } + }, + "@material-ui/system": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.2.tgz", + "integrity": "sha512-BELFJEel5E+5DMiZb6XXT3peWRn6UixRvBtKwSxqntmD0+zwbbfCij6jtGwwdJhN1qX/aXrKu10zX31GBaeR7A==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.2", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.14.tgz", + "integrity": "sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==" + } + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" + }, + "@material-ui/utils": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", + "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@npmcli/move-file": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz", + "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==", + "requires": { + "mkdirp": "^1.0.4" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.2.tgz", + "integrity": "sha512-Loc4UDGutcZ+Bd56hBInkm6JyjyCwWy4t2wcDXzN8EDPANgVRj0VP8Nxn0Zq2pc+WKauZwEivQgbDGg4xZO20A==", + "requires": { + "ansi-html": "^0.0.7", + "error-stack-parser": "^2.0.6", + "html-entities": "^1.2.1", + "native-url": "^0.2.6", + "schema-utils": "^2.6.5", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "@reduxjs/toolkit": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.5.0.tgz", + "integrity": "sha512-E/FUraRx+8guw9Hlg/Ja8jI/hwCrmIKed8Annt9YsZw3BQp+F24t5I5b2OWR6pkEHY4hn1BgP08FrTZFRKsdaQ==", + "requires": { + "immer": "^8.0.0", + "redux": "^4.0.0", + "redux-thunk": "^2.3.0", + "reselect": "^4.0.0" + }, + "dependencies": { + "immer": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.0.tgz", + "integrity": "sha512-jm87NNBAIG4fHwouilCHIecFXp5rMGkiFrAuhVO685UnMAlOneEAnOyzPt8OnP47TC11q/E7vpzZe0WvwepFTg==" + } + } + }, + "@rollup/plugin-node-resolve": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", + "integrity": "sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==", + "requires": { + "@rollup/pluginutils": "^3.0.8", + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.14.2" + } + }, + "@rollup/plugin-replace": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.3.4.tgz", + "integrity": "sha512-waBhMzyAtjCL1GwZes2jaE9MjuQ/DQF2BatH3fRivUF3z0JBFrU0U6iBNC/4WR+2rLKhaAhPWDNPYp4mI6RqdQ==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + } + } + }, + "@sheerun/mutationobserver-shim": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz", + "integrity": "sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw==" + }, + "@sinonjs/commons": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@surma/rollup-plugin-off-main-thread": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz", + "integrity": "sha512-yBMPqmd1yEJo/280PAMkychuaALyQ9Lkb5q1ck3mjJrFuEobIfhnQ4J3mbvBoISmR3SWMWV+cGB/I0lCQee79A==", + "requires": { + "ejs": "^2.6.1", + "magic-string": "^0.25.0" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==" + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==" + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==" + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==" + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==" + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==" + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==" + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==" + }, + "@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + } + }, + "@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "requires": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "requires": { + "@babel/types": "^7.12.6" + } + }, + "@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "requires": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + } + }, + "@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "requires": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.4.0.tgz", + "integrity": "sha512-LjepnS/BSAvelnOnnzr6Gg0GcpLmnZ9ThGFK5WJtm1xOqdBE/1IACZU7MMdVzjyUkfFqGz87eRE4hFaSLiUwYg==", + "requires": { + "@babel/core": "^7.9.0", + "@babel/plugin-transform-react-constant-elements": "^7.9.0", + "@babel/preset-env": "^7.9.5", + "@babel/preset-react": "^7.9.4", + "@svgr/core": "^5.4.0", + "@svgr/plugin-jsx": "^5.4.0", + "@svgr/plugin-svgo": "^5.4.0", + "loader-utils": "^2.0.0" + } + }, + "@testing-library/dom": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-6.16.0.tgz", + "integrity": "sha512-lBD88ssxqEfz0wFL6MeUyyWZfV/2cjEZZV3YRpb2IoJRej/4f1jB0TzqIOznTpfR1r34CNesrubxwIlAQ8zgPA==", + "requires": { + "@babel/runtime": "^7.8.4", + "@sheerun/mutationobserver-shim": "^0.3.2", + "@types/testing-library__dom": "^6.12.1", + "aria-query": "^4.0.2", + "dom-accessibility-api": "^0.3.0", + "pretty-format": "^25.1.0", + "wait-for-expect": "^3.0.2" + }, + "dependencies": { + "@jest/types": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", + "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "pretty-format": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", + "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", + "requires": { + "@jest/types": "^25.5.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@testing-library/jest-dom": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-4.2.4.tgz", + "integrity": "sha512-j31Bn0rQo12fhCWOUWy9fl7wtqkp7In/YP2p5ZFyRuiiB9Qs3g+hS4gAmDWONbAHcRmVooNJ5eOHQDCOmUFXHg==", + "requires": { + "@babel/runtime": "^7.5.1", + "chalk": "^2.4.1", + "css": "^2.2.3", + "css.escape": "^1.5.1", + "jest-diff": "^24.0.0", + "jest-matcher-utils": "^24.0.0", + "lodash": "^4.17.11", + "pretty-format": "^24.0.0", + "redent": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/yargs": { + "version": "13.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.11.tgz", + "integrity": "sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" + }, + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" + }, + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + } + } + }, + "@testing-library/react": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-9.5.0.tgz", + "integrity": "sha512-di1b+D0p+rfeboHO5W7gTVeZDIK5+maEgstrZbWZSSvxDyfDRkkyBE1AJR5Psd6doNldluXlCWqXriUfqu/9Qg==", + "requires": { + "@babel/runtime": "^7.8.4", + "@testing-library/dom": "^6.15.0", + "@types/testing-library__react": "^9.1.2" + } + }, + "@testing-library/user-event": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-7.2.1.tgz", + "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==" + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==" + }, + "@types/babel__core": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", + "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.16", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.16.tgz", + "integrity": "sha512-S63Dt4CZOkuTmpLGGWtT/mQdVORJOpx6SZWGVaP56dda/0Nx5nEe82K7/LAm8zYr6SfMq+1N2OreIOrHAx656w==", + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/eslint": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", + "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/estree": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", + "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==" + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", + "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "requires": { + "@types/node": "*" + } + }, + "@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==" + }, + "@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==" + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" + }, + "@types/node": { + "version": "14.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", + "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==" + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/prettier": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz", + "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==" + }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" + }, + "@types/react": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz", + "integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==", + "requires": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.0.tgz", + "integrity": "sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==", + "requires": { + "@types/react": "*" + } + }, + "@types/react-transition-group": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", + "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", + "requires": { + "@types/react": "*" + } + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==" + }, + "@types/stack-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", + "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==" + }, + "@types/tapable": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", + "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==" + }, + "@types/testing-library__dom": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-6.14.0.tgz", + "integrity": "sha512-sMl7OSv0AvMOqn1UJ6j1unPMIHRXen0Ita1ujnMX912rrOcawe4f7wu0Zt9GIQhBhJvH2BaibqFgQ3lP+Pj2hA==", + "requires": { + "pretty-format": "^24.3.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/yargs": { + "version": "13.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.11.tgz", + "integrity": "sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + } + } + }, + "@types/testing-library__react": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@types/testing-library__react/-/testing-library__react-9.1.3.tgz", + "integrity": "sha512-iCdNPKU3IsYwRK9JieSYAiX0+aYDXOGAmrC/3/M7AqqSDKnWWVv07X+Zk1uFSL7cMTUYzv4lQRfohucEocn5/w==", + "requires": { + "@types/react-dom": "*", + "@types/testing-library__dom": "*", + "pretty-format": "^25.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", + "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "pretty-format": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", + "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", + "requires": { + "@jest/types": "^25.5.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@types/uglify-js": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz", + "integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==", + "requires": { + "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==" + } + } + }, + "@types/webpack": { + "version": "4.41.25", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.25.tgz", + "integrity": "sha512-cr6kZ+4m9lp86ytQc1jPOJXgINQyz3kLLunZ57jznW+WIAL0JqZbGubQk4GlD42MuQL5JGOABrxdpqqWeovlVQ==", + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "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==" + } + } + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "@types/yargs": { + "version": "15.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.10.tgz", + "integrity": "sha512-z8PNtlhrj7eJNLmrAivM7rjBESG6JwC5xP3RVk12i/8HVP7Xnx/sEmERnRImyEuUaJfO942X0qMOYsoupaJbZQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.9.0.tgz", + "integrity": "sha512-WrVzGMzzCrgrpnQMQm4Tnf+dk+wdl/YbgIgd5hKGa2P+lnJ2MON+nQnbwgbxtN9QDLi8HO+JAq0/krMnjQK6Cw==", + "requires": { + "@typescript-eslint/experimental-utils": "4.9.0", + "@typescript-eslint/scope-manager": "4.9.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.0.tgz", + "integrity": "sha512-0p8GnDWB3R2oGhmRXlEnCvYOtaBCijtA5uBfH5GxQKsukdSQyI4opC4NGTUb88CagsoNQ4rb/hId2JuMbzWKFQ==", + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.9.0", + "@typescript-eslint/types": "4.9.0", + "@typescript-eslint/typescript-estree": "4.9.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.9.0.tgz", + "integrity": "sha512-QRSDAV8tGZoQye/ogp28ypb8qpsZPV6FOLD+tbN4ohKUWHD2n/u0Q2tIBnCsGwQCiD94RdtLkcqpdK4vKcLCCw==", + "requires": { + "@typescript-eslint/scope-manager": "4.9.0", + "@typescript-eslint/types": "4.9.0", + "@typescript-eslint/typescript-estree": "4.9.0", + "debug": "^4.1.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.0.tgz", + "integrity": "sha512-q/81jtmcDtMRE+nfFt5pWqO0R41k46gpVLnuefqVOXl4QV1GdQoBWfk5REcipoJNQH9+F5l+dwa9Li5fbALjzg==", + "requires": { + "@typescript-eslint/types": "4.9.0", + "@typescript-eslint/visitor-keys": "4.9.0" + } + }, + "@typescript-eslint/types": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.0.tgz", + "integrity": "sha512-luzLKmowfiM/IoJL/rus1K9iZpSJK6GlOS/1ezKplb7MkORt2dDcfi8g9B0bsF6JoRGhqn0D3Va55b+vredFHA==" + }, + "@typescript-eslint/typescript-estree": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.0.tgz", + "integrity": "sha512-rmDR++PGrIyQzAtt3pPcmKWLr7MA+u/Cmq9b/rON3//t5WofNR4m/Ybft2vOLj0WtUzjn018ekHjTsnIyBsQug==", + "requires": { + "@typescript-eslint/types": "4.9.0", + "@typescript-eslint/visitor-keys": "4.9.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.0.tgz", + "integrity": "sha512-sV45zfdRqQo1A97pOSx3fsjR+3blmwtdCt8LDrXgCX36v4Vmz4KHrhpV6Fo2cRdXmyumxx11AHw0pNJqCNpDyg==", + "requires": { + "@typescript-eslint/types": "4.9.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==" + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" + }, + "adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==" + } + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=" + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-includes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", + "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "get-intrinsic": "^1.0.1", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=" + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "axe-core": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz", + "integrity": "sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==" + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "requires": { + "babylon": "^6.18.0" + } + }, + "babel-jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "requires": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + } + } + }, + "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==" + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "babel-preset-current-node-syntax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz", + "integrity": "sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q==", + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "requires": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "babel-preset-react-app": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.0.tgz", + "integrity": "sha512-itL2z8v16khpuKutx5IH8UdCdSTuzrOhRFTEdIhveZ2i1iBKDrVE0ATa4sFVy+02GLucZNVBWtoarXBy0Msdpg==", + "requires": { + "@babel/core": "7.12.3", + "@babel/plugin-proposal-class-properties": "7.12.1", + "@babel/plugin-proposal-decorators": "7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.12.1", + "@babel/plugin-proposal-numeric-separator": "7.12.1", + "@babel/plugin-proposal-optional-chaining": "7.12.1", + "@babel/plugin-transform-flow-strip-types": "7.12.1", + "@babel/plugin-transform-react-display-name": "7.12.1", + "@babel/plugin-transform-runtime": "7.12.1", + "@babel/preset-env": "7.12.1", + "@babel/preset-react": "7.12.1", + "@babel/preset-typescript": "7.12.1", + "@babel/runtime": "7.12.1", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/plugin-proposal-numeric-separator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.1.tgz", + "integrity": "sha512-MR7Ok+Af3OhNTCxYVjJZHS0t97ydnJZt/DbR4WISO39iDnhiD8XHrY12xuSJ90FFEGjir0Fzyyn7g/zY6hxbxA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz", + "integrity": "sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/preset-env": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.1.tgz", + "integrity": "sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg==", + "requires": { + "@babel/compat-data": "^7.12.1", + "@babel/helper-compilation-targets": "^7.12.1", + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-option": "^7.12.1", + "@babel/plugin-proposal-async-generator-functions": "^7.12.1", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-dynamic-import": "^7.12.1", + "@babel/plugin-proposal-export-namespace-from": "^7.12.1", + "@babel/plugin-proposal-json-strings": "^7.12.1", + "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.1", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.1", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.12.1", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-async-to-generator": "^7.12.1", + "@babel/plugin-transform-block-scoped-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-computed-properties": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-dotall-regex": "^7.12.1", + "@babel/plugin-transform-duplicate-keys": "^7.12.1", + "@babel/plugin-transform-exponentiation-operator": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-function-name": "^7.12.1", + "@babel/plugin-transform-literals": "^7.12.1", + "@babel/plugin-transform-member-expression-literals": "^7.12.1", + "@babel/plugin-transform-modules-amd": "^7.12.1", + "@babel/plugin-transform-modules-commonjs": "^7.12.1", + "@babel/plugin-transform-modules-systemjs": "^7.12.1", + "@babel/plugin-transform-modules-umd": "^7.12.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", + "@babel/plugin-transform-new-target": "^7.12.1", + "@babel/plugin-transform-object-super": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-property-literals": "^7.12.1", + "@babel/plugin-transform-regenerator": "^7.12.1", + "@babel/plugin-transform-reserved-words": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-sticky-regex": "^7.12.1", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.1", + "@babel/plugin-transform-unicode-escapes": "^7.12.1", + "@babel/plugin-transform-unicode-regex": "^7.12.1", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.12.1", + "core-js-compat": "^3.6.2", + "semver": "^5.5.0" + } + }, + "@babel/preset-react": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.1.tgz", + "integrity": "sha512-euCExymHCi0qB9u5fKw7rvlw7AZSjw/NaB9h7EkdTt5+yHRrXdiRTh7fkG3uBPpJg82CqLfp1LHLqWGSCrab+g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-react-display-name": "^7.12.1", + "@babel/plugin-transform-react-jsx": "^7.12.1", + "@babel/plugin-transform-react-jsx-development": "^7.12.1", + "@babel/plugin-transform-react-jsx-self": "^7.12.1", + "@babel/plugin-transform-react-jsx-source": "^7.12.1", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + } + }, + "@babel/runtime": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz", + "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==", + "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==" + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bfj": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", + "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "requires": { + "bluebird": "^3.5.5", + "check-types": "^11.1.1", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "optional": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bn.js": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "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==" + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.15.0.tgz", + "integrity": "sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ==", + "requires": { + "caniuse-lite": "^1.0.30001164", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.612", + "escalade": "^3.1.1", + "node-releases": "^1.1.67" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "cacache": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz", + "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==", + "requires": { + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.0", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + } + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001164", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001164.tgz", + "integrity": "sha512-G+A/tkf4bu0dSp9+duNiXc7bGds35DioCyC6vgK2m/rjA4Krpy5WeZgZyfH2f0wj2kI6yAWWucyap6oOwmY1mg==" + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "requires": { + "rsvp": "^4.8.4" + } + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz", + "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==" + }, + "check-types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", + "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==" + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "optional": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "optional": true + } + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cjs-module-lexer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==" + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "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": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", + "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.4" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz", + "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "requires": { + "arity-n": "^1.0.4" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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==" + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "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==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.0.tgz", + "integrity": "sha512-W2VYNB0nwQQE7tKS7HzXd7r2y/y2SVJl4ga6oH/dnaLFzM0o2lB2P3zCkWj5Wc/zyMYjtgd5Hmhk0ObkQFZOIA==" + }, + "core-js-compat": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.0.tgz", + "integrity": "sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ==", + "requires": { + "browserslist": "^4.14.7", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, + "core-js-pure": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.0.tgz", + "integrity": "sha512-fRjhg3NeouotRoIV0L1FdchA6CK7ZD+lyINyMoz19SyV+ROpC4noS1xItWHFtwZdlqfMfVPJEyEGdfri2bD1pA==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "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==" + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "requires": { + "inherits": "^2.0.3", + "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": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-has-pseudo": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", + "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^5.0.0-rc.4" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "css-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz", + "integrity": "sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==", + "requires": { + "camelcase": "^6.0.0", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^2.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.3", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.1", + "semver": "^7.3.2" + } + }, + "css-prefers-color-scheme": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", + "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" + }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" + }, + "cssdb": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", + "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + } + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=" + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=" + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + }, + "dependencies": { + "css-tree": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", + "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } + }, + "csstype": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", + "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decimal.js": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=" + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "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", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-accessibility-api": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.3.0.tgz", + "integrity": "sha512-PzwHEmsRP3IGY4gv/Ug+rMeaTIyTJvadCb+ujYXYeIylbHJezIyNToe8KfEgHTCEYyC+/bUghYOGg8yMGlZ6vA==" + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } + } + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" + }, + "electron-to-chromium": { + "version": "1.3.613", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.613.tgz", + "integrity": "sha512-c3gkahddiUalk7HLhTC7PsKzPZmovYFtgh+g3rZJ+dGokk4n4dzEoOBnoV8VU8ptvnGJMhrjM/lyXKSltqf2hQ==" + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "emittery": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "requires": { + "stackframe": "^1.1.1" + } + }, + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "eslint": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.14.0.tgz", + "integrity": "sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-react-app": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz", + "integrity": "sha512-bpoAAC+YRfzq0dsTk+6v9aHm/uqnDwayNAXleMypGl6CpxI9oXXscVHo4fk3eJPIn+rsbtNetB4r/ZIidFIE8A==", + "requires": { + "confusing-browser-globals": "^1.0.10" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "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" + } + } + } + }, + "eslint-plugin-flowtype": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.2.0.tgz", + "integrity": "sha512-z7ULdTxuhlRJcEe1MVljePXricuPOrsWfScRXFhNzVD5dmTHWjIF57AxD0e7AbEoLSbjSsaA5S+hCg43WvpXJQ==", + "requires": { + "lodash": "^4.17.15", + "string-natural-compare": "^3.0.1" + } + }, + "eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.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" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "eslint-plugin-jest": { + "version": "24.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz", + "integrity": "sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg==", + "requires": { + "@typescript-eslint/experimental-utils": "^4.0.1" + } + }, + "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==", + "requires": { + "@babel/runtime": "^7.11.2", + "aria-query": "^4.2.2", + "array-includes": "^3.1.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.0.2", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.6", + "emoji-regex": "^9.0.0", + "has": "^1.0.3", + "jsx-ast-utils": "^3.1.0", + "language-tags": "^1.0.5" + }, + "dependencies": { + "emoji-regex": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.0.tgz", + "integrity": "sha512-DNc3KFPK18bPdElMJnf/Pkv5TXhxFU3YFDEuGLDRtPmV4rkmCjBkCSEp22u6rBHdSN9Vlp/GK7k98prmE1Jgug==" + } + } + }, + "eslint-plugin-react": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", + "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", + "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==" + }, + "eslint-plugin-testing-library": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.1.tgz", + "integrity": "sha512-nQIFe2muIFv2oR2zIuXE4vTbcFNx8hZKRzgHZqJg8rfopIWwoTwtlbCCNELT/jXzVe1uZF68ALGYoDXjLczKiQ==", + "requires": { + "@typescript-eslint/experimental-utils": "^3.10.1" + }, + "dependencies": { + "@typescript-eslint/experimental-utils": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz", + "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==", + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/typescript-estree": "3.10.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/types": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz", + "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==" + }, + "@typescript-eslint/typescript-estree": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz", + "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==", + "requires": { + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/visitor-keys": "3.10.1", + "debug": "^4.1.1", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz", + "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==" + }, + "eslint-webpack-plugin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-2.4.1.tgz", + "integrity": "sha512-cj8iPWZKuAiVD8MMgTSunyMCAvxQxp5mxoPHZl1UMGkApFXaXJHdCFcCR+oZEJbBNhReNa5SjESIn34uqUbBtg==", + "requires": { + "@types/eslint": "^7.2.4", + "arrify": "^2.0.1", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exec-sh": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==" + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "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" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "expect": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "requires": { + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fastq": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", + "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "requires": { + "bser": "2.1.1" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-loader": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.1.1.tgz", + "integrity": "sha512-Klt8C4BjWSXYQAfhpYYkG4qHNTna4toMHEbWrI5IuVoxbU6uiDKeKAP99R8mmbJi3lvewn/jQBOgU4+NS3tDQw==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "filesize": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", + "integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" + }, + "flatten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", + "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==" + }, + "flexboxgrid2": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/flexboxgrid2/-/flexboxgrid2-7.2.1.tgz", + "integrity": "sha512-O2bO5ZcBXnFy7cYmyt/CKb6CuwzNuUPxWJt8WOiaot8SetE9zyUahXGTSpKDm3+CTYQ5YeEMPeunMdjcxKJz4w==", + "requires": { + "normalize.css": "^7.0.0" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "fork-ts-checker-webpack-plugin": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz", + "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", + "requires": { + "@babel/code-frame": "^7.5.5", + "chalk": "^2.4.1", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.2.1.tgz", + "integrity": "sha512-bTLYHSeC0UH/EFXS9KqWnXuOl/wHK5Z/d+ghd5AsFMYN7wIGkUCOJyzy88+wJKkZPGON8u4Z9f6U4FdgURE9qA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "optional": true + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "harmony-reflect": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.1.tgz", + "integrity": "sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "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==" + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" + }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==" + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-entities": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", + "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + } + }, + "html-webpack-plugin": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz", + "integrity": "sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw==", + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.15", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "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==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "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=" + } + } + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" + }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "requires": { + "postcss": "^7.0.14" + } + }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "requires": { + "harmony-reflect": "^1.4.6" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + }, + "immer": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/immer/-/immer-7.0.9.tgz", + "integrity": "sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A==" + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + } + } + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "dependencies": { + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indefinite-observable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz", + "integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==", + "requires": { + "symbol-observable": "1.2.0" + } + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "internal-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", + "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", + "requires": { + "es-abstract": "^1.17.0-next.1", + "has": "^1.0.3", + "side-channel": "^1.0.2" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" + }, + "is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" + }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-potential-custom-element-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", + "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=" + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==" + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "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==" + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "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", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.0.tgz", + "integrity": "sha512-jxTmrvuecVISvKFFhOkjsWRZV7sFqdSUAd1ajOKY+/QE/aLBVstsJ/dX8GczLzwiT6ZEwwmZqtCUHLHHQVzcfA==", + "requires": { + "@jest/core": "^26.6.0", + "import-local": "^3.0.2", + "jest-cli": "^26.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-cli": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "requires": { + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-changed-files": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "requires": { + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "jest-circus": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-26.6.0.tgz", + "integrity": "sha512-L2/Y9szN6FJPWFK8kzWXwfp+FOR7xq0cUL4lIsdbIdwz3Vh6P1nrpcqOleSzr28zOtSHQNV9Z7Tl+KkuK7t5Ng==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.0", + "@jest/test-result": "^26.6.0", + "@jest/types": "^26.6.0", + "@types/babel__traverse": "^7.0.4", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^26.6.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.0", + "jest-matcher-utils": "^26.6.0", + "jest-message-util": "^26.6.0", + "jest-runner": "^26.6.0", + "jest-runtime": "^26.6.0", + "jest-snapshot": "^26.6.0", + "jest-util": "^26.6.0", + "pretty-format": "^26.6.0", + "stack-utils": "^2.0.2", + "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-config": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^26.6.3", + "@jest/types": "^26.6.2", + "babel-jest": "^26.6.3", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-environment-jsdom": "^26.6.2", + "jest-environment-node": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-jasmine2": "^26.6.3", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-docblock": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-environment-jsdom": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", + "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "requires": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2", + "jsdom": "^16.4.0" + } + }, + "jest-environment-node": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "requires": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + } + }, + "jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==" + }, + "jest-haste-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "requires": { + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.1.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", + "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^26.6.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2", + "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-leak-detector": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "requires": { + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + } + }, + "jest-matcher-utils": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-message-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-mock": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==" + }, + "jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==" + }, + "jest-resolve": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.0.tgz", + "integrity": "sha512-tRAz2bwraHufNp+CCmAD8ciyCpXCs1NQxB5EJAmtCFy6BN81loFEGWKzYu26Y62lAJJe4X4jg36Kf+NsQyiStQ==", + "requires": { + "@jest/types": "^26.6.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.0", + "read-pkg-up": "^7.0.1", + "resolve": "^1.17.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "requires": { + "@jest/types": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-snapshot": "^26.6.2" + } + }, + "jest-runner": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.7.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-docblock": "^26.0.0", + "jest-haste-map": "^26.6.2", + "jest-leak-detector": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-runtime": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "requires": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/globals": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^0.6.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^15.4.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-serializer": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.0.0", + "chalk": "^4.0.0", + "expect": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-haste-map": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "natural-compare": "^1.4.0", + "pretty-format": "^26.6.2", + "semver": "^7.3.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest-resolve": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-util": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "requires": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-validate": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "requires": { + "@jest/types": "^26.6.2", + "camelcase": "^6.0.0", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "leven": "^3.1.0", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watch-typeahead": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.6.1.tgz", + "integrity": "sha512-ITVnHhj3Jd/QkqQcTqZfRgjfyRhDFM/auzgVo2RKvSwi18YMvh0WvXDJFoFED6c7jd/5jxtu4kSOb9PTu2cPVg==", + "requires": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^26.0.0", + "jest-watcher": "^26.3.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watcher": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "requires": { + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^26.6.2", + "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "jsdom": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", + "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "requires": { + "abab": "^2.0.3", + "acorn": "^7.1.1", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.2.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.0", + "domexception": "^2.0.1", + "escodegen": "^1.14.1", + "html-encoding-sniffer": "^2.0.1", + "is-potential-custom-element-name": "^1.0.0", + "nwsapi": "^2.2.0", + "parse5": "5.1.1", + "request": "^2.88.2", + "request-promise-native": "^1.0.8", + "saxes": "^5.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^3.0.1", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0", + "ws": "^7.2.3", + "xml-name-validator": "^3.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jss": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.5.0.tgz", + "integrity": "sha512-B6151NvG+thUg3murLNHRPLxTLwQ13ep4SH5brj4d8qKtogOx/jupnpfkPGSHPqvcwKJaCLctpj2lEk+5yGwMw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "indefinite-observable": "^2.0.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.5.0.tgz", + "integrity": "sha512-GSjPL0adGAkuoqeYiXTgO7PlIrmjv5v8lA6TTBdfxbNYpxADOdGKJgIEkffhlyuIZHlPuuiFYTwUreLUmSn7rg==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.5.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.5.0.tgz", + "integrity": "sha512-rsbTtZGCMrbcb9beiDd+TwL991NGmsAgVYH0hATrYJtue9e+LH/Gn4yFD1ENwE+3JzF3A+rPnM2JuD9L/SIIWw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0" + } + }, + "jss-plugin-global": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.5.0.tgz", + "integrity": "sha512-FZd9+JE/3D7HMefEG54fEC0XiQ9rhGtDHAT/ols24y8sKQ1D5KIw6OyXEmIdKFmACgxZV2ARQ5pAUypxkk2IFQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0" + } + }, + "jss-plugin-nested": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.5.0.tgz", + "integrity": "sha512-ejPlCLNlEGgx8jmMiDk/zarsCZk+DV0YqXfddpgzbO9Toamo0HweCFuwJ3ZO40UFOfqKwfpKMVH/3HUXgxkTMg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.5.0.tgz", + "integrity": "sha512-kTLRvrOetFKz5vM88FAhLNeJIxfjhCepnvq65G7xsAQ/Wgy7HwO1BS/2wE5mx8iLaAWC6Rj5h16mhMk9sKdZxg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.5.0.tgz", + "integrity": "sha512-jXINGr8BSsB13JVuK274oEtk0LoooYSJqTBCGeBu2cG/VJ3+4FPs1gwLgsq24xTgKshtZ+WEQMVL34OprLidRA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.5.0.tgz", + "integrity": "sha512-rux3gmfwDdOKCLDx0IQjTwTm03IfBa+Rm/hs747cOw5Q7O3RaTUIMPKjtVfc31Xr/XI9Abz2XEupk1/oMQ7zRA==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.5.0" + } + }, + "jsx-ast-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz", + "integrity": "sha512-d4/UOjg+mxAWxCiF0c5UTSwyqbchkbqCvK87aBovhnh8GtysTjWmgC63tY0cJx/HzGgm9qnA147jVBdpOiQ2RA==", + "requires": { + "array-includes": "^3.1.1", + "object.assign": "^4.1.1" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "language-subtag-registry": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", + "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==" + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "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=" + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "requires": { + "tmpl": "1.0.x" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "microevent.ts": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", + "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" + }, + "mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "requires": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + } + }, + "mini-css-extract-plugin": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz", + "integrity": "sha512-n9BA8LonkOkW1/zn+IbLPQmovsL0wMb9yx75fMJQZf2X1Zoec9yTZtyMePcyu19wPkmFbzZZA6fLTotpFhQsOA==", + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "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==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "native-url": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/native-url/-/native-url-0.2.6.tgz", + "integrity": "sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA==", + "requires": { + "querystring": "^0.2.0" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + } + } + }, + "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": "8.0.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz", + "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", + "optional": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-releases": { + "version": "1.1.67", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", + "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "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": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "normalize.css": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-7.0.0.tgz", + "integrity": "sha1-q/sd2CRwZ04DIrU86xqvQSk45L8=" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" + }, + "object-is": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", + "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", + "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.3.tgz", + "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", + "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", + "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz", + "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==", + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + } + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz", + "integrity": "sha512-wqd6FdI2a5/FdoiCNNkEvLeA//lHHfG24Ln2Xm2qqdIk4aOlsR18jwpyOihqQ8849W3qu2DX8fOYxpvTMj+93A==", + "requires": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "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" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "pnp-webpack-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", + "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", + "requires": { + "ts-pnp": "^1.1.6" + } + }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.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==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-attribute-case-insensitive": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", + "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^6.0.2" + } + }, + "postcss-browser-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz", + "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==", + "requires": { + "postcss": "^7" + } + }, + "postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "requires": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "postcss-color-functional-notation": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", + "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-gray": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", + "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-hex-alpha": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", + "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", + "requires": { + "postcss": "^7.0.14", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-color-mod-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", + "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", + "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-custom-media": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", + "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", + "requires": { + "postcss": "^7.0.14" + } + }, + "postcss-custom-properties": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", + "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", + "requires": { + "postcss": "^7.0.17", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-custom-selectors": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", + "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-dir-pseudo-class": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", + "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-double-position-gradients": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", + "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", + "requires": { + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-env-function": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", + "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-flexbugs-fixes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz", + "integrity": "sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==", + "requires": { + "postcss": "^7.0.26" + } + }, + "postcss-focus-visible": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", + "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-focus-within": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", + "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-font-variant": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", + "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-gap-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", + "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-image-set-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", + "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-initial": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.2.tgz", + "integrity": "sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA==", + "requires": { + "lodash.template": "^4.5.0", + "postcss": "^7.0.2" + } + }, + "postcss-lab-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", + "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + } + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "postcss-logical": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", + "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-media-minmax": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", + "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "postcss-nesting": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", + "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-normalize": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-8.0.1.tgz", + "integrity": "sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ==", + "requires": { + "@csstools/normalize.css": "^10.1.0", + "browserslist": "^4.6.2", + "postcss": "^7.0.17", + "postcss-browser-comments": "^3.0.0", + "sanitize.css": "^10.0.0" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-overflow-shorthand": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", + "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-page-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", + "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-place": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", + "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-preset-env": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", + "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", + "requires": { + "autoprefixer": "^9.6.1", + "browserslist": "^4.6.4", + "caniuse-lite": "^1.0.30000981", + "css-blank-pseudo": "^0.1.4", + "css-has-pseudo": "^0.10.0", + "css-prefers-color-scheme": "^3.1.1", + "cssdb": "^4.4.0", + "postcss": "^7.0.17", + "postcss-attribute-case-insensitive": "^4.0.1", + "postcss-color-functional-notation": "^2.0.1", + "postcss-color-gray": "^5.0.0", + "postcss-color-hex-alpha": "^5.0.3", + "postcss-color-mod-function": "^3.0.3", + "postcss-color-rebeccapurple": "^4.0.1", + "postcss-custom-media": "^7.0.8", + "postcss-custom-properties": "^8.0.11", + "postcss-custom-selectors": "^5.1.2", + "postcss-dir-pseudo-class": "^5.0.0", + "postcss-double-position-gradients": "^1.0.0", + "postcss-env-function": "^2.0.2", + "postcss-focus-visible": "^4.0.0", + "postcss-focus-within": "^3.0.0", + "postcss-font-variant": "^4.0.0", + "postcss-gap-properties": "^2.0.0", + "postcss-image-set-function": "^3.0.1", + "postcss-initial": "^3.0.0", + "postcss-lab-function": "^2.0.1", + "postcss-logical": "^3.0.0", + "postcss-media-minmax": "^4.0.0", + "postcss-nesting": "^7.0.0", + "postcss-overflow-shorthand": "^2.0.0", + "postcss-page-break": "^2.0.0", + "postcss-place": "^4.0.1", + "postcss-pseudo-class-any-link": "^6.0.0", + "postcss-replace-overflow-wrap": "^3.0.0", + "postcss-selector-matches": "^4.0.0", + "postcss-selector-not": "^4.0.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", + "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-replace-overflow-wrap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", + "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-safe-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-5.0.2.tgz", + "integrity": "sha512-jDUfCPJbKOABhwpUKcqCVbbXiloe/QXMcbJ6Iipf3sDIihEzTqRCeMBfRaOHxhBuTYqtASrI1KJWxzztZU4qUQ==", + "requires": { + "postcss": "^8.1.0" + }, + "dependencies": { + "postcss": { + "version": "8.1.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.1.10.tgz", + "integrity": "sha512-iBXEV5VTTYaRRdxiFYzTtuv2lGMQBExqkZKSzkJe+Fl6rvQrA/49UVGKqB+LG54hpW/TtDBMGds8j33GFNW7pg==", + "requires": { + "colorette": "^1.2.1", + "nanoid": "^3.1.18", + "source-map": "^0.6.1", + "vfile-location": "^3.2.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "postcss-selector-matches": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", + "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-not": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz", + "integrity": "sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ==", + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-parser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "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==" + }, + "postcss-values-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", + "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "pretty-bytes": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz", + "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==" + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "react-is": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", + "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==" + } + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "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==", + "requires": { + "asap": "~2.0.6" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "prompts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "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==" + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "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==" + } + } + }, + "react": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", + "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-app-polyfill": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz", + "integrity": "sha512-0sF4ny9v/B7s6aoehwze9vJNWcmCemAUYBVasscVr92+UYiEqDXOxfKjXN685mDaMRNF3WdhHQs76oTODMocFA==", + "requires": { + "core-js": "^3.6.5", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "whatwg-fetch": "^3.4.1" + } + }, + "react-dev-utils": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.1.tgz", + "integrity": "sha512-rlgpCupaW6qQqvu0hvv2FDv40QG427fjghV56XyPcP5aKtOAPzNAhQ7bHqk1YdS2vpW1W7aSV3JobedxuPlBAA==", + "requires": { + "@babel/code-frame": "7.10.4", + "address": "1.1.2", + "browserslist": "4.14.2", + "chalk": "2.4.2", + "cross-spawn": "7.0.3", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.1.0", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "4.1.6", + "global-modules": "2.0.0", + "globby": "11.0.1", + "gzip-size": "5.1.1", + "immer": "7.0.9", + "is-root": "2.1.0", + "loader-utils": "2.0.0", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "prompts": "2.4.0", + "react-error-overlay": "^6.0.8", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "dependencies": { + "browserslist": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz", + "integrity": "sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==", + "requires": { + "caniuse-lite": "^1.0.30001125", + "electron-to-chromium": "^1.3.564", + "escalade": "^3.0.2", + "node-releases": "^1.1.61" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "react-dom": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz", + "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.1" + } + }, + "react-error-overlay": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.8.tgz", + "integrity": "sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw==" + }, + "react-flexbox-grid": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/react-flexbox-grid/-/react-flexbox-grid-2.1.2.tgz", + "integrity": "sha512-lj1oVnIJ7TY3W6tPjFUxlUYd1DLFxEg8RiX3HAYVvreE3O9HU9n2390CFoPQ+qk1E+5MXa2t/mLMafFLAa8+7Q==", + "requires": { + "flexboxgrid2": "^7.2.0", + "prop-types": "^15.5.8" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-redux": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz", + "integrity": "sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA==", + "requires": { + "@babel/runtime": "^7.12.1", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + } + }, + "react-refresh": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", + "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" + }, + "react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-scripts": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.1.tgz", + "integrity": "sha512-NnniMSC/wjwhcJAyPJCWtxx6CWONqgvGgV9+QXj1bwoW/JI++YF1eEf3Upf/mQ9KmP57IBdjzWs1XvnPq7qMTQ==", + "requires": { + "@babel/core": "7.12.3", + "@pmmmwh/react-refresh-webpack-plugin": "0.4.2", + "@svgr/webpack": "5.4.0", + "@typescript-eslint/eslint-plugin": "^4.5.0", + "@typescript-eslint/parser": "^4.5.0", + "babel-eslint": "^10.1.0", + "babel-jest": "^26.6.0", + "babel-loader": "8.1.0", + "babel-plugin-named-asset-import": "^0.3.7", + "babel-preset-react-app": "^10.0.0", + "bfj": "^7.0.2", + "camelcase": "^6.1.0", + "case-sensitive-paths-webpack-plugin": "2.3.0", + "css-loader": "4.3.0", + "dotenv": "8.2.0", + "dotenv-expand": "5.1.0", + "eslint": "^7.11.0", + "eslint-config-react-app": "^6.0.0", + "eslint-plugin-flowtype": "^5.2.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jest": "^24.1.0", + "eslint-plugin-jsx-a11y": "^6.3.1", + "eslint-plugin-react": "^7.21.5", + "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-testing-library": "^3.9.2", + "eslint-webpack-plugin": "^2.1.0", + "file-loader": "6.1.1", + "fs-extra": "^9.0.1", + "fsevents": "^2.1.3", + "html-webpack-plugin": "4.5.0", + "identity-obj-proxy": "3.0.0", + "jest": "26.6.0", + "jest-circus": "26.6.0", + "jest-resolve": "26.6.0", + "jest-watch-typeahead": "0.6.1", + "mini-css-extract-plugin": "0.11.3", + "optimize-css-assets-webpack-plugin": "5.0.4", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "4.2.1", + "postcss-loader": "3.0.0", + "postcss-normalize": "8.0.1", + "postcss-preset-env": "6.7.0", + "postcss-safe-parser": "5.0.2", + "prompts": "2.4.0", + "react-app-polyfill": "^2.0.0", + "react-dev-utils": "^11.0.1", + "react-refresh": "^0.8.3", + "resolve": "1.18.1", + "resolve-url-loader": "^3.1.2", + "sass-loader": "8.0.2", + "semver": "7.3.2", + "style-loader": "1.3.0", + "terser-webpack-plugin": "4.2.3", + "ts-pnp": "1.2.0", + "url-loader": "4.1.1", + "webpack": "4.44.2", + "webpack-dev-server": "3.11.0", + "webpack-manifest-plugin": "2.2.0", + "workbox-webpack-plugin": "5.1.4" + } + }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "dependencies": { + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "requires": { + "minimatch": "3.0.4" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "redux-thunk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==" + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "renderkid": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.4.tgz", + "integrity": "sha512-K2eXrSOJdq+HuKzlcjOlGoOarUu5SDguDEhE7+Ah4zuOWL40j8A/oHvLlLob9PSTNvVnBd+/q0Er1QfpEuem5g==", + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "reselect": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", + "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + }, + "resolve": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", + "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "requires": { + "is-core-module": "^2.0.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "resolve-url-loader": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz", + "integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==", + "requires": { + "adjust-sourcemap-loader": "3.0.0", + "camelcase": "5.3.1", + "compose-function": "3.0.3", + "convert-source-map": "1.7.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.21", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "postcss": { + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", + "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "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", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "requires": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + }, + "dependencies": { + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=" + } + } + }, + "rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=" + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rollup": { + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", + "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==", + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "rollup-plugin-babel": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz", + "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-terser": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz", + "integrity": "sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w==", + "requires": { + "@babel/code-frame": "^7.5.5", + "jest-worker": "^24.9.0", + "rollup-pluginutils": "^2.8.2", + "serialize-javascript": "^4.0.0", + "terser": "^4.6.2" + }, + "dependencies": { + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "requires": { + "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" + } + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" + }, + "run-parallel": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", + "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==" + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "sanitize.css": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz", + "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg==" + }, + "sass-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.6.1", + "semver": "^6.3.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, + "scheduler": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz", + "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "selfsigned": { + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.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" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "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==" + } + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "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==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "optional": true + }, + "side-channel": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.3.tgz", + "integrity": "sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==", + "requires": { + "es-abstract": "^1.18.0-next.0", + "object-inspect": "^1.8.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "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" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sockjs": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz", + "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==", + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.4.0", + "websocket-driver": "0.6.5" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "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": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz", + "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==", + "requires": { + "minipass": "^3.1.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, + "stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string-length": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", + "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string.prototype.matchall": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz", + "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3" + } + }, + "string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "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==" + } + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "requires": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "requires": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", + "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "tar": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", + "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=" + }, + "tempy": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.3.0.tgz", + "integrity": "sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ==", + "requires": { + "temp-dir": "^1.0.0", + "type-fest": "^0.3.1", + "unique-string": "^1.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==" + } + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "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": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz", + "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==", + "requires": { + "cacache": "^15.0.5", + "find-cache-dir": "^3.3.1", + "jest-worker": "^26.5.0", + "p-limit": "^3.0.2", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", + "source-map": "^0.6.1", + "terser": "^5.3.4", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "terser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", + "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" + }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "requires": { + "punycode": "^2.1.1" + } + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, + "ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", + "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==" + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", + "optional": true + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==" + }, + "v8-to-istanbul": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz", + "integrity": "sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vfile-location": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", + "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "wait-for-expect": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", + "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==" + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "requires": { + "makeerror": "1.0.x" + } + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" + }, + "webpack": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", + "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.3.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + } + } + }, + "webpack-dev-server": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz", + "integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==", + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.20", + "sockjs-client": "1.4.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "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", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "webpack-manifest-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz", + "integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==", + "requires": { + "fs-extra": "^7.0.0", + "lodash": ">=3.5 <5", + "object.entries": "^1.1.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "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": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "requires": { + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz", + "integrity": "sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A==" + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", + "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^2.0.2", + "webidl-conversions": "^6.1.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "workbox-background-sync": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-5.1.4.tgz", + "integrity": "sha512-AH6x5pYq4vwQvfRDWH+vfOePfPIYQ00nCEB7dJRU1e0n9+9HMRyvI63FlDvtFT2AvXVRsXvUt7DNMEToyJLpSA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-broadcast-update": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-5.1.4.tgz", + "integrity": "sha512-HTyTWkqXvHRuqY73XrwvXPud/FN6x3ROzkfFPsRjtw/kGZuZkPzfeH531qdUGfhtwjmtO/ZzXcWErqVzJNdXaA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-build": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-5.1.4.tgz", + "integrity": "sha512-xUcZn6SYU8usjOlfLb9Y2/f86Gdo+fy1fXgH8tJHjxgpo53VVsqRX0lUDw8/JuyzNmXuo8vXX14pXX2oIm9Bow==", + "requires": { + "@babel/core": "^7.8.4", + "@babel/preset-env": "^7.8.4", + "@babel/runtime": "^7.8.4", + "@hapi/joi": "^15.1.0", + "@rollup/plugin-node-resolve": "^7.1.1", + "@rollup/plugin-replace": "^2.3.1", + "@surma/rollup-plugin-off-main-thread": "^1.1.1", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^8.1.0", + "glob": "^7.1.6", + "lodash.template": "^4.5.0", + "pretty-bytes": "^5.3.0", + "rollup": "^1.31.1", + "rollup-plugin-babel": "^4.3.3", + "rollup-plugin-terser": "^5.3.1", + "source-map": "^0.7.3", + "source-map-url": "^0.4.0", + "stringify-object": "^3.3.0", + "strip-comments": "^1.0.2", + "tempy": "^0.3.0", + "upath": "^1.2.0", + "workbox-background-sync": "^5.1.4", + "workbox-broadcast-update": "^5.1.4", + "workbox-cacheable-response": "^5.1.4", + "workbox-core": "^5.1.4", + "workbox-expiration": "^5.1.4", + "workbox-google-analytics": "^5.1.4", + "workbox-navigation-preload": "^5.1.4", + "workbox-precaching": "^5.1.4", + "workbox-range-requests": "^5.1.4", + "workbox-routing": "^5.1.4", + "workbox-strategies": "^5.1.4", + "workbox-streams": "^5.1.4", + "workbox-sw": "^5.1.4", + "workbox-window": "^5.1.4" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } + }, + "workbox-cacheable-response": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-5.1.4.tgz", + "integrity": "sha512-0bfvMZs0Of1S5cdswfQK0BXt6ulU5kVD4lwer2CeI+03czHprXR3V4Y8lPTooamn7eHP8Iywi5QjyAMjw0qauA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-core": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-5.1.4.tgz", + "integrity": "sha512-+4iRQan/1D8I81nR2L5vcbaaFskZC2CL17TLbvWVzQ4qiF/ytOGF6XeV54pVxAvKUtkLANhk8TyIUMtiMw2oDg==" + }, + "workbox-expiration": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-5.1.4.tgz", + "integrity": "sha512-oDO/5iC65h2Eq7jctAv858W2+CeRW5e0jZBMNRXpzp0ZPvuT6GblUiHnAsC5W5lANs1QS9atVOm4ifrBiYY7AQ==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-google-analytics": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-5.1.4.tgz", + "integrity": "sha512-0IFhKoEVrreHpKgcOoddV+oIaVXBFKXUzJVBI+nb0bxmcwYuZMdteBTp8AEDJacENtc9xbR0wa9RDCnYsCDLjA==", + "requires": { + "workbox-background-sync": "^5.1.4", + "workbox-core": "^5.1.4", + "workbox-routing": "^5.1.4", + "workbox-strategies": "^5.1.4" + } + }, + "workbox-navigation-preload": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-5.1.4.tgz", + "integrity": "sha512-Wf03osvK0wTflAfKXba//QmWC5BIaIZARU03JIhAEO2wSB2BDROWI8Q/zmianf54kdV7e1eLaIEZhth4K4MyfQ==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-precaching": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-5.1.4.tgz", + "integrity": "sha512-gCIFrBXmVQLFwvAzuGLCmkUYGVhBb7D1k/IL7pUJUO5xacjLcFUaLnnsoVepBGAiKw34HU1y/YuqvTKim9qAZA==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-range-requests": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-5.1.4.tgz", + "integrity": "sha512-1HSujLjgTeoxHrMR2muDW2dKdxqCGMc1KbeyGcmjZZAizJTFwu7CWLDmLv6O1ceWYrhfuLFJO+umYMddk2XMhw==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-routing": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-5.1.4.tgz", + "integrity": "sha512-8ljknRfqE1vEQtnMtzfksL+UXO822jJlHTIR7+BtJuxQ17+WPZfsHqvk1ynR/v0EHik4x2+826Hkwpgh4GKDCw==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "workbox-strategies": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-5.1.4.tgz", + "integrity": "sha512-VVS57LpaJTdjW3RgZvPwX0NlhNmscR7OQ9bP+N/34cYMDzXLyA6kqWffP6QKXSkca1OFo/v6v7hW7zrrguo6EA==", + "requires": { + "workbox-core": "^5.1.4", + "workbox-routing": "^5.1.4" + } + }, + "workbox-streams": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-5.1.4.tgz", + "integrity": "sha512-xU8yuF1hI/XcVhJUAfbQLa1guQUhdLMPQJkdT0kn6HP5CwiPOGiXnSFq80rAG4b1kJUChQQIGPrq439FQUNVrw==", + "requires": { + "workbox-core": "^5.1.4", + "workbox-routing": "^5.1.4" + } + }, + "workbox-sw": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-5.1.4.tgz", + "integrity": "sha512-9xKnKw95aXwSNc8kk8gki4HU0g0W6KXu+xks7wFuC7h0sembFnTrKtckqZxbSod41TDaGh+gWUA5IRXrL0ECRA==" + }, + "workbox-webpack-plugin": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-5.1.4.tgz", + "integrity": "sha512-PZafF4HpugZndqISi3rZ4ZK4A4DxO8rAqt2FwRptgsDx7NF8TVKP86/huHquUsRjMGQllsNdn4FNl8CD/UvKmQ==", + "requires": { + "@babel/runtime": "^7.5.5", + "fast-json-stable-stringify": "^2.0.0", + "source-map-url": "^0.4.0", + "upath": "^1.1.2", + "webpack-sources": "^1.3.0", + "workbox-build": "^5.1.4" + } + }, + "workbox-window": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-5.1.4.tgz", + "integrity": "sha512-vXQtgTeMCUq/4pBWMfQX8Ee7N2wVC4Q7XYFqLnfbXJ2hqew/cU1uMTD2KqGEgEpE4/30luxIxgE+LkIa8glBYw==", + "requires": { + "workbox-core": "^5.1.4" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "requires": { + "errno": "~0.1.7" + } + }, + "worker-rpc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", + "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", + "requires": { + "microevent.ts": "~0.1.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz", + "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==" + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/.internal/wui/package.json b/.internal/wui/package.json new file mode 100644 index 000000000..186af0658 --- /dev/null +++ b/.internal/wui/package.json @@ -0,0 +1,41 @@ +{ + "name": "iotstack_wui", + "version": "0.0.1", + "private": true, + "dependencies": { + "@material-ui/core": "^4.11.2", + "@material-ui/icons": "^4.11.2", + "@material-ui/lab": "^4.0.0-alpha.57", + "@reduxjs/toolkit": "^1.5.0", + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.5.0", + "@testing-library/user-event": "^7.2.1", + "react": "^17.0.1", + "react-dom": "^17.0.1", + "react-flexbox-grid": "^2.1.2", + "react-redux": "^7.2.2", + "react-router-dom": "^5.2.0", + "react-scripts": "4.0.1" + }, + "scripts": { + "start": "set PORT=32777 && react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/.internal/wui/public/favicon.ico b/.internal/wui/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..354202a4e6baec3429e928e13d54144f8eebb62c GIT binary patch literal 3585 zcmV+c4*v0pP)% zYj70TmB)YGJu{l8G&7P0y@k*V1m-0hzpzcfG0wwaleL{kZM?26$JyQNZlx+8cWb>> zo2`7=N2;><c;ao%at1QB#J?`vP`$f4hp!I|FG) zQ`ZH3?UNk&uWNL-h71E`_}X98@Zi33ELJ(&rjpebbxrWe`vaVPtJ~~+X^n>${&gF7 zf3p|jCW6t~5*m>dy zb>tU2k>#Z?YlWpwo_Mj&bo=O}%KN|RLQ|IzL^DKI3Hb165B(isV9Ir$uc2zA_m0{s zS?A&L=c-Yx264fw<20YSNw#Nf)(99Gi1BIDP4l{TtDlB@3zpU9hItY7Z6l+0j-u?+lRRG>D9aRf3;QWTo9{WQBluROLqVOq6c8uaF!^ zc9Iu|+rqj{KJz-;t3g%>7zjp)g^kE>vC7mp`m@n20J0)cy~Q^r-oap3ghV`haUd%M zOeZY>MQdF+T-Izf3m8?Quh4GR1o4Q<#8CF)Kvw*;zkSmDe_@#mYtC$5bzRVPZGyA^ z*F#6k7#5pMxW+(d*!=s+Uw6{q9_HIW*$99n8UGksfRPn4r3?7iIN1CBb%ZBUgofkz z);N}HwuxmE5S>gBkIu|Vhueaz%w&B+hx5mKXLTM7ueki-5dZkCQvldq7TjJNcBg_b zU?))FCQ$CApv1|VN;g)UjK^!kJ`|_DWt=ldx~Xf-r*Tga zb=&f1dD@*~*#t107+8 z`=f+L5=16aW@QNL{XeYd#h-1bcH2zK-P<Rt(qx>zc_F%CYO~s=cy={{Vwv#PXZt(KVj~m#& zyU5fECx#Qe@r%zG?u{;4I9U<_siekxuXWIT=B63Msy2ElUh4+H?zYYfH=|RHd$yxVv^K*FWN9)=3OeNA(Pe%G;9RB%LLs?z|77d+32riu- zP5P*XbHtszdn*2$B9U5~|*evB9O zfY_wU$^Y#nF_rEXSGhUxcQc&_V{X=N_2c##Y3k@;jMj@IcdXx~k{Typ>*V?$N6j)j z8Q18(7UI~i+U9Ju24%Cqvs z3w0Ef%q>PrYdq%2XemL{(H_(IOff!`pzV{v?O5EuLXt*~zOC-$%YEn0)^*Q%aIq9nszI|CFh zKmdT%rqH;1MoGTWJUS<4+={dW^h~YivLbQU1A#>imn4b2f}DBx@Wuw?oPHy?plja> zp&JJ&rpdBcB`P-LvG0fV?EUj~vjmswNZZnIUlcIP+35(s z7>4_z3!VeG*&Q`klXU3s2=nnf{Y*Pc)g~X${1ZF1s7pKD0j%5P!yA|@bV@SRHRj{YU057R#*OuVI^C9J*tWZfnk~KspP3J` z42orGRbg5JJbuINqmzbUu@tzyHugSOZO*}I)NJvm-Q(9ZLDO%$IeUv{5GZr8>*>mj zm7i2XU$SzXb_xW_U5xa_NF{XI{xmu(1x<&BdkZP6$>m1#7-~|-8?aMRpNqpi|LCWZ z8hZSHNiov*1#L~& zP|X%UuBkaY*cImd@!kcGxMd1m6ZGAfv;6LRT&+sm_{t3 z^4_mI(Nx3E{32)CBX?;DD5`Q(*)Wsee{iIW{$O}nhZKYmBw{K}N4q)rvlfC^XYzWR zU18_`avs=Menn$kJy)f+*aJVcye4vuni=$H#b%I0xc7><@ zrk=|6c}N+KP&}&g*+;{id%Ks;E92bCqsM1s&v&ZW@p#D{bzav5AHUnr$=5o~ZTi}+ zezxx^O8eZRqNt|o{Qi|2eDGGc=~f=Ujjuetmi0Rd$o1P6JP09#AQ{()PNryY8Rz1= z{q(ejW+g+4MWUqI!`Gj$p>jhWibY1(1e0S4avThjVYwRG_)} zHlF{dt&~)!KXJMwRX7?-ar~7VoIln(^Ppr%+tpiqlvaE21?;o3v`8q$a9@;xV1%x# zJAeaj^fd>Z#qfco1E(EFO=joIlpfhi~`Hk((5YgvBaz>$^0~kh5=Z zT~;J~0Xui?4A8izn1T|gxz0x?Q=EPyNYl|C(@SJo!sbx0=EzucjD5pIOk;8^K`NmW zkEmu~wpeAVHhKBx3$+BwT}uk08SM+`nz7A&;rD$se=tZYzVu^jibZ1GW*_VCDWG8w)jL~rWYy`?&R5s*MeV5PNIbO&ur;pT+4#c=}ZipMrV@!-B2#q9&M^*E9y`o4s zJXYLZD}gc>>vt5e@%}<`?CIl0RtUHqx+aK(Qu7cX;qfhRCpQt(m>f+oF_It=RZT%f zu}C=FR@`12-a`Abj?jMTKbet%E30kAD&mSPggA)tY3Y{@su1F!EJ@NK;KFKKvkJH% zNz$P&{in0j;qzVKX^hWFzsS=;#pvUH;50D%bc^^Bem?*Ihu+H91%a4J00000NkvXX Hu0mjfhdT@% literal 0 HcmV?d00001 diff --git a/.internal/wui/public/index.html b/.internal/wui/public/index.html new file mode 100644 index 000000000..430b58fa3 --- /dev/null +++ b/.internal/wui/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + React Redux App + + + +
+ + + diff --git a/.internal/wui/public/logo192.png b/.internal/wui/public/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..33624109cdc98874ea8657a2a3a7ce71c81d1837 GIT binary patch literal 4153 zcmbtY`8U*!_kX{~V1@=W)+B~T_AJ@5WX3*ZiLy^A#RySCnlN_qh%8C6RhF`)(1h%I zWC@Wn_I(h8&|vWK{0raj53hUg>z;dmd7X35z30YTTbdv^ggF2JK;TUcZH|1?e}J(a zS({OB_9F-PGj;R_0Dk@d02)>5*8l+bGTsn(={|LZU~yOYE9$^lnY3w%o`+6nV>KP# z^U$HUva$Eu@2;h!ufs>R!uum6r-l%dP!vmFZ z^-OXH#`sID8365GK%V`SS0M0yy4oS>3gtZp+o7)qTGv0|I%wx5->VcYqfjweY5g#` zD+e0%`_b2^3z&lPp8Tf3M1)?z>lHOk4*2{i5|xLa$|VUfZ3V8G{fvVWCEi(_xEJuY z4F(^RKs80zon>F+X`T@UFFZ5;5y^hdm-7$^7Typ~FepKlnmFB8g4x zQ@ZQ(GuDCx^f1#mrX|;KtX zT=t}Zas>0>*S=dS<)$U1O3dG+h4;PO=GP{UO*}c!E6nHHp}8qLLBOTq6$>j4QZ;x| zvj)$DA^-fM%Zo>*0ty2MEHp3L$S-d*FV+Vgw#681SKeoIDA6rd#z0O<5~Q-1*?E27 zejz&%G*<0O`2kISF4psgjtss@loLOmFV)2n2_-(+rt7~NPJ_}!!Bu%qlWsfLf@3kh zwP}c33gEG&vD`Kz8l>v>crujscyFMfyc2_sg(+b`**Y8sJGfhSFp~u9KYyX)|O6c;9tM$Hj*E&5sGxM)G`(LoPIq z*Quv^MF~`WN{@k}!P*OC%gNqyR8xC&5WX=-i`)gNb3J^?)NQTN`0jHGRNYyAb+g$j zIm0$ro5Ucgk3-K+g;a_vc+B+JrLgkSvRJFQ%DfUaPxz|p(Sj>Q5elBnL2EKs#~#9m z#p#2&cnh>~+hUhi$Eu@1-Z566X0i7!eu-lG2yR7x6FkN}tV8zpC7t6`?}{*gUO$ zkQ*G5*y#0&krEz9(E)JhTgouHC8PZTA9L_)LY%s!!FbKyXHsM4hITC9-_%Fq{L2jF z7WH49Bb_hPiaG?5utQYS&y=LyoXOSnt7Ao!MtoF3X@8OMRsRI$#-SwKx>+$hQA3WI zwsn; zJ$-87v~Q+ofqN~Nnl>`iJgrHG@E{S`O^R^^?f4U}k-jvx0TI^X0#%jqEabpJ3 z;|l7uuHo%Fyh^XgANJB?#P%j^4G-lRG`tw#q|@ z4Y}7O&*;s8Zb$HFroANV!appLHkC{FII zvuc}rB^+VOi-!IV{wJrELl9Gkk8TONJgPmJg<%lao{SXEgeSyk6eZOUjec6Qhs6{r z@Em{}%b5XwKDNB(m*0FnhkKPsd0qpUv-E5d7ww*GYp*)>fju`uCI;HnKe*Y_to|Vh zn2H=t$JxBkQJ+5qcoHn-g4j;*mu!o*-2SWSr7wNF5V}jvuPa=tdR_%M{ak?U#oAJP zUKo3`db4lXtItSWH1ucRK%EDVRohOZr793HB&0JaC_Jzvp5MkoO;FQ#I;K=1fbE)B zJo8{ajScs4n8W29<6FZi^MZirr~SOx?qcITv6ET4E7!kxvqngfRUt#G?di)7d2r4= z{=zq1ccG5=eY9><=W`gKYkYmd%fAjyGN2hEW4tv#-`I?L*iV!_<9g$9T7N>g>jXvK zF-TVoJCd&Hd0pdZt*f8#%}GBqoPDoAT1DJ>HhX+KoTFqrDASehr)cv=?|a)BTl?Fd zywE=4VJQxmX>j!oV&r+%JBPH>yFsqeh6g+AF6X<##qIQRQPC3Da<;m_bp9abYUt{5uqsp)*CRVA-$E8r`G=yf|Y zrHVuo_94`nTGU~hNZ@e)0-DwFzBA6d_iSdExSK@}z4f`L)nV*K9_;aVH_jIrUgyi2 zW6@|R!zMoJ^Oy~~yO1MFFel^qpn%_TEpW2%L=?R=Iet6LFw}Wjaq<0>kKWNXzA<0w z4A?IK&)K(hO>Rxnf=K6ZPfMbx2WCk*F4=$irY#0Y^B)wGeIXPYSI8osp@?)X3t@#2 zua^ZQx)5j}5ZP;?Qv!GZAdLr-)$L z@id<N6}B ziuuc}E`JpyndwJx6=1 zVz_p6AU}HhDdSjI9jW)N!qBM_PwNbVxT=pFyi7Uae z_E>}(xArymn$#A(Qfa2Pq2`v&Ql@I7T0%VVJa#4A&Fm_tK}5aplQ(N(r#AP(+T;Y% zZwWz_OcCE?wu8IHL)U(Ci0MIuVuY<^rbT?zyeq{< zOJu7vrCDAOVp-Gsl1g%NSi({)_HX6Tj%lgChvU;0akBS6fht|~ZV_QJJwYXpRTG^U zob4Wy)9ofecwnTcelhngQ-)N>a=~q{hZch^irM+qcD{46ltx(G9PsYe2RYRfzPm5C z8uQ0l>A#}G$o0+dRy4(RAVQYzi_O!oHvqNqn!+JH2|e8;M@GVTE`0cfhg&g`5ZjEEWGwrMt6$}oQI+Xh2K;(!2ZjlSQxX8|q@4&eBr&^%6aaG15x9n)X zCp1eZIdwEl9)5UH)%ADFLG z%RNQL+5Xf#Aw`zI;ACKazU7auJ$^>AgLB6_kfPb?>ueWN&chc)(UIvsdnNIwYOpw& z6~*VI65VQ$!i!sJ3-1%WkK+7T!FUMYu$^Ps_>ggVz)T<7DC9}yBrrasno#i08y&z6 z_44lY+mVPlHFD&)wungRu4Cc?VftQf9s!U4eR9?9s{C}-v{rD5`<5Bdg}JYAi8Sk2 z)S~r!omBS}46T`#J_wZgU7-=;=pmbsUvft}ElT=PNKc3ypJBvrgP~(yNXqYv%j~_zJ5_&)Rv!gsJ#!A#9 zCEA3Xg3oO&rQf7UM|>ZQDI~Q{B(dU7-exl*+YhppE2u4D8Y-xrIh+^6LTm~{^v zhoq^8z(`xF7M>pmpVsJo5VajFk=_F79vT->lRv&ly~|a2AMO!PutU_C&}TfX3Pf2O z=b-oJ*f7Pp4@#B?JR~+V>33P-aS8UY8=7gQljrYcK6(U5btpCWw#wQMznV_=NvKzw zK0m3JnKm@r8EIo0!Zo_e2Y#clh72=97XxmhX~~JB3Ge=Wxbs@GSXdL?hHMmlYgA`h zCJy93F4(QO!rB?@tj(lOY0JsQ#yGHyE@j7`@ literal 0 HcmV?d00001 diff --git a/.internal/wui/public/logo512.png b/.internal/wui/public/logo512.png new file mode 100644 index 0000000000000000000000000000000000000000..b3516222f0b978579b871c871b955b5fc5b4ca5e GIT binary patch literal 12066 zcmb_?={uC)|M;0P7$!_*$v%Z7p;X8^k&tYOtf5V0CuEyJO4dlJtVOm6+1D9Lq>z1Y zY&CYqlCjLp_xAn+eh+@v=fQp5XXc#yb9f%y&dJ_i5;^e$bz?mx0LZsa8}Soe)0ng4V06ZQ`CF=^x6 zBl2j=&{g&roddB?V`6S#%EK~YS|>Z$;nK*$2}$!zmD%JYDv1XU1=B+`%s$QhZtueO zZtSLRrK;0C<3z}^h`i-um%<^Tab|APS@0t1lH^S>CtAUM$Z0Qesa_UVn;hxPwI z@c%6*1jo32S$;2*FXhDOdPN(qQ(h|`(X$#RXb9~EO6g5M%AL8-G)JAIP!h7hSJT;1 z^D)#eIbyo1^ksReaYdZL_@3cd1yI2d!bY5y~U%~dLl;;z~BHKIO%TL zy>fO$WnDx=OvQ?b(WN3tdg$4*%lrEt z<)$ax->j=F$COMOLjpv+JLz6vHMW(IHQ6s|R>k!>AB_dTS&km8ceu1bgZnB9T9i4^ zOsZ_|QpLSqmO=jF0EQc9p923%YP>kjfWkFWksa$=d;rf0R{xqXt}p)POOY#Z6U-I_ zzhK~|+I%jxmE4fs0~Z3y0A$gBE{byuVUd|kU@wolCGnD*ap#=)IAya>s;Lms%%~AJaT5ygl z!3q$w6L4H=dQ1@wCC~r+RF|@%U;AN}b&%(X)R^|`$NRbyMKFC}<|p~nYp6(e6@x`W z=gXuH+PR1uc#WrZ=G?!`?(U4={~Alts7s6eC%I_A=-5&)v3PJ^J%*gdM&g9zv4v4o znRs~-yS2DASnfvL#sB72VF`n5#!Xet#{T$b+=!oLUI5ngL=`7pJ>Bn0Bme%+jMDp? zgd)MyFMWjDw%SY)7Xdgy*Qt4NE_0Qzy(_G{BSf^ev_?+sB47Y{C&}Vup^Rg)Ih9`~ zhi`4Ub=@%D9g)BNMhlOOxW4CCU>@6hQvIw-x{P4Nu8(Vc0t*u0TTLdHB0RazQCXDn;V;g*4r$?@St&F zk9YIi%-HhRaBN-+LBdG_mqIMza8V_<_uV$Wa}xLf{Mi(fJFHrco){wNkh$lg(=5+#dr>RR4g9q%1BtSiOCCyT*0luuApagYe6Vuj1_fwTsws zKx*K4nGvz)GFdw_sct#<@$Itbvvm{#Ot5C*27MC)gmwyRfgl(2cDu+uW@z=wWk&FJ z4Vlp8YGwHZ|7^^N`4=-J$<$BOT`THVL`TTyzdOENsM>w2#Ara%h<#qH1M17{ z6RAuvpmc<`JLLa#KqK3E{MiqVuvs`nT%j1cE$QD@gf-pX7SGBBOWJo1M`(f7)SjKz zt)uqGt5EP^K1e1`?`)mk$=!@6cWNgi-yu1>;P@ZijBlQxTC_`LY#sXld;XZ)rIxdB zh!!z);h|@_dq)dRF4#gE_}mqEI5po#$(628M}J9Pw3Ix60T?b{!6XR8s|LDfbKY3L zH(X#UZh!Hl_JD-!XQfKiDyFI{+un*D0q&gLS^2*738%lj-TLe}XC2@hJA{M-uQR%P zn^?Yy>%no#NT3_MK}z)bvnsLTLhzfoZu+$N;g?%jG$770>Msj<)qh5nB>3p;_Q=Hmi;5&e(RIT?AtW1QJu;6MK2mNi|( z^_^EhwwG!7b*MGbE zsjk6q&a6^;5fCsefSeEU6x%)uZg65^2M&$qvxOuQ36RMhrV58@Cg4ZY;$4skIQT3| z(=TTnMBi8d7RY^J-~x5~(SxzrY1w~F7%2F{+t*ZMUkcqrv}vDk^?VKC?IEO2PX>5& zjglOS^DN}i9&Q)`Y@UJ-v@`ZoYK-A)hEAlA45EHQHyq$?RDeF`S-APGCRT*w032w} zOsW4#{1StA6{^1+{RR3bY;u);XM};|_k(l^zgS&+;vje)$ck^+hi7bKljJ-7$nnd& z%YR{+-yK+B;HcCQ8j~R$bRi(hTy(nN9}9td-u({Z=LIiMoIKwR>==7w0Im5b7SESu zaJjYogR`x+wVB_C&7U}{D*?~Ty*4i?@BO+~J_liQ+)DPQ_$FL&Q8pkkpkTmMXw;-e znMzuT?z-9&<6EwH)(o{N`yeQ`^7SD|{of$)uFYb!#_Z7SZ~XLj>D~25L$;?R3|iMa zlT7>4DD`I(&hh*58KAr)nCrX^UwBIHQ(bd%;(Ve&hn44R-P(N0-B04S9CgtN*#|EY zAEEtA+=y3uh|RwnzjzB@oQ3d1-a41~QwINK`4+~>C+8sJjO>0S65W^$<1$_2MJn*_ z9QPHezt{eB-^zq}%}tyaIdo!AM$dHH8sjT5x8mSOaZ+80QF3iy4GZ?OC%p6}H4`Ot zSk-A8RBD?E@r-tn)EtiU<~&!O{kMQr_PQZO_#=INJ+%j>V)dCrW!P1lBSW!d;Q?4C z?;;cacFjn#>WJpuqAddaBz@Nn>jdL;c*vpvF-1PzZzM6~<;KMxnjgb5T#OkGg1pVJ z?^CNPr*ML^qjgE;o>Xz2di4Vv;$}<|)qCdRk1Q8Y7bSzNfa~dCN zn1g;1xhjO}za4+y&A@tUAfIgRTO=j+co^MkFQvej8f~f7@6878M5TeyUW24>v|-Vu z?_s$o?btn4)6kJjDzK@cgT>LdAe>Y?z)PonvGh#*(?lrVcvzN8BWSFS!65_CJmbvt zMn3HJ#nC;V8(n+54kbJ4rxw37wZk>PJ3x^g-YA$e^hJrs<|XWqC1z+S4cQ%XWK9>`S;V+b{Tmm*o7X`)?Vq5g7yl2ZoEEnAufc80fe3GUq6O(PUQ6|g zq5z(#95kD!$|?S@N*zscqw-w(`Hd4$4FE#)3iAN6TcKaeCO z00mhXF1~^R&U#T_zPj+!#Op95u-`~Iou2wsi(_~M*1S*RQ5Pm0E;&eB>F9y0{*BNI zqNjooT%4DsGBGDH=M?5rn1;kh=fGcqWDskQG}jhvRU9jmP@# z5X>iVkVYsk%328>f?R+p1r;39Fmn#iq*#!{dJjsaCOq(vGa;l8tBtD|GAnt>%*k0x zLT(3&Q&ISzHkRn25_>chmWftAijd<=bYp`(G8<44d1eEIbC#6*lBgJn$6y9JwYgLKTM{#R3Eg;c&PqmjX= zFmp`|@3j#|gsRt}rnoiK)YZMXJ$^>)%CX9A1|AT5|vcbdk9DV{R4H;mCTQ) zFelKQhDe`*gBT=4B;)YV?3-}yIoWbe&sF63TAjVe5tfmH9D$)X6oQ-h=HeTs#ZyRS z$i5qYIl~Xdy_CV)7kyC;Sc_JBMlSjRC#S0f2jp7(iXkiF<8ct&)j)jn#ACoZCIuEA(%2J`zLu^)70+SD zLW(p|*z#v3^7mSR>Pq=pjpQwdOydw!7V8C;B%6NXWh_x}=zWD>DK{>-VM&&}QYh4= z!i3T!jBNR3d~YSKh@LLva8s;>=9@&oX^dYm7}R5S~1q+Th4=3oK9w zzv2m-Y?9MB#49jH`}h1@`2S6l97XO=t86h ziz%GVK@_AmYp=O`zD_tc8dja_ygON^tMTnac27JO@#EKXf&oMy6O}ax4>t*)VKOEorhNO=z z8ZwP$XvBMuBIhgkUxonxbc$4#usvCsU9opW_>(&MR#<8{(Y?TJJ*FkZ7TZ*%3-EPQ z8VMV@^twsiG-e-tD5>FqOV=I#yA>IR)#|ZRHI4-M9TcwD?Ry~OC+?c#A(9d`Ql{}P z8ln7wIn*yMZ0o|<2oZq*ea3sE1y*#q@pzocbaQG?Q)~T93JaYBZfa&*YQ(-^(%bb& zV^KCI$QuDttEgK=K-BxAjjb)X;RojqnkEvCPBc}vxk<-GgegJ>r9~JjhNR|V;>5@2 zsjM-5W?02Ib@>H=XRw6QG@D3fOYMB0X;WBDh~mYk_6#262CGtVR{FrBn)w6__|yF? z;>c;0*<9>_R`#NBs@h@T;Y_*Fzeae}!BzZiX6e>ldA548EsTNI_<|hU zO&eysh$EM=HFC(Jjq}f$FRI$lp$Y_7L!`0|t4B)<$UBcv9lHHQ1Hlc?2|A0wb4TGu zy(z`s+-lw%bX2E!=0D776Qu?CC)d(*NMORpkjGbD8(hMFQWxw6_!RW%GNQ01vbt2e z7XvQc*h^6+g$IY7dSChDbu@}u7!Yld7JAN7F)g7PuIxMrD0!EbF(akEjg}=cS24j2 zp;`j-%3a`2enrxNVUC-cp)565q3DeJUwGVkpnE6_a-zs1T`CdH)mr%2Fz5s^bjid| zO#ad;dN{~8nRFCSJ0Ha?K=$)urYIH(5x`3a4a3Y#k#5j-cSUbY=a(?6J+u>2@H%^= z?Hrg;L>KFR0hZHk5xi=Yl{RH=mT%?Q6Zpsd(Z_I`w>QBLvY6@74<=c&B>UDH++D+ zuo^Xei_2NWWyn^wt>do_ZsylLZ5i_YuBayqq@}d%i&0tqpfkGYZE%*0ZMh9riy4_8A~1xzo(0tIUn z!T30t9>jn?=aV?D?Pm_3ewgv$RbU=hDFibmu0P5?ADnT!eae;*t?1Qm-h1J|_y_Y{ z3~p<;_4BWm{=oV>zqxd{8P9EVc;PMyw~dySLm4&n(`vdPZ#t|e@!WeVV-;>(Fv1-n z3xa6o(a0!<15$TBj(2o7bCnw|t9mn+4X~xO8A(%Qo2_k9$2qVgt%onFRffGCqyMYa z$|%Ou)AIqGctP%@+P3Az#fO0;#U~Pc0#mSy)Pd^`o!g?O<%w29&P>U2&+NjH;29qy zC-;SuuoJ~^JJSA{6SQm5j!l;LtJTDbG#HbfK9^jFEu`yZJVyqr(5_}3?^@Ikc~2f| z=`i!~qPR=ZYe<*hiw&la6`^+ij<}MUk)XISulo0tmt=l2@zp!iWDTFrfyG#E#|1{9 zVt$96=otTmn6bgO6B^w7p(C)8yBev#+g&%pzZhi=FXNh5WDCwVaV90$_Nx2)&q?zl z4uPBACQ>sYlce0QB3@d2fcq+ZNgZ)@#!(GGSuu8%@8t)z>tY{7gQWbtaf&~;?(+Ag zT=BM^z0On=ZxANy5_$p&bZoEhc-6i2|LC(->31QvIbKym?ZcTZMj!b~oB_wb-~+Qm zXQ49b{461P%DcIvZ}P$Bc7h{6xYnn;xy+mL*QY@P8xDiRCWg8RKSt^5A4+CdSf4TC zL@zjdrL8*ZZ~q%e7$XT#6Pz^RSlukf%wHPQEd0PM{LbNl=&u^LK4)~1uLFV*9E;3i zq{$C|8{lQC9pQg2i&ekI1^A?%TGq){r?cCao`zu}eUv`SczaL!oWa=QPtAB7H44T> zL(qA!e0Z>$(T(exoW(h9eZBWZG#$=H{1KvId6AH|~ zhh62wgR9nq6;-9sky9h96aLTpj7L&r4gxqEP`Uj6rp}+koR1QHg~DbuiPzoykU#&` zrUnBK{{_2F6eE2nAvvxNs2)}|kmiJie^#t*+Z@5N5)F18Tao7?O}3M?(o=;rAASe# zd@Vn9v@3(5DK5Tf#&I@{xfL0WwKrpxJF-v4TO!4bK;+d=gPh5P{so~G-u4EjiCY_l zj_pbUF=XaY3ey?oxF52ABqLY`nA_aWOvt^lQ{7?XtsV-QF%^7SHxgF!&UyYFqq&~+ zWK)2`{mjAdB2h08znc89DO5hCfCe>m&ip8AA5mjKmBgy*tBlpUS^Zj$)go6j8F^`m zmo;%;k165qC4M?g^B46Byw`S^w`LtG8zy^1z#i}3?k;I?Ktk0>(w%nq ze|OGQl0FrRot|3AvPkdl)I2lBg@&wvv@?Bo<^FiXyw39Un+fuo=a6mTEQ`O2pZUQI zl^FULf$Ims?0)%E{BOd>hio1$k+qzRHuBIRQ2*rpW!Z(m&nV#Q>DISB{pT6ZUEur6 zg!mbO#4B|b2i>~TVzcGgf|6hhPt*58Y(H(by+=L2&6>G@B+sRNeGfOVY_L+|oCNYdR&BI-DK-1NVI%Zd6J zy%ATTrIT{}w1qejSJ;sReJ?ir*n;Bp|FNwedlfA4+p~+IH`xi5C*jyz^QrN+J&hm# zJWancxz`o|$hVaIPS7VgD+Tfy_t+r9YH`61w=@*&qWvP3ZY{|EX5HiU<7Oz@^4;_5 z6~0=FdTtG>3n?qI+m-`fN9C@oJ(gs?p^A;{CKRxaa&t3Iu-GE-kJMdN=FoosL4;HDH~R`{VP?EI-=kibf1R+#+AKW9Jr=3}-0s>cd-|<$%!q$UyvXIT z#g&saB1$V@45~NlwM&7%ip10w)tE#(K@W&0(sTo^EXE)I-%?6DbSMOR>fl%U=>k=(Lj8-LeC!wnLWBPuh(SPDEelvXS+JoqMoXr?^L_b~iNh*ikH* z8W#+3uTCxgI1Wzq(^S0JfD9aaop0mVi>~3RQFW9kigASY^h?V*m$NNQI>2A-G7Nd{ z_1{ChtX?DohYeA*wU6bN@1&mLFzx5u`f(Lb*aXxuQH}k|Pa_X9>&h3B4}mCMBW2K) z(nf101YTw!pa>jaHD!n&jHd^#m6`P6vy1=+V5fMokAu6fR8STFI1(5t3fpYv<0Sn= zKZ#N#8tandMcN@ft6|tve6-50L&Y$*Vx>bI+1IO zw_fYrAxXtNJurFK2dcvuz7z@@DP&Woc3xk$W+a}2;z=%{5HwT`X(gA;NUJ+-Xe4GV zy%?N+WHzH&1^{Q<{#^jac10roD%&RsF@PBqEpsoIj+djm>WQi~s8-QJ_p@+nkO&kO z(nV5!=4j{&K(*G-qXCuALh7Loe0`*^3vXam|ol zX*?UH-}+iE03+rfe~Jf0a=`~GU!r3=k4;s&wA^CBNV7D>2y20Cs{)Gj^Gwhrfmu&I!?_|MNk|^JES+xd*U0Q2V z%TWwajWD<|rC{8#8>F%)oZM}*%+q8L-I^4tws?I`0QU0+hPXRezXwea49t1 zel^Be8VnBN1}4x-C`kQAzYj+Ztm(H9WC#z$d=qzq4r4&Jlj(HJ$BA=ZIl0svIMhul ze`R-y{(*ejU_paJh7$%OI)RC7?-6Ey1?hA`f<+f1q7*b})=%l(t6 zg#{k5DljBe2I;-b=moL^e&zHR%DGmYH;>npyw(SK-kg;Vs5cXmh;r`EahSCp!DJ7j zp*x(KKJ?Y6Lwb^E<)_6VZgPw)|340#|{5 zcj61VIn3#6=Y^*OMkkU^a!@9M{fVePRAu*s* z@k`#fl|VbHPWf)uNxJ^1F*^cpD#5?(Jr7)*_v$QJ(dOtAu2vH_^y~^PGQJp^ePnD= z>U-Z)bvjgN0T zH`ka^e0=-`+a!_eE0tMJ%XahzzjC|wjTZ=Dvn z;(zS6FZs@o$?eyBMcJ0V;8cH+a6Pvz_!{tToJ10JrZ6s1x_a6u*aYxA&nZmult>W4#Z%N$=v+;wyNNUlwy>)dX9j~$lJM%0C z)b?;?_gPt$c%;jwS(Eqgy6d7h57qhul^mR2IYS>li2${rqWacF4E)Gu7xzC+jVKMy z;x5^)-rYV$#!(P7%KTbyL^-v`tV*9k4iat)etPnw?2=sSJx0h}hH!)V zmus#~4o^Rt5YoH{6YB3qX^>s?m-!4G%c$|3#HySEk&{#HFJ)X{M>b9OC>!U8H@VGx z2WK)wL`5(37oh%JT3!jIt5tnv%N5JZZ?>D!p|oz1mvwt|AP;Kp*7}x{ctibf$h|^V zEC=7O&}_3iEezon(aOm#9WFVwc8Y&5jQVdTrJeT0XrLh7kxo>^pS4kyWDnHJAV)Eh z+)wYWSLHj`wm)3Z_|Z-HdW@KREpq|tLi4#^*6{xkadxKlpSq)De(Sj-SEV$na_$8# z-DRJ^k24;TCqK9s?t)aSJyr$hs8T8)H*V;W>dTDIetEL@bFk{eXHTAd=sqNll(ab= z4LSI0)KRMXU77sz>3-%xFG?2Di@|8u_D~ti#N1&oaSfD-_+Kr`TFvma{$)bkhS-?? zeA!=SU-d1C@qmDBBd8U12@tm=KNPo|cns=&3^`R)CagUodL7o>luwL!V1b;@0-y zjf&%cj!ngvnpN~q4M=EWs; zhM`%j^EbulaPN9|a&?!rxup$Fm=`9JD@qK!ue-%X?7KGROI?RKyhFRbLKu z8mi_k)KEz#dvl=vkGM$Qh>t`P$~D8>ygtHiu6$?f{`PdfckoF@-F5jDBcSx-yQ-;$ zV2MX}?84q$er?0K56xYD-08}LDT()BsS7G*b%vkOFM-Fa7Xcqi+giLMpbB|S{Q!R`(05%OUBfF#%ihn)R0`(Y%kgQF9yl~9YShev6?&egg}PF`v!(C&K0p6Idd zxSXya4FqZZNnvQS^Oorz8+eSrVKo}zefbFWo{#BJMiP0$PFeDOP0_~VIxl3S6K_bA z1`Ln($U!l#UVGDff37af?gVXnk9?`BZG{8n$=2A)P`Dh*Iw=Q9F|kS;U=XQQN0JH@ z)UF&y59#K(Ml`zOWR)H~bj+eZjcok!EPKoGK;v13nC-2h<-r;oR=Rmje>`};(IQpO z*)+du)W-b9{DdMGyIKpK@XDNe;~=f_twKO?mXfOsby>w>_!LIfVxcE`#!r(X2@tgK zdFioWc&F_pkyG4lvYCk+#y1=;9Qpo(KAhC|S;O^@qC4ZQ=3snL*=?D*H)As2Y(}?j za*iMiXSWuOPN8gue9}r+r;>d zsaiWlB^^Io*mxI*l>Sban{0$lKaO9=*l9_ znYorw(z8O(>fT$~C8kSqY24pF3_c^_5wSkAEEDGk6h<`_?E#?<)JBuDtFVe?Dydo_v86ctM4qQP7&F+tMh@#M`6REw331hfIltwTE?vC zdNc76Dx`+-D*Ji~y6L);IaF+spE33* z_=wkB0BxuDo-5{VhJD8F&zzlN8$^X^%zd;jhGEk;|sI=dIf;=2D}0n zyopY-hTYVyN>nhPRbY~NLva3np`to5m07|hy1tOew zZit?tOeK6+H;6BiSVC>L(`ij~TbE`gH~^1D1^%TymNfYZ<$uuX-8Wj$3kE$Y450fR0KX6G|1p5CGHgWJRSg^YclKB6X&YYpq-h`ae-rA4 A^#A|> literal 0 HcmV?d00001 diff --git a/.internal/wui/public/manifest.json b/.internal/wui/public/manifest.json new file mode 100644 index 000000000..2f2be64fe --- /dev/null +++ b/.internal/wui/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/.internal/wui/public/robots.txt b/.internal/wui/public/robots.txt new file mode 100644 index 000000000..fa06a7563 --- /dev/null +++ b/.internal/wui/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/.internal/wui/src/App.css b/.internal/wui/src/App.css new file mode 100644 index 000000000..355c49bf9 --- /dev/null +++ b/.internal/wui/src/App.css @@ -0,0 +1,39 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-float infinite 3s ease-in-out; + } +} + +.App-header { + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); +} + +.App-link { + color: rgb(112, 76, 182); +} + +@keyframes App-logo-float { + 0% { + transform: translateY(0); + } + 50% { + transform: translateY(10px) + } + 100% { + transform: translateY(0px) + } +} diff --git a/.internal/wui/src/App.js b/.internal/wui/src/App.js new file mode 100644 index 000000000..85a146223 --- /dev/null +++ b/.internal/wui/src/App.js @@ -0,0 +1,30 @@ +import React, { Fragment } from 'react'; +import useMediaQuery from '@material-ui/core/useMediaQuery'; +import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import ReactRouterBootstrap from './router' +import './App.css'; + +function App() { + const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); + const theme = React.useMemo( + () => + createMuiTheme({ + palette: { + type: prefersDarkMode ? 'dark' : 'light', + }, + }), + [prefersDarkMode], + ); + + return ( + + + + + + + ); +} + +export default App; diff --git a/.internal/wui/src/actions/buildStack.action.js b/.internal/wui/src/actions/buildStack.action.js new file mode 100644 index 000000000..0f6d83337 --- /dev/null +++ b/.internal/wui/src/actions/buildStack.action.js @@ -0,0 +1,15 @@ +import { createAndBuildStack } from '../services/builds' + +const CREATE_AND_BUILD_STACK = 'CREATE_AND_BUILD_STACK'; + +const createAndBuildStackAction = (selectedServices, serviceConfigurations) => { + return { + type: CREATE_AND_BUILD_STACK, + promise: createAndBuildStack({ selectedServices, serviceConfigurations }) + } +}; + +export { + CREATE_AND_BUILD_STACK, + createAndBuildStackAction +}; diff --git a/.internal/wui/src/actions/checkBuildIssues.action.js b/.internal/wui/src/actions/checkBuildIssues.action.js new file mode 100644 index 000000000..c4572b7f1 --- /dev/null +++ b/.internal/wui/src/actions/checkBuildIssues.action.js @@ -0,0 +1,15 @@ +import { getBuildIssues } from '../services/builds' + +const CHECK_BUILD_ISSUES = 'CHECK_BUILD_ISSUES'; + +const getBuildIssuesAction = (selectedServices, serviceConfigurations) => { + return { + type: CHECK_BUILD_ISSUES, + promise: getBuildIssues({ selectedServices, serviceConfigurations }) + } +}; + +export { + CHECK_BUILD_ISSUES, + getBuildIssuesAction +}; diff --git a/.internal/wui/src/actions/downloadBuild.action.js b/.internal/wui/src/actions/downloadBuild.action.js new file mode 100644 index 000000000..41823ebf0 --- /dev/null +++ b/.internal/wui/src/actions/downloadBuild.action.js @@ -0,0 +1,16 @@ +import { downloadBuild } from '../services/builds' + +const DOWNLOAD_BUILD = 'DOWNLOAD_BUILD'; + +const downloadBuildFile = ({ build, type, linkRef }) => { + return { + type: DOWNLOAD_BUILD, + promise: downloadBuild({ build, type, linkRef }), + label: build + } +}; + +export { + DOWNLOAD_BUILD, + downloadBuildFile +}; diff --git a/.internal/wui/src/actions/getBuildHistoryList.action.js b/.internal/wui/src/actions/getBuildHistoryList.action.js new file mode 100644 index 000000000..874e67a25 --- /dev/null +++ b/.internal/wui/src/actions/getBuildHistoryList.action.js @@ -0,0 +1,15 @@ +import { getBuildHistoryList } from '../services/builds' + +const GET_BUILD_HISTORY_LIST_ACTION = 'GET_BUILD_HISTORY_LIST_ACTION'; + +const getBuildHistoryListAction = () => { + return { + type: GET_BUILD_HISTORY_LIST_ACTION, + promise: getBuildHistoryList() + } +}; + +export { + GET_BUILD_HISTORY_LIST_ACTION, + getBuildHistoryListAction +}; diff --git a/.internal/wui/src/actions/getNetworkTemplateList.action.js b/.internal/wui/src/actions/getNetworkTemplateList.action.js new file mode 100644 index 000000000..6fa999f58 --- /dev/null +++ b/.internal/wui/src/actions/getNetworkTemplateList.action.js @@ -0,0 +1,15 @@ +import { getNetworkTemplatesList } from '../services/templates' + +const GET_NETWORK_TEMPLATE_LIST_ACTION = 'GET_NETWORK_TEMPLATE_LIST_ACTION'; + +const getNetworkTemplateListAction = () => { + return { + type: GET_NETWORK_TEMPLATE_LIST_ACTION, + promise: getNetworkTemplatesList() + } +}; + +export { + GET_NETWORK_TEMPLATE_LIST_ACTION, + getNetworkTemplateListAction +}; diff --git a/.internal/wui/src/actions/getScript.action.js b/.internal/wui/src/actions/getScript.action.js new file mode 100644 index 000000000..8b01dd579 --- /dev/null +++ b/.internal/wui/src/actions/getScript.action.js @@ -0,0 +1,16 @@ +import { getScriptTemplate } from '../services/templates' + +const GET_SCRIPT_TEMPLATE = 'GET_SCRIPT_TEMPLATE'; + +const getScriptFromTemplateAction = ({ scriptName, options, linkRef }) => { + return { + type: GET_SCRIPT_TEMPLATE, + promise: getScriptTemplate({ scriptName, options, linkRef }), + label: scriptName + } +}; + +export { + GET_SCRIPT_TEMPLATE, + getScriptFromTemplateAction +}; diff --git a/.internal/wui/src/actions/getServiceConfigOptions.action.js b/.internal/wui/src/actions/getServiceConfigOptions.action.js new file mode 100644 index 000000000..0f83dc263 --- /dev/null +++ b/.internal/wui/src/actions/getServiceConfigOptions.action.js @@ -0,0 +1,16 @@ +import { getServiceConfigOptions } from '../services/configs' + +const GET_CONFIG_SERVICE_CONFIG_OPTIONS = 'GET_CONFIG_SERVICE_CONFIG_OPTIONS'; + +const getServiceConfigOptionsAction = (serviceName) => { + return { + type: GET_CONFIG_SERVICE_CONFIG_OPTIONS, + promise: getServiceConfigOptions(serviceName), + label: serviceName + } +}; + +export { + GET_CONFIG_SERVICE_CONFIG_OPTIONS, + getServiceConfigOptionsAction +}; diff --git a/.internal/wui/src/actions/getServiceMetadata.action.js b/.internal/wui/src/actions/getServiceMetadata.action.js new file mode 100644 index 000000000..9336c9ea4 --- /dev/null +++ b/.internal/wui/src/actions/getServiceMetadata.action.js @@ -0,0 +1,16 @@ +import { getServiceMetadata } from '../services/configs' + +const GET_CONFIG_SERVICE_METADATA = 'GET_CONFIG_SERVICE_METADATA'; + +const getServiceMetadataAction = (serviceName) => { + return { + type: GET_CONFIG_SERVICE_METADATA, + promise: getServiceMetadata(serviceName), + label: serviceName + } +}; + +export { + GET_CONFIG_SERVICE_METADATA, + getServiceMetadataAction +}; diff --git a/.internal/wui/src/actions/getServiceTemplateList.action.js b/.internal/wui/src/actions/getServiceTemplateList.action.js new file mode 100644 index 000000000..361383dd7 --- /dev/null +++ b/.internal/wui/src/actions/getServiceTemplateList.action.js @@ -0,0 +1,15 @@ +import { getServiceTemplatesList } from '../services/templates' + +const GET_SERVICE_TEMPLATE_LIST_ACTION = 'GET_SERVICE_TEMPLATE_LIST_ACTION'; + +const getServiceTemplateListAction = () => { + return { + type: GET_SERVICE_TEMPLATE_LIST_ACTION, + promise: getServiceTemplatesList() + } +}; + +export { + GET_SERVICE_TEMPLATE_LIST_ACTION, + getServiceTemplateListAction +}; diff --git a/.internal/wui/src/actions/getServiceTemplates.action.js b/.internal/wui/src/actions/getServiceTemplates.action.js new file mode 100644 index 000000000..f0aaa8c71 --- /dev/null +++ b/.internal/wui/src/actions/getServiceTemplates.action.js @@ -0,0 +1,15 @@ +import { getServiceTemplates } from '../services/templates'; + +const GET_SERVICE_TEMPLATES_ACTION = 'GET_SERVICE_TEMPLATES_ACTION'; + +const getServiceTemplatesAction = () => { + return { + type: GET_SERVICE_TEMPLATES_ACTION, + promise: getServiceTemplates() + } +}; + +export { + GET_SERVICE_TEMPLATES_ACTION, + getServiceTemplatesAction +}; diff --git a/.internal/wui/src/actions/updateFilterTags.action.js b/.internal/wui/src/actions/updateFilterTags.action.js new file mode 100644 index 000000000..8f9e5c3a2 --- /dev/null +++ b/.internal/wui/src/actions/updateFilterTags.action.js @@ -0,0 +1,27 @@ +const ADD_TO_FILTER_HIDE_LIST = 'ADD_TO_FILTER_SHOW_LIST'; +const REMOVE_FROM_FILTER_HIDE_LIST = 'REMOVE_FROM_FILTER_HIDE_LIST'; + +const addTagToHideListAction = (filterTag) => { + return { + type: ADD_TO_FILTER_HIDE_LIST, + data: { + filterTag + } + }; +}; + +const removeTagFromHideListAction = (filterTag) => { + return { + type: REMOVE_FROM_FILTER_HIDE_LIST, + data: { + filterTag + } + }; +}; + +export { + ADD_TO_FILTER_HIDE_LIST, + REMOVE_FROM_FILTER_HIDE_LIST, + addTagToHideListAction, + removeTagFromHideListAction +}; diff --git a/.internal/wui/src/actions/updateSelectedServices.action.js b/.internal/wui/src/actions/updateSelectedServices.action.js new file mode 100644 index 000000000..7aab418da --- /dev/null +++ b/.internal/wui/src/actions/updateSelectedServices.action.js @@ -0,0 +1,27 @@ +const ADD_TO_SELECTED_SERVICES = 'ADD_TO_SELECTED_SERVICES'; +const REMOVE_FROM_SELECTED_SERVICES = 'REMOVE_FROM_SELECTED_SERVICES'; + +const addSelectedService = (serviceName) => { + return { + type: ADD_TO_SELECTED_SERVICES, + data: { + serviceName + } + } +}; + +const removeSelectedService = (serviceName) => { + return { + type: REMOVE_FROM_SELECTED_SERVICES, + data: { + serviceName + } + } +}; + +export { + ADD_TO_SELECTED_SERVICES, + REMOVE_FROM_SELECTED_SERVICES, + addSelectedService, + removeSelectedService +}; diff --git a/.internal/wui/src/config.js b/.internal/wui/src/config.js new file mode 100644 index 000000000..15315e3a2 --- /dev/null +++ b/.internal/wui/src/config.js @@ -0,0 +1,6 @@ +const config = { + apiUrl: 'localhost:32128', + apiProtocol: 'http://' +}; + +export default config; diff --git a/.internal/wui/src/constants.js b/.internal/wui/src/constants.js new file mode 100644 index 000000000..2f00de768 --- /dev/null +++ b/.internal/wui/src/constants.js @@ -0,0 +1,10 @@ +const API_STATUS = Object.freeze({ + UNINIT: 'UNINIT', + PENDING: 'PENDING', + SUCCESS: 'SUCCESS', + FAILURE: 'FAILURE' +}); + +module.exports = { + API_STATUS +}; diff --git a/.internal/wui/src/features/BuildSidebar/build-sidebar.module.css b/.internal/wui/src/features/BuildSidebar/build-sidebar.module.css new file mode 100644 index 000000000..0bc7efa3d --- /dev/null +++ b/.internal/wui/src/features/BuildSidebar/build-sidebar.module.css @@ -0,0 +1,11 @@ +.sidebarWrapper { + display: 'block'; + min-width: 40rem; + max-width: 50rem; + padding: 1rem; +} + +.section { + padding-bottom: 2rem; + padding-top: 1rem; +} \ No newline at end of file diff --git a/.internal/wui/src/features/BuildSidebar/index.jsx b/.internal/wui/src/features/BuildSidebar/index.jsx new file mode 100644 index 000000000..e41634fb3 --- /dev/null +++ b/.internal/wui/src/features/BuildSidebar/index.jsx @@ -0,0 +1,331 @@ +import React, { Fragment, useState, useEffect } from 'react'; +import { useDispatch, useSelector } from "react-redux"; +import Box from '@material-ui/core/Box'; +// import Tooltip from '@material-ui/core/Tooltip'; +import Button from '@material-ui/core/Button'; +// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined'; +import Divider from '@material-ui/core/Divider'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Checkbox from '@material-ui/core/Checkbox'; +// import { makeStyles, useTheme } from '@material-ui/core/styles'; +import styles from './build-sidebar.module.css'; +import { + addTagToHideListAction, + removeTagFromHideListAction +} from '../../actions/updateFilterTags.action'; +import { + createAndBuildStackAction +} from '../../actions/buildStack.action'; +import { + getScriptFromTemplateAction +} from '../../actions/getScript.action'; +import { + downloadBuildFile +} from '../../actions/downloadBuild.action'; +import BuildCompletedModal from '../buildCompletedModal'; +import { API_STATUS } from '../../constants' + +// const useStyles = makeStyles({ +// serviceCard: { +// "&:hover": { +// borderColor: ({ theme }) => theme.palette.text.primary +// } +// } +// }); + +const getUniqueTagsFromTemplates = ({ serviceTemplateListPayload, metadataList }) => { + const tagList = []; + if (Array.isArray(serviceTemplateListPayload)) { + serviceTemplateListPayload.forEach((service) => { + if (metadataList[service] && metadataList[service].payload && Array.isArray(metadataList[service].payload.serviceTypeTags)) { + metadataList[service].payload.serviceTypeTags.forEach((tag) => { + if (!tagList.includes(tag)) { + tagList.push(tag); + } + }); + } + }); + } + tagList.sort(); + return tagList; +}; + +const buildIssueListItem = (name, issueType, issueText) => { + return ( + {name} [{issueType}] - {issueText} + ); +}; + +const buildIssuesRender = (issues) => { + const unknownError = !( + issues.payload + && issues.payload.issueList + && Array.isArray(issues.payload.issueList.services) + && Array.isArray(issues.payload.issueList.networks) + && Array.isArray(issues.payload.issueList.other) + ); + + const noIssues = ( + !unknownError + && issues.payload.issueList.services.length === 0 + && issues.payload.issueList.networks.length === 0 + && issues.payload.issueList.other.length === 0 + ); + + return ( + + Build Issues: + + {issues.status === API_STATUS.SUCCESS + && ( + + {Array.isArray(issues.payload.issueList.services) + && issues.payload.issueList.services.length > 0 + && ( + + + Services: + +
    + {issues.payload.issueList.services.map((issue) => { + return ( +
  • + {buildIssueListItem(issue.name, issue.issueType, issue.message)} +
  • + ) + })} +
+
+
+
+ )} + {Array.isArray(issues.payload.issueList.networks) + && issues.payload.issueList.networks.length > 0 + && ( + + + Networks: + +
    + {issues.payload.issueList.networks.map((issue) => { + return ( +
  • + {buildIssueListItem(issue.name, issue.issueType, issue.message)} +
  • + ) + })} +
+
+
+
+ )} + {Array.isArray(issues.payload.issueList.other) + && issues.payload.issueList.other.length > 0 + && ( + + + Other Issues: + +
    + {issues.payload.issueList.other.map((issue) => { + return ( +
  • + {buildIssueListItem(issue.name, issue.issueType, issue.message)} +
  • + ) + })} +
+
+
+
+ )} + {noIssues + && ( + + + No build issues + + + )} + {!noIssues + && ( + + + You can still attempt to build when issues are reported. + + + )} + {unknownError + && ( + + + An unknown error occured retrieving build issues + + + )} +
+ )} + {issues.status === API_STATUS.PENDING + && ( + Loading... + )} + {issues.status === API_STATUS.FAILURE + && ( + Failed to get build issues from API + )} + {issues.status === API_STATUS.UNINIT + && ( + No changes detected + )} +
+
+ ); +}; + +const buildList = (selectedServices) => { + return ( + + Building Services: + + {selectedServices.join(', ')} + + + ); +}; + +const buildServices = (dispatchBuildStack) => { + return ( + + Build: + + + + + ); +}; + +const Sidebar = (props) => { + // const theme = useTheme(); + // const classes = useStyles({ props, theme }); + + const mapStateToProps = (selector) => { + return { + configServiceMetadata: selector(state => state.configServiceMetadata), + hideServiceTags: selector(state => state.hideServiceTags), + selectedServices: selector(state => state.selectedServices), + buildIssues: selector(state => state.buildIssues), + buildStack: selector(state => state.buildStack), + scriptTemplates: selector(state => state.scriptTemplates) + }; + }; + const mapDispatchToProps = (dispatch) => { + return { + dispatchAddTagToHideList: (tag) => dispatch(addTagToHideListAction(tag)), + dispatchRemoveTagFromHideList: (tag) => dispatch(removeTagFromHideListAction(tag)), + dispatchBuildStack: (selectedServices, serviceConfigurations) => dispatch(createAndBuildStackAction(selectedServices, serviceConfigurations)), + dispatchGetScriptTemplates: ({ scriptName, options, linkRef }) => dispatch(getScriptFromTemplateAction({ scriptName, options, linkRef })), + dispatchDownloadBuildFile: ({ build, type, linkRef }) => dispatch(downloadBuildFile({ build, type, linkRef })) + }; + }; + + props = { + ...props, + ...mapStateToProps(useSelector), + ...mapDispatchToProps(useDispatch()), + }; + + const [modalOpen, setModalOpen] = useState(false); + useEffect(() => { + if (props.buildStack.status === API_STATUS.SUCCESS) { + setModalOpen(true); + } + }, [ + props.buildStack + ]); + + const { + serviceTemplateList, + configServiceMetadata, + selectedServices, + buildIssues, + hideServiceTags, + dispatchRemoveTagFromHideList, + dispatchAddTagToHideList, + dispatchBuildStack, + dispatchGetScriptTemplates, + dispatchDownloadBuildFile, + buildStack, + scriptTemplates + } = props; + + const downloadLinkRef = React.useRef(null); + + const handleBuildSelectChange = (evt, tagName) => { + if (evt.target.checked) { + return dispatchAddTagToHideList(tagName); + } + return dispatchRemoveTagFromHideList(tagName); + }; + + const serviceFilter = (serviceTemplateListPayload, servicesMetadata) => { + return ( + + Hide by tag: + + { + getUniqueTagsFromTemplates({ serviceTemplateListPayload, metadataList: servicesMetadata }).map((tag) => { + return ( + -1} + onChange={(evt) => handleBuildSelectChange(evt, tag)} + name="checkedB" + color="primary" + /> + } + label={tag} + /> + ); + }) + } + + + ); + }; + + return ( + +
+ setModalOpen(false)} + buildStack={buildStack} + scriptTemplates={scriptTemplates} + dispatchGetScriptTemplates={dispatchGetScriptTemplates} + dispatchDownloadBuildFile={dispatchDownloadBuildFile} + downloadLinkRef={downloadLinkRef} + /> + + {serviceFilter(serviceTemplateList.payload, configServiceMetadata.services.completed)} + + {buildIssuesRender(buildIssues)} + + {buildList(selectedServices.selectedServices)} + + {buildServices(() => { + if (Array.isArray(selectedServices.selectedServices) && selectedServices.selectedServices.length > 0) { + dispatchBuildStack(selectedServices.selectedServices); + } + })} + + + ); +}; + +export default Sidebar; diff --git a/.internal/wui/src/features/Sidebar/index.js b/.internal/wui/src/features/Sidebar/index.js new file mode 100644 index 000000000..00fd410d5 --- /dev/null +++ b/.internal/wui/src/features/Sidebar/index.js @@ -0,0 +1,165 @@ +import React, { Fragment } from 'react'; +import clsx from 'clsx'; +import { makeStyles } from '@material-ui/core/styles'; +import Drawer from '@material-ui/core/Drawer'; +import Box from '@material-ui/core/Box'; +import List from '@material-ui/core/List'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import Divider from '@material-ui/core/Divider'; +import IconButton from '@material-ui/core/IconButton'; +import MenuIcon from '@material-ui/icons/Menu'; +import BuildIcon from '@material-ui/icons/Build'; +import QueryBuilderIcon from '@material-ui/icons/QueryBuilder'; +import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'; +import AttachMoneyIcon from '@material-ui/icons/AttachMoney'; +import { Link } from "react-router-dom"; +import HelpOutlineIcon from '@material-ui/icons/HelpOutline'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; + +const drawerWidth = 240; + +const useStyles = makeStyles((theme) => ({ + root: { + display: 'flex', + }, + appBar: { + zIndex: theme.zIndex.drawer + 1, + transition: theme.transitions.create(['width', 'margin'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + }, + appBarShift: { + marginLeft: drawerWidth, + width: `calc(100% - ${drawerWidth}px)`, + transition: theme.transitions.create(['width', 'margin'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + }, + menuButton: { + marginRight: 10, + }, + hide: { + display: 'none', + }, + drawer: { + width: drawerWidth, + flexShrink: 0, + whiteSpace: 'nowrap', + }, + drawerOpen: { + width: drawerWidth, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + }, + drawerClose: { + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + overflowX: 'hidden', + width: theme.spacing(7) + 1, + [theme.breakpoints.up('sm')]: { + width: theme.spacing(9) + 1, + }, + }, + toolbar: { + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-end', + padding: theme.spacing(0, 1) + }, + content: { + flexGrow: 1, + padding: theme.spacing(3), + }, +})); + +export default function MiniDrawer() { + const classes = useStyles(); + // const theme = useTheme(); + const [menuOpen, setOpen] = React.useState(false); + + const handleDrawerOpen = () => { + setOpen(true); + }; + + const handleDrawerClose = () => { + setOpen(false); + }; + + return ( +
+ + + + {menuOpen + && ( + + + + + + )} + {!menuOpen + && ( + + + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); +} \ No newline at end of file diff --git a/.internal/wui/src/features/buildCompletedModal/index.jsx b/.internal/wui/src/features/buildCompletedModal/index.jsx new file mode 100644 index 000000000..4794a780f --- /dev/null +++ b/.internal/wui/src/features/buildCompletedModal/index.jsx @@ -0,0 +1,130 @@ +// import React, { Fragment, useState, useEffect } from 'react'; +import React, { Fragment, useState } from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import Modal from '@material-ui/core/Modal'; +// import Box from '@material-ui/core/Box'; +// import Tooltip from '@material-ui/core/Tooltip'; +import Grid from '@material-ui/core/Grid'; +import Button from '@material-ui/core/Button'; + +const getModalStyle = () => { + const top = 15; + const left = 50; + + return { + top: `${top}%`, + left: `${left}%`, + transform: `translate(-50%, -${left}%)`, + }; +}; + +const useStyles = makeStyles((theme) => ({ + paper: { + position: 'absolute', + width: '50%', + backgroundColor: theme.palette.background.paper, + border: '2px solid #000', + boxShadow: theme.shadows[5], + padding: theme.spacing(2, 4, 3), + }, +})); + +const BuildCompletedModal = ({ + isOpen, + handleClose, + buildStack, + scriptTemplates, + dispatchGetScriptTemplates, + dispatchDownloadBuildFile, + downloadLinkRef +}) => { + const [showBootstrapScript, setShowBootstrapScript] = useState(false); + const [associatedBuildFiles, setAssociatedBuildFiles] = useState(false); + + // const { build, files, issues } = buildStack?.payload ?? {}; + const { build } = buildStack?.payload ?? {}; + + const bootstrapBody = () => { + if ((typeof scriptTemplates?.scripts?.completed?.bootstrap?.payload ?? null) === 'string') { + return scriptTemplates.scripts.completed.bootstrap?.payload; + } + return ''; + }; + + const closeModal = (event) => { + setShowBootstrapScript(false); + setAssociatedBuildFiles(false); + if (typeof handleClose === 'function') { + handleClose(event); + } + } + + // const linkRef = React.createRef(); + const classes = useStyles(); + const [modalStyle] = React.useState(getModalStyle); + const body = ( +
+

Build {build} Complete

+

+ Choose from the following options: +

+ + + + + + + + + + + + + {showBootstrapScript + && ( + +
{bootstrapBody()}
+
+ )} + {associatedBuildFiles + && ( + +
associatedBuildFiles
+
+ )} +
+ +
+ ); + + return ( + + {body} + + ); +}; + +export default BuildCompletedModal; \ No newline at end of file diff --git a/.internal/wui/src/features/buildHistoryGridItem/build-history-grid-item.module.css b/.internal/wui/src/features/buildHistoryGridItem/build-history-grid-item.module.css new file mode 100644 index 000000000..c922af44c --- /dev/null +++ b/.internal/wui/src/features/buildHistoryGridItem/build-history-grid-item.module.css @@ -0,0 +1,34 @@ +.docsLink { + background: linear-gradient(45deg, #2196F3 30%, #04add3 90%); + box-shadow: 0 3px 5px 2px rgba(33, 203, 243, .3); + color: 'white'; + padding: 0.5rem; +} + +.selectedForBuild { + background: linear-gradient(45deg, #76c01644 30%, #04d35a44 90%); +} + +.buildIssue { + background: linear-gradient(45deg, #ff7b008c 30%, #ffee00a8 90%); +} + +.serviceError { + background: linear-gradient(45deg, #c016167f 30%, #d304047f 90%); +} + +.serviceCard { + width: 24rem; + height: 24rem; + /* border-color: "primary.main"; */ +} + +.serviceIconContainer { + height: 6rem +} + +.serviceIcon { + height: 6rem; + width: auto; +} + diff --git a/.internal/wui/src/features/buildHistoryGridItem/index.jsx b/.internal/wui/src/features/buildHistoryGridItem/index.jsx new file mode 100644 index 000000000..7fc0aacf6 --- /dev/null +++ b/.internal/wui/src/features/buildHistoryGridItem/index.jsx @@ -0,0 +1,129 @@ +// import React, { Fragment, useState, useEffect } from 'react'; +import React, { Fragment } from 'react'; +// import { useDispatch, useSelector } from "react-redux"; +import Box from '@material-ui/core/Box'; +// import Tooltip from '@material-ui/core/Tooltip'; +import Skeleton from '@material-ui/lab/Skeleton'; +// import FormControlLabel from '@material-ui/core/FormControlLabel'; +// import Checkbox from '@material-ui/core/Checkbox'; +// import Button from '@material-ui/core/Button'; +import Link from '@material-ui/core/Link'; +// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined'; +import { makeStyles } from '@material-ui/core/styles'; +import { useTheme } from '@material-ui/core/styles'; +import styles from './build-history-grid-item.module.css'; + +const useStyles = makeStyles({ + serviceCard: { + "&:hover": { + borderColor: ({ theme }) => theme.palette.text.primary + } + } +}); + +const ServiceItem = (props) => { + const theme = useTheme(); + const classes = useStyles({ props, theme }); + // console.log('theme.palette', theme.palette) + + const { + buildTime, + // buildDetails + } = props; + + let isLoading = false; + let buildHistoryError = { + hasError: false + }; + + const buildHistoryComponent = () => { + return ( + + {buildTime} + + + Download Zip + + + + + {buildTime} Help and Docs + + + + ) + }; + + const errorComponent = () => { + return ( + +
Error loading: {buildTime}
+
Try refreshing, and ensuring the API server is running correctly.
+
+ ) + }; + + const loadingComponent = () => { + return ( + + Loading '{buildTime}' details... + + + + + + + + + + + + + + ) + }; + + return ( + + + {isLoading + && (loadingComponent())} + {!isLoading + && buildTime + && ( + buildHistoryComponent() + )} + {!isLoading + && buildHistoryError.hasError === true + && ( + errorComponent() + )} + + + ); +}; + +export default ServiceItem; diff --git a/.internal/wui/src/features/counter/Counter.js b/.internal/wui/src/features/counter/Counter.js new file mode 100644 index 000000000..7bdeb324d --- /dev/null +++ b/.internal/wui/src/features/counter/Counter.js @@ -0,0 +1,60 @@ +import React, { useState } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { + decrement, + increment, + incrementByAmount, + incrementAsync, + selectCount, +} from '../../reducers/counter'; +import styles from './Counter.module.css'; + +export function Counter() { + const count = useSelector(selectCount); + const dispatch = useDispatch(); + const [incrementAmount, setIncrementAmount] = useState('2'); + + return ( +
+
+ + {count} + +
+
+ setIncrementAmount(e.target.value)} + /> + + +
+
+ ); +} diff --git a/.internal/wui/src/features/counter/Counter.module.css b/.internal/wui/src/features/counter/Counter.module.css new file mode 100644 index 000000000..6c2b58f48 --- /dev/null +++ b/.internal/wui/src/features/counter/Counter.module.css @@ -0,0 +1,74 @@ +.row { + display: flex; + align-items: center; + justify-content: center; +} + +.row:not(:last-child) { + margin-bottom: 16px; +} + +.value { + font-size: 78px; + padding-left: 16px; + padding-right: 16px; + margin-top: 2px; + font-family: 'Courier New', Courier, monospace; +} + +.button { + appearance: none; + background: none; + font-size: 32px; + padding-left: 12px; + padding-right: 12px; + outline: none; + border: 2px solid transparent; + color: rgb(112, 76, 182); + padding-bottom: 4px; + cursor: pointer; + background-color: rgba(112, 76, 182, 0.1); + border-radius: 2px; + transition: all 0.15s; +} + +.textbox { + font-size: 32px; + padding: 2px; + width: 64px; + text-align: center; + margin-right: 8px; +} + +.button:hover, .button:focus { + border: 2px solid rgba(112, 76, 182, 0.4); +} + +.button:active { + background-color: rgba(112, 76, 182, 0.2); +} + +.asyncButton { + composes: button; + position: relative; + margin-left: 8px; +} + +.asyncButton:after { + content: ""; + background-color: rgba(112, 76, 182, 0.15); + display: block; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + opacity: 0; + transition: width 1s linear, opacity 0.5s ease 1s; +} + +.asyncButton:active:after { + width: 0%; + opacity: 1; + transition: 0s +} diff --git a/.internal/wui/src/features/serviceConfigModal/index.jsx b/.internal/wui/src/features/serviceConfigModal/index.jsx new file mode 100644 index 000000000..55f5feb30 --- /dev/null +++ b/.internal/wui/src/features/serviceConfigModal/index.jsx @@ -0,0 +1,129 @@ +import React, { Fragment, useState, useEffect } from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import Modal from '@material-ui/core/Modal'; +import Grid from '@material-ui/core/Grid'; +import Button from "@material-ui/core/Button"; +import Box from '@material-ui/core/Box'; +import getConfigComponents from '../../utils/configOptionLoader'; +import { + deleteTemporaryBuildOptions, + saveTemporaryBuildOptions +} from '../../utils/buildOptionSync'; + +const getModalStyle = () => { + const top = 10; + const left = 50; + + return { + top: `${top}%`, + left: `${left}%`, + maxHeight: '75%', + overflow: 'hidden', + overflowY: 'scroll', + transform: `translate(-50%, 0%)`, + }; +}; + +const useStyles = makeStyles((theme) => ({ + paper: { + position: 'absolute', + width: '50%', + backgroundColor: theme.palette.background.paper, + border: '2px solid #000', + boxShadow: theme.shadows[5], + padding: theme.spacing(2, 4, 3), + }, +})); + +const ServiceConfigModal = (props) => { + const { + isOpen, + handleClose, + serviceName, + networkTemplateList, + serviceMetadata, + serviceConfigOptions, + buildOptions, + serviceTemplates, + setBuildOptions, + getBuildOptions, + buildOptionsInit, + setServiceOptions, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions + } = props; + + const closeModal = (event) => { + deleteTemporaryBuildOptions(); + if (typeof handleClose === 'function') { + handleClose(event); + } + } + + const classes = useStyles(); + const [modalStyle] = React.useState(getModalStyle); + const body = ( +
+

{serviceMetadata ? serviceMetadata.displayName : ''} ({serviceName}) Configuration

+ + {getConfigComponents(serviceConfigOptions ?? []).map((ConfigComponent, index) => { + return ( + + + + ); + })} + + + + + + + + + + + + +
+ ); + + return ( + + {body} + + ); +}; + +export default ServiceConfigModal; \ No newline at end of file diff --git a/.internal/wui/src/features/serviceUiControls/general/logging.jsx b/.internal/wui/src/features/serviceUiControls/general/logging.jsx new file mode 100644 index 000000000..0df6b1ff1 --- /dev/null +++ b/.internal/wui/src/features/serviceUiControls/general/logging.jsx @@ -0,0 +1,64 @@ +import React, { Fragment, useState, useEffect } from 'react'; +// import Box from '@material-ui/core/Box'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Checkbox from '@material-ui/core/Checkbox'; +import Box from '@material-ui/core/Box'; + +const PortConfig = (props) => { + + const { + serviceConfigOptions, + serviceName, + setBuildOptions, + getBuildOptions, + buildOptionsInit, + setServiceOptions, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions, + serviceTemplates, + onChange + } = props; + + const tempBuildOptions = getTemporaryBuildOptions(); + + const [loggingEnabled, setLoggingEnabled] = useState(getBuildOptions()?.services?.[serviceName]?.loggingEnabled ?? true); + useEffect(() => { + setTemporaryServiceOptions(serviceName, { + ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {}, + loggingEnabled + }); + }, [ + loggingEnabled + ]); + + const onChangeCb = (event) => { + const newSetting = event.target.checked; + setLoggingEnabled(newSetting); + if (typeof(onChange) === 'function') { + onChange(newSetting); + } + }; + + return ( + + + onChangeCb(evt) } + name={"logging"} + color="primary" + /> + } + label={`Enable Logging for ${serviceName}`} + /> + + + ); +}; + +export default PortConfig; diff --git a/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx b/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx new file mode 100644 index 000000000..192b11be7 --- /dev/null +++ b/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx @@ -0,0 +1,97 @@ +import React, { Fragment, useState, useEffect } from 'react'; +// import Box from '@material-ui/core/Box'; +import Grid from '@material-ui/core/Grid'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Checkbox from '@material-ui/core/Checkbox'; + +const NetworkConfig = (props) => { + const { + serviceConfigOptions, + serviceName, + setBuildOptions, + getBuildOptions, + buildOptionsInit, + setServiceOptions, + networkTemplateList, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions, + serviceTemplates, + onChange + } = props; + + const tempBuildOptions = getTemporaryBuildOptions(); + + const [modifiedNetworkList, setModifiedNetworkList] = useState({}); + useEffect(() => { + const defaultOnNetworks = { ...getBuildOptions()?.services?.[serviceName]?.networks ?? {} }; + serviceTemplates[serviceName]?.networks?.forEach((networkName) => { + defaultOnNetworks[networkName] = true; + }); + setModifiedNetworkList({ + ...defaultOnNetworks + }); + }, []); + + useEffect(() => { + setTemporaryServiceOptions(serviceName, { + ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {}, + networks: modifiedNetworkList + }); + }, [ + modifiedNetworkList + ]); + + const onChangeCb = (networkName, event) => { + const networkSelected = event.target.checked; + setModifiedNetworkList({ + ...modifiedNetworkList, + [networkName]: networkSelected + }); + if (typeof(onChange) === 'function') { + onChange(networkName, networkName); + } + }; + + const defaultValue = (networkName) => { + return (serviceTemplates[serviceName]?.networks ?? []).includes(networkName); + }; + + return ( + + IOTstack Networks: + + {(networkTemplateList?.payload ?? []).map((networkName) => { + return ( + + onChangeCb(networkName, evt) } + name={networkName} + color="primary" + /> + } + label={networkName} + /> + + ); + }).filter((ele) => { + return ele !== null; + })} + + + ); +}; + +export default NetworkConfig; diff --git a/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx b/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx new file mode 100644 index 000000000..48dd5e21e --- /dev/null +++ b/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx @@ -0,0 +1,91 @@ +import React, { Fragment, useState, useEffect } from 'react'; +// import Box from '@material-ui/core/Box'; +import Grid from '@material-ui/core/Grid'; +import TextField from '@material-ui/core/TextField'; +import { + getExternalPort, + replaceExternalPort, + getInternalPort +} from '../../../utils/parsers'; + +const PortConfig = (props) => { + + const { + serviceConfigOptions, + serviceName, + setBuildOptions, + getBuildOptions, + buildOptionsInit, + setServiceOptions, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions, + serviceTemplates, + onChange + } = props; + + const tempBuildOptions = getTemporaryBuildOptions(); + + const [portSettings, setPortSettings] = useState(getBuildOptions()?.services?.[serviceName]?.ports || {}); + useEffect(() => { + setTemporaryServiceOptions(serviceName, { + ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {}, + ports: portSettings + }); + }, [ + portSettings + ]); + + const onChangeCb = (portKey, portLabelValue, event) => { + const newPort = event.target.value; + // const defaultTemplatePort = defaultValue(portKey, portKey); + setPortSettings({ + ...portSettings, + [portKey]: replaceExternalPort((portSettings[portKey] || portKey), newPort) + }); + if (typeof(onChange) === 'function') { + onChange(portKey, portLabelValue, newPort); + } + }; + + const defaultValue = (portValueKey, defaultValue) => { + const servicePorts = tempBuildOptions?.services?.[serviceName] ?? {}; + return servicePorts?.ports?.[portValueKey] ?? defaultValue; + }; + + return ( + + + {serviceConfigOptions && Object.keys(serviceConfigOptions.labeledPorts).map((portValueKey) => { + const currentPortSetting = portSettings[portValueKey] || defaultValue(portValueKey, portValueKey); + if ((serviceTemplates[serviceName]?.ports?.[portValueKey] ?? []).indexOf(portValueKey)) { // Only show ports that exist in the YAML template + return ( + + { onChangeCb(portValueKey, serviceConfigOptions.labeledPorts[portValueKey], event) }} + value={getExternalPort(currentPortSetting)} + /> + + ); + } + + return null; + }).filter((ele) => { + return ele !== null; + })} + + + ); +}; + +export default PortConfig; diff --git a/.internal/wui/src/features/serviceUiControls/index.js b/.internal/wui/src/features/serviceUiControls/index.js new file mode 100644 index 000000000..3949bc9f3 --- /dev/null +++ b/.internal/wui/src/features/serviceUiControls/index.js @@ -0,0 +1,9 @@ +import PortConfig from './general/portConfig'; +import NetworkConfig from './general/networkConfig'; +import Logging from './general/logging'; + +export default { + PortConfig, + NetworkConfig, + Logging +}; diff --git a/.internal/wui/src/features/servicesGridItem/index.jsx b/.internal/wui/src/features/servicesGridItem/index.jsx new file mode 100644 index 000000000..846f8a75a --- /dev/null +++ b/.internal/wui/src/features/servicesGridItem/index.jsx @@ -0,0 +1,354 @@ +import React, { Fragment, useState, useEffect } from 'react'; +import { useDispatch, useSelector } from "react-redux"; +import Box from '@material-ui/core/Box'; +import Tooltip from '@material-ui/core/Tooltip'; +import Skeleton from '@material-ui/lab/Skeleton'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Checkbox from '@material-ui/core/Checkbox'; +import Button from '@material-ui/core/Button'; +import Link from '@material-ui/core/Link'; +import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined'; +import { makeStyles } from '@material-ui/core/styles'; +import ServiceConfigModal from '../serviceConfigModal'; +import { useTheme } from '@material-ui/core/styles'; +import { + getBuildIssuesAction +} from '../../actions/checkBuildIssues.action'; +import { + getServiceMetadataAction +} from '../../actions/getServiceMetadata.action'; +import { + getServiceConfigOptionsAction +} from '../../actions/getServiceConfigOptions.action'; +import { + addSelectedService, + removeSelectedService +} from '../../actions/updateSelectedServices.action'; +import styles from './services-grid-item.module.css'; + +const mapDispatchToProps = (dispatch) => { + return { + dispatchGetServiceMetadata: (serviceName) => dispatch(getServiceMetadataAction(serviceName)), + dispatchGetServiceConfigOptions: (serviceName) => dispatch(getServiceConfigOptionsAction(serviceName)), + dispatchGetBuildIssues: (selectedServices, serviceConfigurations) => dispatch(getBuildIssuesAction(selectedServices, serviceConfigurations)), + dispatchAddSelectedService: (serviceName) => dispatch(addSelectedService(serviceName)), + dispatchRemoveSelectedService: (serviceName) => dispatch(removeSelectedService(serviceName)) + }; +}; + +const mapStateToProps = (selector) => { + return { + templateList: selector(state => state.templateList), + configServiceMetadata: selector(state => state.configServiceMetadata), + configServiceConfigOptions: selector(state => state.configServiceConfigOptions), + hideServiceTags: selector(state => state.hideServiceTags), + selectedServices: selector(state => state.selectedServices), + buildIssues: selector(state => state.buildIssues) + }; +}; + +const useStyles = makeStyles({ + serviceCard: { + "&:hover": { + borderColor: ({ theme }) => theme.palette.text.primary + } + } +}); + +const ServiceItem = (props) => { + const theme = useTheme(); + const classes = useStyles({ props, theme }); + // console.log('theme.palette', theme.palette) + props = { + ...props, + ...mapDispatchToProps(useDispatch()), + ...mapStateToProps(useSelector) + }; + + const { + serviceName, + networkTemplateList, + serviceTemplates, + dispatchGetServiceMetadata, + dispatchGetServiceConfigOptions, + dispatchAddSelectedService, + dispatchRemoveSelectedService, + dispatchGetBuildIssues, + configServiceMetadata, + configServiceConfigOptions, + selectedServices, + hideServiceTags, + buildIssues, + buildOptions, + setBuildOptions, + getBuildOptions, + buildOptionsInit, + setServiceOptions, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions + } = props; + + const [isLoading, setIsLoading] = useState(false); + const [serviceMetadata, setServiceMetadata] = useState({}); + const [serviceMetadataError, setServiceMetadataError] = useState({}); + useEffect(() => { + if ( + typeof configServiceMetadata.services.completed[serviceName] === 'undefined' + && typeof configServiceMetadata.services.failed[serviceName] === 'undefined' + && !configServiceMetadata.services.pending.includes(serviceName) + && !isLoading + ) { + setIsLoading(true); + return void dispatchGetServiceMetadata(serviceName); + } + + setIsLoading(false); + + if (typeof configServiceMetadata.services.completed[serviceName] === 'object') { + setServiceMetadata(configServiceMetadata.services.completed[serviceName].payload); + } else if (!configServiceMetadata.services.pending.includes(serviceName)) { + setServiceMetadataError({ + hasError: true + }); + } + }, [ + isLoading, + serviceName, + dispatchGetServiceMetadata, + configServiceMetadata.services.completed, + configServiceMetadata.services.pending, + configServiceMetadata.services.failed + ]); + + const [serviceConfigOptions, setServiceConfigOptions] = useState({}); + const [serviceConfigOptionsError, setServiceConfigOptionsError] = useState({}); + useEffect(() => { + if ( + typeof configServiceConfigOptions.services.completed[serviceName] === 'undefined' + && typeof configServiceConfigOptions.services.failed[serviceName] === 'undefined' + && !configServiceConfigOptions.services.pending.includes(serviceName) + && !isLoading + ) { + setIsLoading(true); + return void dispatchGetServiceConfigOptions(serviceName); + } + + // setIsLoading(false); + + if (typeof configServiceConfigOptions.services.completed[serviceName] === 'object') { + setServiceConfigOptions(configServiceConfigOptions.services.completed[serviceName].payload); + } else if (!configServiceConfigOptions.services.pending.includes(serviceName)) { + setServiceConfigOptionsError({ + hasError: true + }); + } + }, [ + isLoading, + serviceName, + dispatchGetServiceConfigOptions, + configServiceConfigOptions.services.completed, + configServiceConfigOptions.services.pending, + configServiceConfigOptions.services.failed + ]); + + const [updated, setIsUpdated] = useState(false); + useEffect(() => { + if (updated) { + dispatchGetBuildIssues(selectedServices.selectedServices, {}); + } + setIsUpdated(false); + }, [ + updated, + serviceName, + selectedServices.selectedServices, + dispatchGetBuildIssues + ]); + + const [hasIssue, setHasIssue] = useState(false); + useEffect(() => { + if (!selectedServices.selectedServices.includes(serviceName)) { + return void setHasIssue(false); + } + const issueList = buildIssues?.payload?.issueList ?? {}; + if (Array.isArray(issueList.services)) { + issueList.services.forEach((service) => { + if (service.name === serviceName) { + return void setHasIssue(true); + } + }); + } + }, [buildIssues, selectedServices.selectedServices, serviceName]); + + const handleBuildSelectChange = (evt) => { + setIsUpdated(true); + if (evt.target.checked) { + return dispatchAddSelectedService(serviceName); + } + return dispatchRemoveSelectedService(serviceName); + } + + const [modalOpen, setModalOpen] = useState(false); + + const serviceComponent = () => { + return ( + + setModalOpen(false)} + serviceMetadata={serviceMetadata} + serviceConfigOptions={serviceConfigOptions} + serviceName={serviceName} + buildOptions={buildOptions} + setBuildOptions={setBuildOptions} + setServiceOptions={setServiceOptions} + getBuildOptions={getBuildOptions} + buildOptionsInit={buildOptionsInit} + setTemporaryBuildOptions={setTemporaryBuildOptions} + getTemporaryBuildOptions={getTemporaryBuildOptions} + setTemporaryServiceOptions={setTemporaryServiceOptions} + setupTemporaryBuildOptions={setupTemporaryBuildOptions} + saveTemporaryBuildOptions={saveTemporaryBuildOptions} + networkTemplateList={networkTemplateList} + serviceTemplates={serviceTemplates} + /> + {serviceMetadata.displayName} + + {!serviceMetadata.iconUri + && ( + + + + )} + {serviceMetadata.iconUri + && ( + +
+ {`${serviceMetadata.displayName} +
+
+ )} +
+ + + + + + } + label={`Add ${serviceMetadata.displayName} to build`} + /> + + + + {serviceMetadata.displayName} Help and Docs + + +
+ ) + }; + + const errorComponent = () => { + return ( + +
Error loading: {serviceName}
+
Try refreshing, and ensuring the API server is running correctly.
+
+ ) + }; + + const loadingComponent = () => { + return ( + + Loading '{serviceName}' metadata... + + + + + + + + + + + + + + ) + }; + + const highlightClass = () => { + if (selectedServices.selectedServices.includes(serviceName)) { + if (hasIssue) { + return styles.serviceError; + } else { + return styles.selectedForBuild; + } + } + + return ''; + }; + + const tagIsHidden = (hiddenTags, serviceTags) => { + let hide = false; + + hiddenTags.forEach((hiddenTag) => { + serviceTags.forEach((serviceTag) => { + if (hiddenTag === serviceTag) { + hide = true; + } + }); + }); + + return hide; + } + + if (!isLoading && tagIsHidden(hideServiceTags.hideServiceTags, serviceMetadata.serviceTypeTags)) { + return null; + } + + return ( + + + {isLoading + && (loadingComponent())} + {!isLoading + && serviceMetadata.displayName + && ( + serviceComponent() + )} + {!isLoading + && serviceMetadataError.hasError === true + && ( + errorComponent() + )} + + + ); +}; + +export default ServiceItem; diff --git a/.internal/wui/src/features/servicesGridItem/services-grid-item.module.css b/.internal/wui/src/features/servicesGridItem/services-grid-item.module.css new file mode 100644 index 000000000..c922af44c --- /dev/null +++ b/.internal/wui/src/features/servicesGridItem/services-grid-item.module.css @@ -0,0 +1,34 @@ +.docsLink { + background: linear-gradient(45deg, #2196F3 30%, #04add3 90%); + box-shadow: 0 3px 5px 2px rgba(33, 203, 243, .3); + color: 'white'; + padding: 0.5rem; +} + +.selectedForBuild { + background: linear-gradient(45deg, #76c01644 30%, #04d35a44 90%); +} + +.buildIssue { + background: linear-gradient(45deg, #ff7b008c 30%, #ffee00a8 90%); +} + +.serviceError { + background: linear-gradient(45deg, #c016167f 30%, #d304047f 90%); +} + +.serviceCard { + width: 24rem; + height: 24rem; + /* border-color: "primary.main"; */ +} + +.serviceIconContainer { + height: 6rem +} + +.serviceIcon { + height: 6rem; + width: auto; +} + diff --git a/.internal/wui/src/index.css b/.internal/wui/src/index.css new file mode 100644 index 000000000..bd5bd6d57 --- /dev/null +++ b/.internal/wui/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/.internal/wui/src/index.js b/.internal/wui/src/index.js new file mode 100644 index 000000000..41c478d64 --- /dev/null +++ b/.internal/wui/src/index.js @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; +import store from './reducers'; +import { Provider } from 'react-redux'; + +ReactDOM.render( + + + + + , + document.getElementById('root') +); diff --git a/.internal/wui/src/logo.svg b/.internal/wui/src/logo.svg new file mode 100644 index 000000000..9e9633482 --- /dev/null +++ b/.internal/wui/src/logo.svg @@ -0,0 +1 @@ + diff --git a/.internal/wui/src/pages/buildHistory/index.jsx b/.internal/wui/src/pages/buildHistory/index.jsx new file mode 100644 index 000000000..93b045eed --- /dev/null +++ b/.internal/wui/src/pages/buildHistory/index.jsx @@ -0,0 +1,63 @@ +// import React, { Fragment, useState, useEffect } from 'react'; +import React, { Fragment, useEffect } from 'react'; +import { useDispatch, useSelector } from "react-redux"; +import Grid from '@material-ui/core/Grid'; +import BuildHistoryGridItem from '../../features/buildHistoryGridItem' +import { + getBuildHistoryListAction +} from '../../actions/getBuildHistoryList.action'; + +const mapDispatchToProps = (dispatch) => { + return { + dispatchGetBuildHistoryList: () => dispatch(getBuildHistoryListAction()) + }; +}; + +const mapStateToProps = (selector) => { + return { + buildHistory: selector(state => state.buildHistory) + }; +}; + +const Main = (props) => { + + props = { + ...props, + ...mapDispatchToProps(useDispatch()), + ...mapStateToProps(useSelector) + }; + + const { dispatchGetBuildHistoryList, buildHistory } = props; + + useEffect(() => { + dispatchGetBuildHistoryList(); + }, []); + + return ( + +
+ + {typeof buildHistory.payload !== 'undefined' && Object.keys(buildHistory.payload.buildsList).map((buildDetailsTime) => { + return ( + + + + ); + })} + +
+
+ ); +} + +export default Main; diff --git a/.internal/wui/src/pages/help/index.jsx b/.internal/wui/src/pages/help/index.jsx new file mode 100644 index 000000000..38474d37d --- /dev/null +++ b/.internal/wui/src/pages/help/index.jsx @@ -0,0 +1,13 @@ +import React, { Fragment } from 'react'; + +const Help = () => { + return ( + +
+ Not completed - Help +
+
+ ); +} + +export default Help; diff --git a/.internal/wui/src/pages/mainBuild/index.jsx b/.internal/wui/src/pages/mainBuild/index.jsx new file mode 100644 index 000000000..51726aebf --- /dev/null +++ b/.internal/wui/src/pages/mainBuild/index.jsx @@ -0,0 +1,111 @@ +// import React, { Fragment, useState, useEffect } from 'react'; +import React, { Fragment, useEffect } from 'react'; +import { useDispatch, useSelector } from "react-redux"; +import Grid from '@material-ui/core/Grid'; +import Box from '@material-ui/core/Box'; +import ServiceGridItem from '../../features/servicesGridItem'; +import BuildSidebar from '../../features/BuildSidebar'; +import { getServiceTemplateListAction } from '../../actions/getServiceTemplateList.action'; +import { getServiceTemplatesAction } from '../../actions/getServiceTemplates.action'; +import { getNetworkTemplateListAction } from '../../actions/getNetworkTemplateList.action'; +import { + getBuildOptions, + setBuildOptions, + buildOptionsInit, + setServiceOptions, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions +} from '../../utils/buildOptionSync'; + +const mapDispatchToProps = (dispatch) => { + return { + dispatchGetServiceTemplatesList: () => dispatch(getServiceTemplateListAction()), + dispatchGetNetworkTemplatesList: () => dispatch(getNetworkTemplateListAction()), + dispatchGetServiceTemplates: () => dispatch(getServiceTemplatesAction()) + }; +}; + +const mapStateToProps = (selector) => { + return { + serviceTemplateList: selector(state => state.serviceTemplateList), + networkTemplateList: selector(state => state.networkTemplateList), + serviceTemplates: selector(state => state.serviceTemplates) + }; +}; + +const Main = (props) => { + props = { + ...props, + ...mapDispatchToProps(useDispatch()), + ...mapStateToProps(useSelector) + }; + + const { + dispatchGetServiceTemplatesList, + dispatchGetNetworkTemplatesList, + dispatchGetServiceTemplates, + serviceTemplateList, + networkTemplateList, + serviceTemplates + } = props; + const buildOptions = getBuildOptions(); + + useEffect(() => { + dispatchGetServiceTemplatesList(); + dispatchGetNetworkTemplatesList(); + dispatchGetServiceTemplates(); + }, []); + + return ( + +
+ + + + {Array.isArray(serviceTemplateList.payload) && serviceTemplateList.payload.map((templateName) => { + return ( + + + + ); + })} + + + + + + + +
+
+ ); +}; + +export default Main; diff --git a/.internal/wui/src/pages/notFound/index.js b/.internal/wui/src/pages/notFound/index.js new file mode 100644 index 000000000..0d9f0174e --- /dev/null +++ b/.internal/wui/src/pages/notFound/index.js @@ -0,0 +1,13 @@ +import React, { Fragment } from 'react'; + +const NotFound = () => { + return ( + +
+ Page not found +
+
+ ); +} + +export default NotFound; diff --git a/.internal/wui/src/pages/scripts/index.jsx b/.internal/wui/src/pages/scripts/index.jsx new file mode 100644 index 000000000..8b86ea72f --- /dev/null +++ b/.internal/wui/src/pages/scripts/index.jsx @@ -0,0 +1,13 @@ +import React, { Fragment } from 'react'; + +const Scripts = () => { + return ( + +
+ Not completed - Scripts +
+
+ ); +} + +export default Scripts; diff --git a/.internal/wui/src/reducers/buildStackReducer.js b/.internal/wui/src/reducers/buildStackReducer.js new file mode 100644 index 000000000..5c65cc38e --- /dev/null +++ b/.internal/wui/src/reducers/buildStackReducer.js @@ -0,0 +1,39 @@ +import { API_STATUS } from '../constants' +import { CREATE_AND_BUILD_STACK } from '../actions/buildStack.action'; + +const defaultState = { + status: API_STATUS.UNINIT +}; + +const reducerHandler = (state = defaultState, action) => { + switch (action.type) { + case `${CREATE_AND_BUILD_STACK}_${API_STATUS.PENDING}`: + return { + ...state, + status: API_STATUS.PENDING + } + + case `${CREATE_AND_BUILD_STACK}_${API_STATUS.SUCCESS}`: + return { + ...state, + status: API_STATUS.SUCCESS, + payload: action.res + } + + case `${CREATE_AND_BUILD_STACK}_${API_STATUS.FAILURE}`: + return { + ...state, + status: API_STATUS.FAILURE, + payload: undefined, + error: action.error + } + default: + return state + } +}; + +export default reducerHandler; + +export const getBuildStackSelector = (state) => { + return state.buildStack +}; diff --git a/.internal/wui/src/reducers/counter.js b/.internal/wui/src/reducers/counter.js new file mode 100644 index 000000000..01dcfe06b --- /dev/null +++ b/.internal/wui/src/reducers/counter.js @@ -0,0 +1,42 @@ +import { createSlice } from '@reduxjs/toolkit'; + +export const counterSlice = createSlice({ + name: 'counter', + initialState: { + value: 0, + }, + reducers: { + increment: state => { + // Redux Toolkit allows us to write "mutating" logic in reducers. It + // doesn't actually mutate the state because it uses the Immer library, + // which detects changes to a "draft state" and produces a brand new + // immutable state based off those changes + state.value += 1; + }, + decrement: state => { + state.value -= 1; + }, + incrementByAmount: (state, action) => { + state.value += action.payload; + }, + }, +}); + +export const { increment, decrement, incrementByAmount } = counterSlice.actions; + +// The function below is called a thunk and allows us to perform async logic. It +// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This +// will call the thunk with the `dispatch` function as the first argument. Async +// code can then be executed and other actions can be dispatched +export const incrementAsync = amount => dispatch => { + setTimeout(() => { + dispatch(incrementByAmount(amount)); + }, 1000); +}; + +// The function below is called a selector and allows us to select a value from +// the state. Selectors can also be defined inline where they're used instead of +// in the slice file. For example: `useSelector((state) => state.counter.value)` +export const selectCount = state => state.counter.value; + +export default counterSlice.reducer; diff --git a/.internal/wui/src/reducers/getBuildHistoryListReducer.js b/.internal/wui/src/reducers/getBuildHistoryListReducer.js new file mode 100644 index 000000000..fcf264100 --- /dev/null +++ b/.internal/wui/src/reducers/getBuildHistoryListReducer.js @@ -0,0 +1,39 @@ +import { API_STATUS } from '../constants' +import { GET_BUILD_HISTORY_LIST_ACTION } from '../actions/getBuildHistoryList.action'; + +const defaultState = { + status: API_STATUS.UNINIT +}; + +const reducerHandler = (state = defaultState, action) => { + switch (action.type) { + case `${GET_BUILD_HISTORY_LIST_ACTION}_${API_STATUS.PENDING}`: + return { + ...state, + status: API_STATUS.PENDING + } + + case `${GET_BUILD_HISTORY_LIST_ACTION}_${API_STATUS.SUCCESS}`: + return { + ...state, + status: API_STATUS.SUCCESS, + payload: action.res + } + + case `${GET_BUILD_HISTORY_LIST_ACTION}_${API_STATUS.FAILURE}`: + return { + ...state, + status: API_STATUS.FAILURE, + payload: undefined, + error: action.error + } + default: + return state + } +}; + +export default reducerHandler; + +export const getBuildHistoryListSelector = (state) => { + return state.buildHistory +}; diff --git a/.internal/wui/src/reducers/getBuildIssuesReducer.js b/.internal/wui/src/reducers/getBuildIssuesReducer.js new file mode 100644 index 000000000..44cb600bf --- /dev/null +++ b/.internal/wui/src/reducers/getBuildIssuesReducer.js @@ -0,0 +1,39 @@ +import { API_STATUS } from '../constants' +import { CHECK_BUILD_ISSUES } from '../actions/checkBuildIssues.action'; + +const defaultState = { + status: API_STATUS.UNINIT +}; + +const reducerHandler = (state = defaultState, action) => { + switch (action.type) { + case `${CHECK_BUILD_ISSUES}_${API_STATUS.PENDING}`: + return { + ...state, + status: API_STATUS.PENDING + } + + case `${CHECK_BUILD_ISSUES}_${API_STATUS.SUCCESS}`: + return { + ...state, + status: API_STATUS.SUCCESS, + payload: action.res + } + + case `${CHECK_BUILD_ISSUES}_${API_STATUS.FAILURE}`: + return { + ...state, + status: API_STATUS.FAILURE, + payload: undefined, + error: action.error + } + default: + return state + } +}; + +export default reducerHandler; + +export const getBuildIssuesSelector = (state) => { + return state.buildIssues +}; diff --git a/.internal/wui/src/reducers/getNetworkTemplateListReducer.js b/.internal/wui/src/reducers/getNetworkTemplateListReducer.js new file mode 100644 index 000000000..0fc9cb38f --- /dev/null +++ b/.internal/wui/src/reducers/getNetworkTemplateListReducer.js @@ -0,0 +1,39 @@ +import { API_STATUS } from '../constants' +import { GET_NETWORK_TEMPLATE_LIST_ACTION } from '../actions/getNetworkTemplateList.action'; + +const defaultState = { + status: API_STATUS.UNINIT +}; + +const reducerHandler = (state = defaultState, action) => { + switch (action.type) { + case `${GET_NETWORK_TEMPLATE_LIST_ACTION}_${API_STATUS.PENDING}`: + return { + ...state, + status: API_STATUS.PENDING + } + + case `${GET_NETWORK_TEMPLATE_LIST_ACTION}_${API_STATUS.SUCCESS}`: + return { + ...state, + status: API_STATUS.SUCCESS, + payload: action.res + } + + case `${GET_NETWORK_TEMPLATE_LIST_ACTION}_${API_STATUS.FAILURE}`: + return { + ...state, + status: API_STATUS.FAILURE, + payload: undefined, + error: action.error + } + default: + return state + } +}; + +export default reducerHandler; + +export const getNetworkTemplateListSelector = (state) => { + return state.networkTemplateList +}; diff --git a/.internal/wui/src/reducers/getScriptTemplatesReducer.js b/.internal/wui/src/reducers/getScriptTemplatesReducer.js new file mode 100644 index 000000000..669ed5202 --- /dev/null +++ b/.internal/wui/src/reducers/getScriptTemplatesReducer.js @@ -0,0 +1,57 @@ +import { API_STATUS } from '../constants' +import { GET_SCRIPT_TEMPLATE } from '../actions/getScript.action'; + +const defaultState = { + scripts: { + pending: [], + failed: {}, + completed: {} + } +}; + +const reducerHandler = (state = defaultState, action) => { + const newState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case `${GET_SCRIPT_TEMPLATE}_${API_STATUS.PENDING}`: + if (state.scripts.pending.indexOf(action.label) > -1) { + console.warn(`getScriptTemplatesReducer: '${action.label}' already dispatched`, action); + } + newState.scripts.pending.push(action.label); + delete newState.scripts.completed[action.label]; + delete newState.scripts.failed[action.label]; + return { + ...state, + ...newState + } + + case `${GET_SCRIPT_TEMPLATE}_${API_STATUS.SUCCESS}`: + newState.scripts.completed[action.label] = { + status: API_STATUS.SUCCESS, + payload: action.res + }; + delete newState.scripts.failed[action.label]; + newState.scripts.pending.splice(newState.scripts.pending.indexOf(action.label), 1); + return { + ...state, + ...newState + } + + case `${GET_SCRIPT_TEMPLATE}_${API_STATUS.FAILURE}`: + newState.scripts.failed[action.label] = { + status: API_STATUS.FAILURE, + payload: undefined, + error: JSON.stringify(action.error, Object.getOwnPropertyNames(action.error)) + }; + delete newState.scripts.completed[action.label]; + newState.scripts.pending.splice(newState.scripts.pending.indexOf(action.label), 1); + return { + ...state, + ...newState + } + + default: + return state + } +}; + +export default reducerHandler; diff --git a/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js b/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js new file mode 100644 index 000000000..795bbcf34 --- /dev/null +++ b/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js @@ -0,0 +1,61 @@ +import { API_STATUS } from '../constants' +import { GET_CONFIG_SERVICE_CONFIG_OPTIONS } from '../actions/getServiceConfigOptions.action'; + +const defaultState = { + services: { + pending: [], + failed: {}, + completed: {} + } +}; + +const reducerHandler = (state = defaultState, action) => { + const newState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case `${GET_CONFIG_SERVICE_CONFIG_OPTIONS}_${API_STATUS.PENDING}`: + if (state.services.pending.indexOf(action.label) > -1) { + console.warn(`getServiceConfigOptionsReducer: '${action.label}' already dispatched`, action); + } + newState.services.pending.push(action.label); + delete newState.services.completed[action.label]; + delete newState.services.failed[action.label]; + return { + ...state, + ...newState + } + + case `${GET_CONFIG_SERVICE_CONFIG_OPTIONS}_${API_STATUS.SUCCESS}`: + newState.services.completed[action.label] = { + status: API_STATUS.SUCCESS, + payload: action.res + }; + delete newState.services.failed[action.label]; + newState.services.pending.splice(newState.services.pending.indexOf(action.label), 1); + return { + ...state, + ...newState + } + + case `${GET_CONFIG_SERVICE_CONFIG_OPTIONS}_${API_STATUS.FAILURE}`: + newState.services.failed[action.label] = { + status: API_STATUS.FAILURE, + payload: undefined, + error: JSON.stringify(action.error, Object.getOwnPropertyNames(action.error)) + }; + delete newState.services.completed[action.label]; + newState.services.pending.splice(newState.services.pending.indexOf(action.label), 1); + return { + ...state, + ...newState + } + + default: + return state + } +}; + +export default reducerHandler; + +export const getConfigServiceConfigOptionsSelector = (state) => { + return state.configServiceConfigOptionsSelector +}; diff --git a/.internal/wui/src/reducers/getServiceMetadataReducer.js b/.internal/wui/src/reducers/getServiceMetadataReducer.js new file mode 100644 index 000000000..4132f2725 --- /dev/null +++ b/.internal/wui/src/reducers/getServiceMetadataReducer.js @@ -0,0 +1,61 @@ +import { API_STATUS } from '../constants' +import { GET_CONFIG_SERVICE_METADATA } from '../actions/getServiceMetadata.action'; + +const defaultState = { + services: { + pending: [], + failed: {}, + completed: {} + } +}; + +const reducerHandler = (state = defaultState, action) => { + const newState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case `${GET_CONFIG_SERVICE_METADATA}_${API_STATUS.PENDING}`: + if (state.services.pending.indexOf(action.label) > -1) { + console.warn(`getServiceMetadataReducer: '${action.label}' already dispatched`, action); + } + newState.services.pending.push(action.label); + delete newState.services.completed[action.label]; + delete newState.services.failed[action.label]; + return { + ...state, + ...newState + } + + case `${GET_CONFIG_SERVICE_METADATA}_${API_STATUS.SUCCESS}`: + newState.services.completed[action.label] = { + status: API_STATUS.SUCCESS, + payload: action.res + }; + delete newState.services.failed[action.label]; + newState.services.pending.splice(newState.services.pending.indexOf(action.label), 1); + return { + ...state, + ...newState + } + + case `${GET_CONFIG_SERVICE_METADATA}_${API_STATUS.FAILURE}`: + newState.services.failed[action.label] = { + status: API_STATUS.FAILURE, + payload: undefined, + error: JSON.stringify(action.error, Object.getOwnPropertyNames(action.error)) + }; + delete newState.services.completed[action.label]; + newState.services.pending.splice(newState.services.pending.indexOf(action.label), 1); + return { + ...state, + ...newState + } + + default: + return state + } +}; + +export default reducerHandler; + +export const getConfigServiceMetadataSelector = (state) => { + return state.configServiceMetadataSelector +}; diff --git a/.internal/wui/src/reducers/getServiceTemplateListReducer.js b/.internal/wui/src/reducers/getServiceTemplateListReducer.js new file mode 100644 index 000000000..2f9311863 --- /dev/null +++ b/.internal/wui/src/reducers/getServiceTemplateListReducer.js @@ -0,0 +1,39 @@ +import { API_STATUS } from '../constants' +import { GET_SERVICE_TEMPLATE_LIST_ACTION } from '../actions/getServiceTemplateList.action'; + +const defaultState = { + status: API_STATUS.UNINIT +}; + +const reducerHandler = (state = defaultState, action) => { + switch (action.type) { + case `${GET_SERVICE_TEMPLATE_LIST_ACTION}_${API_STATUS.PENDING}`: + return { + ...state, + status: API_STATUS.PENDING + } + + case `${GET_SERVICE_TEMPLATE_LIST_ACTION}_${API_STATUS.SUCCESS}`: + return { + ...state, + status: API_STATUS.SUCCESS, + payload: action.res + } + + case `${GET_SERVICE_TEMPLATE_LIST_ACTION}_${API_STATUS.FAILURE}`: + return { + ...state, + status: API_STATUS.FAILURE, + payload: undefined, + error: action.error + } + default: + return state + } +}; + +export default reducerHandler; + +export const getServiceTemplateListSelector = (state) => { + return state.serviceTemplateList +}; diff --git a/.internal/wui/src/reducers/getServiceTemplatesReducer.js b/.internal/wui/src/reducers/getServiceTemplatesReducer.js new file mode 100644 index 000000000..402e7f69c --- /dev/null +++ b/.internal/wui/src/reducers/getServiceTemplatesReducer.js @@ -0,0 +1,40 @@ +import { API_STATUS } from '../constants' +import { GET_SERVICE_TEMPLATES_ACTION } from '../actions/getServiceTemplates.action'; + +const defaultState = { + status: API_STATUS.UNINIT, + payload: {} +}; + +const reducerHandler = (state = defaultState, action) => { + switch (action.type) { + case `${GET_SERVICE_TEMPLATES_ACTION}_${API_STATUS.PENDING}`: + return { + ...state, + status: API_STATUS.PENDING + } + + case `${GET_SERVICE_TEMPLATES_ACTION}_${API_STATUS.SUCCESS}`: + return { + ...state, + status: API_STATUS.SUCCESS, + payload: action.res + } + + case `${GET_SERVICE_TEMPLATES_ACTION}_${API_STATUS.FAILURE}`: + return { + ...state, + status: API_STATUS.FAILURE, + payload: undefined, + error: action.error + } + default: + return state + } +}; + +export default reducerHandler; + +export const getServiceTemplatesSelector = (state) => { + return state.serviceTemplates +}; diff --git a/.internal/wui/src/reducers/index.js b/.internal/wui/src/reducers/index.js new file mode 100644 index 000000000..51265c83a --- /dev/null +++ b/.internal/wui/src/reducers/index.js @@ -0,0 +1,37 @@ +import { configureStore } from '@reduxjs/toolkit'; +import thunk from 'redux-thunk'; +import promiseMiddleware from './middlewares/promiseMiddleware'; +import asyncDispatchMiddleware from './middlewares/asyncDispatchMiddleware'; +import counterReducer from './counter'; +import serviceTemplateList from './getServiceTemplateListReducer'; +import serviceTemplates from './getServiceTemplatesReducer'; +import networkTemplateList from './getNetworkTemplateListReducer'; +import configServiceMetadata from './getServiceMetadataReducer'; +import configServiceConfigOptions from './getServiceConfigOptionsReducer'; +import selectedServices from './updateSelectedServicesReducer'; +import hideServiceTags from './updateSelectedFilterTagsReducer'; +import buildIssues from './getBuildIssuesReducer'; +import buildStack from './buildStackReducer'; +import buildHistory from './getBuildHistoryListReducer'; +import scriptTemplates from './getScriptTemplatesReducer'; + + +const middlewares = [thunk, promiseMiddleware, asyncDispatchMiddleware]; + +export default configureStore({ + reducer: { + counter: counterReducer, + serviceTemplateList: serviceTemplateList, + networkTemplateList: networkTemplateList, + serviceTemplates: serviceTemplates, + configServiceMetadata: configServiceMetadata, + configServiceConfigOptions: configServiceConfigOptions, + selectedServices: selectedServices, + buildHistory: buildHistory, + hideServiceTags: hideServiceTags, + buildIssues: buildIssues, + buildStack: buildStack, + scriptTemplates: scriptTemplates + }, + middleware: middlewares +}); diff --git a/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js b/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js new file mode 100644 index 000000000..a1d3a2c47 --- /dev/null +++ b/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js @@ -0,0 +1,25 @@ +const asyncDispatchMiddleware = store => next => action => { + let syncActivityFinished = false; + let actionQueue = []; + + const flushQueue = () => { + actionQueue.forEach(a => store.dispatch(a)); // flush queue + actionQueue = []; + } + + const asyncDispatch = (asyncAction) => { + actionQueue = actionQueue.concat([asyncAction]); + + if (syncActivityFinished) { + flushQueue(); + } + } + + const actionWithAsyncDispatch = Object.assign({}, action, { asyncDispatch }); + + next(actionWithAsyncDispatch); + syncActivityFinished = true; + flushQueue(); +}; + +export default asyncDispatchMiddleware; diff --git a/.internal/wui/src/reducers/middlewares/promiseMiddleware.js b/.internal/wui/src/reducers/middlewares/promiseMiddleware.js new file mode 100644 index 000000000..d63ca1fae --- /dev/null +++ b/.internal/wui/src/reducers/middlewares/promiseMiddleware.js @@ -0,0 +1,29 @@ +import { API_STATUS } from '../../constants'; + +const promiseMiddleware = () => { + return next => action => { + const { promise, type, label, ...rest } = action; + + if (!promise) { + return next(action); + } + + const SUCCESS = type + `_${API_STATUS.SUCCESS}`; + const PENDING = type + `_${API_STATUS.PENDING}`; + const FAILURE = type + `_${API_STATUS.FAILURE}`; + + next({ ...rest, type: PENDING, label }); + + return promise.then(res => { + next({ ...rest, res, type: SUCCESS, label }); + + return true; + }).catch(error => { + next({ ...rest, error, type: FAILURE, label }); + + return false; + }); + }; +} + +export default promiseMiddleware; diff --git a/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js b/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js new file mode 100644 index 000000000..33cafaf4e --- /dev/null +++ b/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js @@ -0,0 +1,43 @@ +import { + REMOVE_FROM_FILTER_HIDE_LIST, + ADD_TO_FILTER_HIDE_LIST +} from '../actions/updateFilterTags.action'; + +const defaultState = { + hideServiceTags: [] +}; + +const reducerHandler = (state = defaultState, action) => { + const newState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case `${REMOVE_FROM_FILTER_HIDE_LIST}`: + newState.hideServiceTags.splice(newState.hideServiceTags.indexOf(action.data.filterTag), 1); + return { + ...state, + ...newState + }; + + case `${ADD_TO_FILTER_HIDE_LIST}`: + if (newState.hideServiceTags.indexOf(action.data.filterTag) < 0) { + newState.hideServiceTags.push(action.data.filterTag); + } else { + console.warn(`Tag '${action.data.filterTag}' is already added!`); + return { + ...state + } + } + return { + ...state, + ...newState + }; + + default: + return state; + } +}; + +export default reducerHandler; + +export const updateHideServiceTagsSelector = (state) => { + return state.hideServiceTags +}; diff --git a/.internal/wui/src/reducers/updateSelectedServicesReducer.js b/.internal/wui/src/reducers/updateSelectedServicesReducer.js new file mode 100644 index 000000000..b7e487c80 --- /dev/null +++ b/.internal/wui/src/reducers/updateSelectedServicesReducer.js @@ -0,0 +1,43 @@ +import { + REMOVE_FROM_SELECTED_SERVICES, + ADD_TO_SELECTED_SERVICES +} from '../actions/updateSelectedServices.action'; + +const defaultState = { + selectedServices: [] +}; + +const reducerHandler = (state = defaultState, action) => { + const newState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case `${REMOVE_FROM_SELECTED_SERVICES}`: + newState.selectedServices.splice(newState.selectedServices.indexOf(action.data.serviceName), 1); + return { + ...state, + ...newState + } + + case `${ADD_TO_SELECTED_SERVICES}`: + if (newState.selectedServices.indexOf(action.data.serviceName) < 0) { + newState.selectedServices.push(action.data.serviceName); + } else { + console.warn(`Service '${action.data.serviceName}' is already added!`); + return { + ...state + } + } + return { + ...state, + ...newState + } + + default: + return state + } +}; + +export default reducerHandler; + +export const updateSelectedServicesSelector = (state) => { + return state.selectedServices +}; diff --git a/.internal/wui/src/router.jsx b/.internal/wui/src/router.jsx new file mode 100644 index 000000000..ea1062465 --- /dev/null +++ b/.internal/wui/src/router.jsx @@ -0,0 +1,48 @@ +import React, { Fragment } from "react"; +import { + BrowserRouter as Router, + Switch, + Redirect, + Route +} from "react-router-dom"; +import Build from './pages/mainBuild' +import NotFound from './pages/notFound' +import BuildHistory from './pages/buildHistory' +import Scripts from './pages/scripts' +import Box from '@material-ui/core/Box'; +import Help from './pages/help' +import Sidebar from './features/Sidebar' + +export default function RouteWrapper() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/.internal/wui/src/services/builds.js b/.internal/wui/src/services/builds.js new file mode 100644 index 000000000..9f4077224 --- /dev/null +++ b/.internal/wui/src/services/builds.js @@ -0,0 +1,160 @@ +import config from '../config'; + +const getBuildHistoryList = () => { + return new Promise((resolve, reject) => { + try { + return fetch(`${config.apiProtocol}${config.apiUrl}/build/list`).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getBuildHistoryList: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getBuildHistoryList: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getBuildHistoryList: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +const getBuildIssues = ({ selectedServices, serviceConfigurations }) => { + return new Promise((resolve, reject) => { + try { + if (!Array.isArray(selectedServices)) { + console.error('getBuildIssues: selectedServices is not an array'); + return reject('getBuildIssues: selectedServices is not an array'); + } + const bodyObject = { + buildOptions: { + selectedServices, + serviceConfigurations + } + } + + return fetch( + `${config.apiProtocol}${config.apiUrl}/build/dryrun`, + { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(bodyObject) + }).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getBuildIssues: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getBuildIssues: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getBuildIssues: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +const createAndBuildStack = ({ selectedServices, serviceConfigurations }) => { + return new Promise((resolve, reject) => { + try { + if (!Array.isArray(selectedServices)) { + console.error('createAndBuildStack: selectedServices is not an array'); + return reject('createAndBuildStack: selectedServices is not an array'); + } + const bodyObject = { + buildOptions: { + selectedServices, + serviceConfigurations + } + } + + return fetch( + `${config.apiProtocol}${config.apiUrl}/build/save`, + { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(bodyObject) + }).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('createAndBuildStack: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('createAndBuildStack: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('createAndBuildStack: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +const downloadBuild = ({ build, type, linkRef }) => { + return new Promise((resolve, reject) => { + try { + return fetch( + `${config.apiProtocol}${config.apiUrl}/build/get/${build}/${type}`, + { + cache: 'no-cache' + }).then((response) => { + return response.blob().then((data) => { + try { + const href = window.URL.createObjectURL(data); + const a = linkRef.current; + a.download = `${build}.${type}`; + a.href = href; + a.click(); + a.href = ''; + } catch (err) { + console.error('downloadBuild: error creating link for blob download:'); + console.error(err) + } + + return resolve(data); + }).catch((err) => { + console.error('downloadBuild: error parsing text response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('downloadBuild: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('downloadBuild: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +export { + downloadBuild, + getBuildHistoryList, + getBuildIssues, + createAndBuildStack +}; diff --git a/.internal/wui/src/services/configs.js b/.internal/wui/src/services/configs.js new file mode 100644 index 000000000..8c1dec369 --- /dev/null +++ b/.internal/wui/src/services/configs.js @@ -0,0 +1,66 @@ +import config from '../config'; + +const getServiceMetadata = (serviceName) => { + return new Promise((resolve, reject) => { + try { + if (typeof serviceName !== 'string' || !serviceName) { + console.error('getServiceMetadata: invalid serviceName: ', serviceName); + console.trace(); + return reject('getServiceMetadata: invalid serviceName: ', serviceName); + } + + return fetch(`${config.apiProtocol}${config.apiUrl}/config/${serviceName}/meta`).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getServiceMetadata: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getServiceMetadata: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getServiceMetadata: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +const getServiceConfigOptions = (serviceName) => { + return new Promise((resolve, reject) => { + try { + if (typeof serviceName !== 'string' || !serviceName) { + console.error('getServiceConfigOptions: invalid serviceName: ', serviceName); + console.trace(); + return reject('getServiceConfigOptions: invalid serviceName: ', serviceName); + } + + return fetch(`${config.apiProtocol}${config.apiUrl}/config/${serviceName}/options`).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getServiceConfigOptions: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getServiceConfigOptions: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getServiceConfigOptions: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +export { + getServiceMetadata, + getServiceConfigOptions +}; diff --git a/.internal/wui/src/services/templates.js b/.internal/wui/src/services/templates.js new file mode 100644 index 000000000..6924c84dd --- /dev/null +++ b/.internal/wui/src/services/templates.js @@ -0,0 +1,134 @@ +import config from '../config'; + +const getServiceTemplatesList = () => { + return new Promise((resolve, reject) => { + try { + return fetch(`${config.apiProtocol}${config.apiUrl}/templates/services/list`).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getServiceTemplatesList: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getServiceTemplatesList: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getServiceTemplatesList: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +const getServiceTemplates = () => { + return new Promise((resolve, reject) => { + try { + return fetch(`${config.apiProtocol}${config.apiUrl}/templates/services/json`).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getServiceTemplates: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getServiceTemplates: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getServiceTemplates: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +const getNetworkTemplatesList = () => { + return new Promise((resolve, reject) => { + try { + return fetch(`${config.apiProtocol}${config.apiUrl}/templates/networks/list`).then((response) => { + return response.json().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getServiceTemplatesList: error parsing JSON response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getServiceTemplatesList: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getServiceTemplatesList: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +const getScriptTemplate = ({ scriptName, options, linkRef }) => { + return new Promise((resolve, reject) => { + try { + return fetch( + `${config.apiProtocol}${config.apiUrl}/templates/scripts/${linkRef ? 'download/' : ''}${scriptName}`, + { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ options }) + }).then((response) => { + if (linkRef) { + return response.blob().then((data) => { + try { + const href = window.URL.createObjectURL(data); + const a = linkRef.current; + a.download = `${scriptName}${options.build ? '_' + options.build : ''}.sh`; + a.href = href; + a.click(); + a.href = ''; + } catch (err) { + console.error('getScriptTemplate: error creating link for blob download:'); + console.error(err) + } + + return resolve(data); + }).catch((err) => { + console.error('getScriptTemplate: error parsing text response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } + return response.text().then((data) => { + return resolve(data); + }).catch((err) => { + console.error('getScriptTemplate: error parsing text response:'); + console.error(response); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + }).catch((err) => { + console.error('getScriptTemplate: error communicating with API.'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + }); + } catch (err) { + console.error('getScriptTemplate: an unhandled error occured'); + console.error(err); + return reject(JSON.stringify(err, Object.getOwnPropertyNames(err))); + } + }); +}; + +export { + getScriptTemplate, + getServiceTemplates, + getNetworkTemplatesList, + getServiceTemplatesList +}; diff --git a/.internal/wui/src/utils/buildOptionSync.js b/.internal/wui/src/utils/buildOptionSync.js new file mode 100644 index 000000000..560b4bb28 --- /dev/null +++ b/.internal/wui/src/utils/buildOptionSync.js @@ -0,0 +1,90 @@ +const setBuildOptions = (newOptions) => { + buildOptionsInit(); + localStorage.setItem('buildOptions', JSON.stringify(newOptions)); +}; + +const getBuildOptions = () => { + try { + return JSON.parse(localStorage.getItem('buildOptions')) || {}; + } catch (err) { + console.error('Error getting build options', err); + } + + return {}; +}; + +const setServiceOptions = (serviceName, options) => { + buildOptionsInit(); + const currentBuildOptions = getBuildOptions(); + + currentBuildOptions.services[serviceName] = options; + + localStorage.setItem('buildOptions', JSON.stringify(currentBuildOptions)); +}; + +const buildOptionsInit = () => { + const currentBuildOptions = getBuildOptions(); + + if (!currentBuildOptions.services || typeof(currentBuildOptions.services) !== 'object') { + currentBuildOptions.services = {}; + } + + if (!currentBuildOptions.networks || typeof(currentBuildOptions.networks) !== 'object') { + currentBuildOptions.networks = {}; + } + + if (!currentBuildOptions.meta || typeof(currentBuildOptions.meta) !== 'object') { + currentBuildOptions.meta = {}; + } + + localStorage.setItem('buildOptions', JSON.stringify(currentBuildOptions)); +}; + +const setTemporaryBuildOptions = (newOptions) => { + buildOptionsInit(); + sessionStorage.setItem('unsavedBuildOptions', JSON.stringify(newOptions)); +}; + +const deleteTemporaryBuildOptions = () => { + sessionStorage.removeItem('unsavedBuildOptions'); +}; + +const getTemporaryBuildOptions = () => { + try { + return JSON.parse(sessionStorage.getItem('unsavedBuildOptions')) || {}; + } catch (err) { + console.error('Error getting build options', err); + } + + return {}; +}; + +const setTemporaryServiceOptions = (serviceName, options) => { + buildOptionsInit(); + const currentBuildOptions = getBuildOptions(); + + currentBuildOptions.services[serviceName] = options; + + sessionStorage.setItem('unsavedBuildOptions', JSON.stringify(currentBuildOptions)); +}; + +const setupTemporaryBuildOptions = () => { + setTemporaryBuildOptions(getBuildOptions()); +}; + +const saveTemporaryBuildOptions = () => { + setBuildOptions(getTemporaryBuildOptions()); +}; + +module.exports = { + getBuildOptions, + setBuildOptions, + buildOptionsInit, + setServiceOptions, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions, + deleteTemporaryBuildOptions +}; diff --git a/.internal/wui/src/utils/configOptionLoader.jsx b/.internal/wui/src/utils/configOptionLoader.jsx new file mode 100644 index 000000000..c464af8cb --- /dev/null +++ b/.internal/wui/src/utils/configOptionLoader.jsx @@ -0,0 +1,43 @@ +import { Fragment } from 'react'; +import ServiceUiControls from '../features/serviceUiControls'; + +const getConfigComponents = (configOptions) => { + if (configOptions && typeof(configOptions) === 'object') { + return Object.keys(configOptions).map((configName) => { + switch(configName) { + case "serviceName": + return null; + + case "labeledPorts": + return ServiceUiControls.PortConfig + + case "networks": + if (configOptions[configName] === true) { // Check if set to true + return ServiceUiControls.NetworkConfig + } else { + return null; + } + + case "logging": + if (configOptions[configName] === true) { // Check if set to true + return ServiceUiControls.Logging + } else { + return null; + } + + default: + if (configOptions[configName]) { // Check if set + return () => (
Unknown Option {configName}
); + } else { + return null; + } + } + }).filter((ele) => { + return ele !== null; + }); + } + + return [Fragment]; +}; + +export default getConfigComponents; diff --git a/.internal/wui/src/utils/parsers.js b/.internal/wui/src/utils/parsers.js new file mode 100644 index 000000000..0acb27aba --- /dev/null +++ b/.internal/wui/src/utils/parsers.js @@ -0,0 +1,53 @@ +const getExternalPort = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const splitted = intExtStr.split(':'); + if (splitted.length === 2) { + return splitted[0]; + } + } + + return intExtStr; +}; + +const getInternalPort = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const portSection = intExtStr.split('/'); // So that /TCP or /UDP is not returned. + const splitted = portSection[0].split(':'); + if (splitted.length === 2) { + return splitted[1]; + } + } + + return intExtStr; +}; + +const getPortProtocol = (intExtProtStr) => { + if (typeof(intExtProtStr) === 'string') { + const splitted = intExtProtStr.split('/'); + if (splitted.length === 2) { + return splitted[1]; + } + } + + return intExtProtStr; +}; + +const replaceExternalPort = (intExtStr, newExtPort) => { + if (typeof(intExtStr) === 'string' && (typeof(newExtPort) === 'string' || typeof(newExtPort) === 'number')) { + const intAndProtLoc = intExtStr.indexOf(':'); + if (intAndProtLoc > 0 && intAndProtLoc < 6) { + const portsWithoutExt = intExtStr.substring(intAndProtLoc, intExtStr.length); + return `${newExtPort}${portsWithoutExt}`; + } + } + + return intExtStr; +}; + + +module.exports = { + getExternalPort, + getInternalPort, + replaceExternalPort, + getPortProtocol +}; \ No newline at end of file diff --git a/scripts/deps/__pycache__/__init__.cpython-36.pyc b/scripts/deps/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index e6d825d1d60545c691981486ec7ee7cb85073876..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147 zcmXr!<>k6`TRfft2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CUk>`o`k}?CMaBBT zIhEO|`Y!p&rManjCB^zhsRjAP`kwwF#U+W!+4{xFMVSRa;gr;ZV*U8|%)HE!_;|g7 V%3B;Zx%nxjIjMFalZ%0v0RY$TB+~!@ diff --git a/scripts/deps/__pycache__/chars.cpython-36.pyc b/scripts/deps/__pycache__/chars.cpython-36.pyc deleted file mode 100644 index 768c816570cd796b8805db838690cddf32f8bae7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1563 zcmc&!OHb5L6z=VG$}le;DhxQl079G??ZOy0LKKi_f@lCWAwDwGQg=qdKKjLz`qat$H0He#(0vN%LVrmrS{r%*|K=7>>NyH%#y(qV6T;SYrCme zP3CP12EAoa*VJqH3u77Bd@dmla$!ddC8{~9@Xbo~F8{%Or=b9z1GPCGd z1`p?$ZkoSuAlbT%MqCQcFwRMwERP0AO|IfuKagBfm3kxy;Z$Cb^HNQIbkdcp^R^^=nlb&pS5DrAl}s?^-n)!6maO1WYQ*M!ry^ zs8B?>oG*Aiv_@N-Jrp;kF4?r0b9tOOhHmDp$wH1Y9;Ug{vXNDIlo};GsB1PDTw!L# z;Hq7AowCb``B|bFd{$#j)3uw-piG;$)>jN|%GS$8qvSG;8jj7htJfEpo6}b`rc={F z7z~GLx>)Fpv(DReyI8bKc(fCqC{E!snfQ<-qL36xk~CUHrbCGQXQF90zJuT~k6cGF z_PEaP=bEN=nvm>RvkA$jJ($s6VU7!2p=lBK3DYmkfH0Y+8N`Tp`t=nTjGhqZF!-wwQ%xbpeIW{Y2Esd3x}NaVS)UIS+G>rexCqiA=kc@2{Nr8& zDO@f(?z;F-jNvo)Z8VNjpd*ORW(n=`R@~`!*A*_f}O>kSaW1n;n5IP!p-wG~)`N#3&2oq3wM^K8o!maw1kz!Q#epRu4I zJW;^t3ttp57DY*vF_r{hXSK>JXlHAoMFSd*4mzE#FN0(_xoxSrl(jf%KClK%I4$c( zw#9`jyk~xDXY7FALO&plg*C+?_iCERS&*EC#GppnN%IwSP2V#1XnMd&_fL@jmT~qN zZ-N%SR9i5H>pE0X4{RZOx*jIoZW3>9?ZjakC9z)Y?Y%B8H)Sk$d+NGR z*Be@*{{b;oBb8s9yR4@wikpkeog{2@^!3Fx*l>7g}n2JYU4%q3?Y@PU_EEi3bcO*=Td&mO|t+SjgSnp>y-u@y1VMaVH+i z7{d;UG3#_wrmM&Gk>T|@5XK#D!K^+%gR#VCxW^~aJ+9ut*Z+~3)hXOZ&49e3B&ykJ zmKbwHP7|Y`&d_|G2xXL7AVQB+=ZRb(LJvP-n6c4}p-JYS4D&Abgp|D0D2^#WP5eE? z1o3BQmWe(GF^4DtP`JA*DbHL2heuZtd)}b1`w=(*3UDqOj-M4W9{{tI*@(nK#+ryr zz`zn>v3eiTI|KvUIA-{G^X{T~cTfp;ltQ|jXBaEw6BHmflX$BWg{e072r8ra8*U@( z1mln-R!}~s=A^Y|!fhG0Y1^UF51~L){!t+LCV*y4Fsb*z3&}Fn2uH|W#!4;tPw;{J zg6}c1PzyOKEXq52ui+59{=3ykRsi-#5_Su4Z#22kZ3&O~12;Y5duf4uL0sWvt^*`) z^W>!{w0Z1U$a(dL+3g!GKD@~fP)vX)o+!48nG2jKJqI@fPn6NEWtKSykQ9~m@e3xf zlVz@$6jRT~uc13klU8wRo$%y4hoz-<=>=DUvq6Eg{>te6Z<8ilSz^ZMEr{9Yh!1l^ z(mFTRDxl|w!UiLRG6m%HnxZ;pz^T7j{ZCC@gkfT_mvX_Z2&3Yhy| zs%zEg&6~q*zuo9B>|+P;h9YHfZ9nM{FquWo3Q9-cg3{3^liv6GS8=`lbn)qSl*&!i zB_+k6dTF0d8(gaHccs>irX0|oI8oh3XHZ@KxIY`|YMi9iM)gUf6A5!U;4n{3=I4cx z*ej}JxBFM#cE+kw30|@Jo$lfBe0P6`HeBE299Q6awVC$rHJ`ha!zM zlqz@92pI3`j+8yZ?A}hA+qBWvsZxX@xwl1+Nb}`S&@GrkEbIPkEJq=p;{vjNB7ZGXhc(pbTM-tYo0Xs6BRd1LUT-`ODoz>~!RHDhqlN Pgvyz3U2y#={7QcV?)r8B diff --git a/scripts/deps/__pycache__/consts.cpython-36.pyc b/scripts/deps/__pycache__/consts.cpython-36.pyc deleted file mode 100644 index 2d73746ef95e7a91f55b3b2c38790fdc2a184216..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 580 zcmZ8fyH3L}6m|McQz{i&=)f0rs6DVSpbCi!iKRsiGD?I_KIqy`J}-U#~tLLcYkKQ8W17Om%At5Kh414%B!J>bwpO-hd`= zB7xS3@D{Xr8y#>BcA>*N;BgPSOENy&cPUdSvp}F?`yORfW0Zuxwo8w)EDqDi;K`b^XCnAoLSRqw@hQ-DeWhFO>Gn6ub1K-AN zRtSca{rlIR*Dd{7$$Z?+&nv&PK%&sG+~pTX(0DkpaA`Y{bygV7pYECo%buV)oC9@cFc_xEh zmf>!LY!(aC?X798MAJL=w0Ke47aLY}957L)iCd)=O?J6^7sZfsG%th=k&P- G+xZLGE4%9e diff --git a/scripts/deps/__pycache__/version_check.cpython-36.pyc b/scripts/deps/__pycache__/version_check.cpython-36.pyc deleted file mode 100644 index 9ad47fa25eb173d1bbba5f4189b1ee73cc380e6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 839 zcmZWn&2H2%5FR@}n@zK@>ZNc&IdCACMuID<5L+tsK#|x2QZCgh4kb;R1Usp;EB90$ zfY;zfcmR&!Qi;>P0w=~!vRxq7*xz`*@3Y6sv&qE$@pJF2HUWOY)<+S)zz`lz3>f(W z5imN3z=%~%eJ;i>#tcI|CIAvHkaHtU=njXUS@U(UT!j--*9{5x~l z_*~yo?@)e=tBIA{e=A=Jccg-KX zTB6F+x;65oXpOX}12?+Q`vZDGbT97QhI}#*=1LoF($|ZNl5eGHv7Nqb(ws$J@6}0% ztW$0>EgUkf`v!cB4gP)=#^F1GeTVaWnI++288?^Ms0evdl_ETTb1LdZoP{FhX@%P? zsYH0yJ=9sOI^VCBt*24nk9s-r6el1q^)M*$a7>Af`2QUTcc&PSF!&CtP6DD=eZ#Fu T{qn8z{IX Date: Sat, 16 Jan 2021 05:23:11 -0800 Subject: [PATCH 003/142] Got basic python and deps working. Added container ssh to host --- .internal/.ssh/.gitignore | 1 + .internal/cli.Dockerfile | 8 + .internal/cli/entry.py | 39 ++++ .internal/cli/requirements.txt | 3 + .internal/ctrl_api.sh | 30 ++- .internal/ctrl_cli.sh | 51 +++++ install.sh | 214 ++++-------------- menu.sh | 365 +++---------------------------- scripts/deps/__init__.py | 0 scripts/deps/chars.py | 72 ------ scripts/deps/common_functions.py | 190 ---------------- scripts/deps/consts.py | 12 - scripts/deps/version_check.py | 36 --- scripts/deps/yaml_merge.py | 17 -- scripts/python_deps_check.py | 34 --- scripts/setup_iotstack.sh | 184 ++++++++++++++++ scripts/yaml_merge.py | 71 ------ 17 files changed, 376 insertions(+), 951 deletions(-) create mode 100644 .internal/.ssh/.gitignore create mode 100644 .internal/cli.Dockerfile create mode 100644 .internal/cli/entry.py create mode 100644 .internal/cli/requirements.txt create mode 100644 .internal/ctrl_cli.sh delete mode 100755 scripts/deps/__init__.py delete mode 100755 scripts/deps/chars.py delete mode 100755 scripts/deps/common_functions.py delete mode 100755 scripts/deps/consts.py delete mode 100755 scripts/deps/version_check.py delete mode 100755 scripts/deps/yaml_merge.py delete mode 100755 scripts/python_deps_check.py create mode 100644 scripts/setup_iotstack.sh delete mode 100755 scripts/yaml_merge.py diff --git a/.internal/.ssh/.gitignore b/.internal/.ssh/.gitignore new file mode 100644 index 000000000..eafb9102c --- /dev/null +++ b/.internal/.ssh/.gitignore @@ -0,0 +1 @@ +id_rsa* diff --git a/.internal/cli.Dockerfile b/.internal/cli.Dockerfile new file mode 100644 index 000000000..0f1868a02 --- /dev/null +++ b/.internal/cli.Dockerfile @@ -0,0 +1,8 @@ +FROM python:3 + +WORKDIR /usr/iotstack_cli + +COPY cli ./ +RUN pip install --no-cache-dir -r requirements.txt + +CMD [ "python", "./entry.py" ] diff --git a/.internal/cli/entry.py b/.internal/cli/entry.py new file mode 100644 index 000000000..2569bfc4d --- /dev/null +++ b/.internal/cli/entry.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import blessed +import yaml +import ruamel.yaml +import subprocess +import os + +hostUser = os.getenv('HOSTUSER') + +print('blessed Version:', blessed.__version__) +print('ruamel.yaml Version:', ruamel.yaml.__version__) +print('PyYAML Version:', yaml.__version__) +print('') +print('hostUser: ', hostUser) + +print('') +testInput = print('Remote test: ') +res1 = subprocess.check_output(""" +ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'touch ~/tat.file' +""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) + +res2 = subprocess.check_output(""" +ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'echo "hi" >> ~/tat.file' +""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) + +res3 = subprocess.check_output(""" +ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'cat ~/tat.file' +""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) + +res4 = subprocess.check_output(""" +ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'rm ~/tat.file' +""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) + +testInput = print(res3.decode('ascii')) +print('') + +testInput = input('Enter input: ') +print('Input you entered', testInput) diff --git a/.internal/cli/requirements.txt b/.internal/cli/requirements.txt new file mode 100644 index 000000000..817848ba9 --- /dev/null +++ b/.internal/cli/requirements.txt @@ -0,0 +1,3 @@ +ruamel.yaml ~= 0.16.12 +blessed ~= 1.17.5 +pyyaml ~= 5.3.1 diff --git a/.internal/ctrl_api.sh b/.internal/ctrl_api.sh index 18fe48604..f3b8cff09 100644 --- a/.internal/ctrl_api.sh +++ b/.internal/ctrl_api.sh @@ -16,24 +16,30 @@ if [ "$1" = "stop" ]; then else if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then echo "Starting IOTstack API Server" - docker run -d -p 32128:32128 \ - --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ - --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds \ - --restart unless-stopped \ - $FULL_NAME + # docker run -d -p 32128:32128 \ + # --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ + # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds \ + # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ + # -e HOSTUSER="$(whoami)" \ + # --restart unless-stopped \ + # $FULL_NAME # docker run -p 32128:32128 \ # --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ - # --mount type=bind,source="$(pwd)"/builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ # -e cors="yourLanIpHere:32777" \ - # --restart unless-stopped \ + # -e HOSTUSER="$(whoami)" \ + # --restart unless-stopped \ # $FULL_NAME - # docker run -p 32128:32128 \ - # --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ - # --mount type=bind,source="$(pwd)"/builds,target=/usr/iotstack_api/builds,readonly \ - # --restart unless-stopped \ - # -it $FULL_NAME /bin/bash + docker run -p 32128:32128 \ + --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ + --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ + --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ + -e HOSTUSER="$(whoami)" \ + --restart unless-stopped \ + -it $FULL_NAME /bin/bash else echo "IOTstack API Server is running" fi diff --git a/.internal/ctrl_cli.sh b/.internal/ctrl_cli.sh new file mode 100644 index 000000000..b96cdd992 --- /dev/null +++ b/.internal/ctrl_cli.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +VERSION=v0.0.1 +DNAME=iostack_cli +FULL_NAME="$DNAME:$VERSION" + +if [[ $IOTENV == "development" ]]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker build --no-cache -t $FULL_NAME -f cli.Dockerfile . +else + docker build --quiet -t $FULL_NAME -f cli.Dockerfile . +fi + +if [ "$1" = "stop" ]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) +else + if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then + echo "Starting IOTstack CLI instance" + + docker run \ + --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ + --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ + -e HOSTUSER="$(whoami)" \ + --restart no \ + -it $FULL_NAME + + # docker run -d \ + # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds \ + # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ + # -e HOSTUSER="$(whoami)" \ + # --restart no \ + # $FULL_NAME + + # docker run \ + # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ + # -e cors="yourLanIpHere:32777" \ + # -e HOSTUSER="$(whoami)" \ + # --restart no \ + # $FULL_NAME + + # docker run \ + # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ + # -e HOSTUSER="$(whoami)" \ + # --restart no \ + # -it $FULL_NAME /bin/bash + else + echo "IOTstack CLI is running. Check with 'docker ps'." + fi +fi diff --git a/install.sh b/install.sh index d61b8f150..157176e6a 100755 --- a/install.sh +++ b/install.sh @@ -2,12 +2,10 @@ # Minimum Software Versions REQ_DOCKER_VERSION=18.2.0 -REQ_PYTHON_VERSION=3.6.9 -REQ_PIP_VERSION=3.6.9 -REQ_PYAML_VERSION=0.16.12 -REQ_BLESSED_VERSION=1.17.5 -PYTHON_CMD=python3 +# Required to generate and install a ssh key so menu containers can securely execute commands on host +AUTH_KEYS_FILE=~/.ssh/authorized_keys +CONTAINER_KEYS_FILE=./.internal/.ssh/id_rsa sys_arch=$(uname -m) @@ -90,8 +88,7 @@ function minimum_version_check() { echo "$VERSION_GOOD" } -function user_in_group() -{ +function user_in_group() { if grep -q $1 /etc/group ; then if id -nGz "$USER" | grep -qzxF "$1"; then echo "true" @@ -103,206 +100,79 @@ function user_in_group() fi } -function install_python3_and_deps() { - CURR_PYTHON_VER="${1:-Unknown}" - if [ "$NOASKCONFIRM" == "true" ]; then - echo "Installing Python3" - sudo apt install -y python3-pip python3-dev - if [ $? -eq 0 ]; then - PYTHON_VERSION_GOOD="true" - else - echo "Failed to install Python" >&2 - exit 1 - fi - echo "Installing ruamel.yaml and blessed" - pip3 install -U ruamel.yaml==0.16.12 blessed - if [ $? -eq 0 ]; then - PYAML_VERSION_GOOD="true" - BLESSED_GOOD="true" - else - echo "Failed to install ruamel.yaml and Blessed" >&2 - exit 1 - fi - else - if (whiptail --title "Python 3 and Dependencies" --yesno "Python 3.6.9 or later (Current = $CURR_PYTHON_VER), ruamel.yaml 0.16.12 or later, blessed and pip3 are required for the main menu and compose-overrides.yml file to merge into the docker-compose.yml file. Install these now?" 20 78); then - sudo apt install -y python3-pip python3-dev - if [ $? -eq 0 ]; then - PYTHON_VERSION_GOOD="true" - else - echo "Failed to install Python" >&2 - exit 1 - fi - pip3 install -U ruamel.yaml==0.16.12 blessed - if [ $? -eq 0 ]; then - PYAML_VERSION_GOOD="true" - BLESSED_GOOD="true" - else - echo "Failed to install ruamel.yaml and Blessed" >&2 - exit 1 - fi - fi - fi -} - function install_docker() { if command_exists docker; then echo "Docker already installed" >&2 else echo "Install Docker" >&2 curl -fsSL https://get.docker.com | sh - sudo usermod -aG docker $USER + sudo -E usermod -aG docker $USER fi if command_exists docker-compose; then echo "docker-compose already installed" >&2 else echo "Install docker-compose" >&2 - sudo apt install -y docker-compose + sudo -E apt install -y docker-compose fi echo "" >&2 echo "You should now restart your system" >&2 } -function update_docker() { - sudo apt upgrade docker docker-compose -} - -function do_python3_checks() { - PYTHON_VERSION_GOOD="false" - PYAML_VERSION_GOOD="false" - BLESSED_GOOD="false" - - if command_exists $PYTHON_CMD && command_exists pip3; then - PYTHON_VERSION=$($PYTHON_CMD --version) - PYTHON_VERSION_MAJOR=$(echo "$PYTHON_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 1) - PYTHON_VERSION_MINOR=$(echo "$PYTHON_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 2) - PYTHON_VERSION_BUILD=$(echo "$PYTHON_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 3) - - printf "Python Version: '${PYTHON_VERSION:-Unknown}'. " - if [ "$(minimum_version_check $REQ_PYTHON_VERSION $PYTHON_VERSION_MAJOR $PYTHON_VERSION_MINOR $PYTHON_VERSION_BUILD)" == "true" ]; then - PYTHON_VERSION_GOOD="true" - echo "Python is up to date." >&2 - else - echo "Python is outdated." >&2 - install_python3_and_deps "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR.$PYTHON_VERSION_BUILD" "$PYAML_VERSION_MAJOR.$PYAML_VERSION_MINOR.$PYAML_VERSION_BUILD" - return 1 - fi - else - install_python3_and_deps - return 1 - fi -} - -function do_env_setup() { - echo "Setting up environment:" +function do_group_setup() { + echo "Setting up groups:" if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then echo "User is NOT in 'bluetooth' group. Adding:" >&2 echo "sudo usermod -G bluetooth -a $USER" >&2 - sudo usermod -G "bluetooth" -a $USER + sudo -E usermod -G "bluetooth" -a $USER fi if [ ! "$(user_in_group docker)" == "true" ]; then echo "User is NOT in 'docker' group. Adding:" >&2 echo "sudo usermod -G docker -a $USER" >&2 - sudo usermod -G "docker" -a $USER + sudo -E usermod -G "docker" -a $USER fi -} -function do_docker_checks() { - if command_exists docker; then - DOCKER_VERSION_GOOD="false" - DOCKER_VERSION=$(docker version -f "{{.Server.Version}}") - if [ ! -z "$DOCKER_VERSION" ]; then - echo "Error getting docker version. Error when running docker command. Check that docker is installed correctly." - fi - DOCKER_VERSION_MAJOR=$(echo "$DOCKER_VERSION"| cut -d'.' -f 1) - DOCKER_VERSION_MINOR=$(echo "$DOCKER_VERSION"| cut -d'.' -f 2) - DOCKER_VERSION_BUILD=$(echo "$DOCKER_VERSION"| cut -d'.' -f 3) + echo "" >&2 + echo "Rebooting or logging off is advised." >&2 +} - if [ "$(minimum_version_check $REQ_DOCKER_VERSION $DOCKER_VERSION_MAJOR $DOCKER_VERSION_MINOR $DOCKER_VERSION_BUILD )" == "true" ]; then - [ -f .docker_outofdate ] && rm .docker_outofdate - DOCKER_VERSION_GOOD="true" - echo "Docker version $DOCKER_VERSION >= $REQ_DOCKER_VERSION. Docker is good to go." >&2 - else - if [ "$NOASKCONFIRM" == "true" ]; then - update_docker - else - if [ ! -f .docker_outofdate ]; then - if (whiptail --title "Docker and Docker-Compose Version Issue" --yesno "Docker version is currently $DOCKER_VERSION which is less than $REQ_DOCKER_VERSION consider upgrading or you may experience issues. You will not be prompted again. You can manually upgrade by typing:\n sudo apt upgrade docker docker-compose\n\nAttempt to upgrade now?" 20 78); then - update_docker - else - touch .docker_outofdate - fi - fi - fi - fi - else - [ -f .docker_outofdate ] && rm .docker_outofdate - echo "Docker not installed" >&2 - if [ "$NOASKCONFIRM" == "true" ]; then - do_env_setup - install_docker - else - if [ ! -f .docker_notinstalled ]; then - if (whiptail --title "Docker and Docker-Compose" --yesno "Docker is not currently installed, and is required to run IOTstack. Would you like to install docker and docker-compose now?\nYou will not be prompted again." 20 78); then - [ -f .docker_notinstalled ] && rm .docker_notinstalled - do_env_setup - install_docker - else - touch .docker_notinstalled - fi - fi - fi - fi +function do_env_setup() { + sudo -E apt-get install git wget unzip -y } -function do_env_checks() { - GROUPSGOOD=0 +function do_iotstack_setup() { + git clone https://github.com/SensorsIot/IOTstack.git + cd IOTstack - if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then - GROUPSGOOD=1 - echo "User is NOT in 'bluetooth' group" >&2 + if [ $? -eq 0 ]; then + echo "IOTstack cloned" + else + echo "Could not find IOTstack directory" + exit 5 fi +} - if [[ ! "$(user_in_group docker)" == "true" ]]; then - GROUPSGOOD=1 - echo "User is NOT in 'docker' group" >&2 - fi +function generate_container_ssh() { + cat /dev/null | ssh-keygen -q -N "" -f $CONTAINER_KEYS_FILE +} - if [ "$GROUPSGOOD" == 1 ]; then - echo "!! You might experience issues with docker or bluetooth. To fix run: ./menu.sh --run-env-setup" +function install_ssh_keys() { + if [ -f "$CONTAINER_KEYS_FILE" ]; then + NEW_KEY="$(cat $CONTAINER_KEYS_FILE.pub)" + if grep -Fxq "$NEW_KEY" $AUTH_KEYS_FILE ; then + echo "Key already exists in '$AUTH_KEYS_FILE' Skipping..." + else + echo "$NEW_KEY" >> $AUTH_KEYS_FILE + echo "Key added." + fi fi } -touch .new_install -echo "Enter in the sudo password when prompted, to install dependencies" - -sudo apt-get install git -y -git clone https://github.com/SensorsIot/IOTstack.git -cd IOTstack - -if [ $? -eq 0 ]; then - echo "IOTstack cloned" -else - echo "Could not find IOTstack directory" - exit 5 -fi - -do_python3_checks -do_docker_checks -echo "Setting up environment:" -if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then - echo "User is NOT in 'bluetooth' group. Adding:" >&2 - echo "sudo usermod -G bluetooth -a $USER" >&2 - echo "You will need to restart your system before the changes take effect." - sudo usermod -G "bluetooth" -a $USER -fi - -if [ ! "$(user_in_group docker)" == "true" ]; then - echo "User is NOT in 'docker' group. Adding:" >&2 - echo "sudo usermod -G docker -a $USER" >&2 - echo "You will need to restart your system before the changes take effect." - sudo usermod -G "docker" -a $USER -fi -do_env_checks +do_env_setup +do_iotstack_setup +generate_container_ssh +install_ssh_keys +install_docker +do_group_setup diff --git a/menu.sh b/menu.sh index a444fb3c8..cef77588d 100755 --- a/menu.sh +++ b/menu.sh @@ -17,364 +17,72 @@ sys_arch=$(uname -m) # ---------------------------------------------- # Helper functions # ---------------------------------------------- -function command_exists() { - command -v "$@" > /dev/null 2>&1 -} - -function user_in_group() -{ - # see if the group exists - grep -q "^$1:" /etc/group; - - # sense that the group does not exist - if [ $? -ne 0 ]; then return 0; fi - - # group exists - now check that the user is a member - groups | grep -q "\b$1\b" -} - -function minimum_version_check() { - # Usage: minimum_version_check required_version current_major current_minor current_build - # Example: minimum_version_check "1.2.3" 1 2 3 - REQ_MIN_VERSION_MAJOR=$(echo "$1"| cut -d' ' -f 2 | cut -d'.' -f 1) - REQ_MIN_VERSION_MINOR=$(echo "$1"| cut -d' ' -f 2 | cut -d'.' -f 2) - REQ_MIN_VERSION_BUILD=$(echo "$1"| cut -d' ' -f 2 | cut -d'.' -f 3) - - CURR_VERSION_MAJOR=$2 - CURR_VERSION_MINOR=$3 - CURR_VERSION_BUILD=$4 - - VERSION_GOOD="Unknown" - - NUMB_REG='^[0-9]+$' - if ! [[ $CURR_VERSION_MAJOR =~ $NUMB_REG ]] ; then - echo "$VERSION_GOOD" - return 1 - fi - if ! [[ $CURR_VERSION_MINOR =~ $NUMB_REG ]] ; then - echo "$VERSION_GOOD" - return 1 - fi - if ! [[ $CURR_VERSION_BUILD =~ $NUMB_REG ]] ; then - echo "$VERSION_GOOD" - return 1 - fi - - if [ -z "$CURR_VERSION_MAJOR" ]; then - echo "$VERSION_GOOD" - return 1 - fi +source ./scripts/setup_iotstack.sh - if [ -z "$CURR_VERSION_MINOR" ]; then - echo "$VERSION_GOOD" - return 1 - fi - - if [ -z "$CURR_VERSION_BUILD" ]; then - echo "$VERSION_GOOD" - return 1 - fi - - if [ "${CURR_VERSION_MAJOR}" -ge $REQ_MIN_VERSION_MAJOR ]; then - VERSION_GOOD="true" - echo "$VERSION_GOOD" - return 0 - else - VERSION_GOOD="false" - fi - - if [ "${CURR_VERSION_MAJOR}" -ge $REQ_MIN_VERSION_MAJOR ] && \ - [ "${CURR_VERSION_MINOR}" -ge $REQ_MIN_VERSION_MINOR ]; then - VERSION_GOOD="true" - echo "$VERSION_GOOD" - return 0 - else - VERSION_GOOD="false" - fi - - if [ "${CURR_VERSION_MAJOR}" -ge $REQ_MIN_VERSION_MAJOR ] && \ - [ "${CURR_VERSION_MINOR}" -ge $REQ_MIN_VERSION_MINOR ] && \ - [ "${CURR_VERSION_BUILD}" -ge $REQ_MIN_VERSION_BUILD ]; then - VERSION_GOOD="true" - echo "$VERSION_GOOD" - return 0 - else - VERSION_GOOD="false" - fi - - echo "$VERSION_GOOD" -} - -function user_in_group() -{ - if grep -q $1 /etc/group ; then - if id -nGz "$USER" | grep -qzxF "$1"; then - echo "true" - else - echo "false" - fi - else - echo "notgroup" - fi -} - -function check_git_updates() -{ +function check_git_updates() { UPSTREAM=${1:-'@{u}'} LOCAL=$(git rev-parse @) REMOTE=$(git rev-parse "$UPSTREAM") BASE=$(git merge-base @ "$UPSTREAM") if [ $LOCAL = $REMOTE ]; then - echo "Up-to-date" + echo "Up-to-date" elif [ $LOCAL = $BASE ]; then - echo "Need to pull" + echo "Need to pull" elif [ $REMOTE = $BASE ]; then - echo "Need to push" + echo "Need to push" else - echo "Diverged" - fi -} -function install_python3_and_deps() { - CURR_PYTHON_VER="${1:-Unknown}" - CURR_PYAML_VER="${2:-Unknown}" - if (whiptail --title "Python 3 and Dependencies" --yesno "Python 3.6.9 or later (Current = $CURR_PYTHON_VER), ruamel.yaml 0.16.12 or later (Current = $CURR_PYAML_VER), blessed and pip3 are required for IOTstack to function correctly. Install these now?" 20 78); then - sudo -E apt update - sudo -E apt install -y python3-pip python3-dev - if [ $? -eq 0 ]; then - PYTHON_VERSION_GOOD="true" - else - echo "Failed to install Python" >&2 - exit 1 - fi - pip3 install -U ruamel.yaml==0.16.12 blessed - if [ $? -eq 0 ]; then - PYAML_VERSION_GOOD="true" - BLESSED_GOOD="true" - else - echo "Failed to install ruamel.yaml and Blessed" >&2 - exit 1 - fi + echo "Diverged" fi } -function install_docker() { - sudo -E bash ./scripts/install_docker.sh install -} - -function update_docker() { - sudo -E bash ./scripts/install_docker.sh upgrade -} - function update_project() { git pull origin $CURRENT_BRANCH git status } -function do_python3_checks() { - PYTHON_VERSION_GOOD="false" - PYAML_VERSION_GOOD="false" - BLESSED_GOOD="false" - - if command_exists $PYTHON_CMD && command_exists pip3; then - PYTHON_VERSION=$($PYTHON_CMD --version 2>/dev/null) - PYTHON_VERSION_MAJOR=$(echo "$PYTHON_VERSION"| cut -d' ' -f 2 | cut -d' ' -f 2 | cut -d'.' -f 1) - PYTHON_VERSION_MINOR=$(echo "$PYTHON_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 2) - PYTHON_VERSION_BUILD=$(echo "$PYTHON_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 3) - - PYAML_VERSION=$($VGET_CMD --pyaml-version 2>/dev/null) - PYAML_VERSION="${PYAML_VERSION:-Unknown}" - PYAML_VERSION_MAJOR=$(echo "$PYAML_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 1) - PYAML_VERSION_MINOR=$(echo "$PYAML_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 2) - PYAML_VERSION_BUILD=$(echo "$PYAML_VERSION"| cut -d' ' -f 2 |cut -d'.' -f 3) - - BLESSED_VERSION=$($VGET_CMD --blessed-version 2>/dev/null) - BLESSED_VERSION="${BLESSED_VERSION:-Unknown}" - BLESSED_VERSION_MAJOR=$(echo "$BLESSED_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 1) - BLESSED_VERSION_MINOR=$(echo "$BLESSED_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 2) - BLESSED_VERSION_BUILD=$(echo "$BLESSED_VERSION"| cut -d' ' -f 2 | cut -d'.' -f 3) - - printf "Python Version: '${PYTHON_VERSION:-Unknown}'. " - if [ "$(minimum_version_check $REQ_PYTHON_VERSION $PYTHON_VERSION_MAJOR $PYTHON_VERSION_MINOR $PYTHON_VERSION_BUILD)" == "true" ]; then - PYTHON_VERSION_GOOD="true" - echo "Python is up to date." >&2 - else - echo "Python is outdated." >&2 - install_python3_and_deps "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR.$PYTHON_VERSION_BUILD" "$PYAML_VERSION_MAJOR.$PYAML_VERSION_MINOR.$PYAML_VERSION_BUILD" - return 1 - fi - printf "ruamel.yaml Version: '$PYAML_VERSION'. " - if [ "$(minimum_version_check $REQ_PYAML_VERSION $PYAML_VERSION_MAJOR $PYAML_VERSION_MINOR $PYAML_VERSION_BUILD)" == "true" ]; then - PYAML_VERSION_GOOD="true" - echo "ruamel.yaml is up to date." >&2 - else - echo "ruamel.yaml is outdated." >&2 - if [ "$PYAML_VERSION" != "Unknown" ]; then - install_python3_and_deps "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR.$PYTHON_VERSION_BUILD" "$PYAML_VERSION_MAJOR.$PYAML_VERSION_MINOR.$PYAML_VERSION_BUILD" - else - install_python3_and_deps "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR.$PYTHON_VERSION_BUILD" - fi - return 1 - fi - printf "Blessed Version: '$BLESSED_VERSION'. " - if [ "$(minimum_version_check $REQ_BLESSED_VERSION $BLESSED_VERSION_MAJOR $BLESSED_VERSION_MINOR $BLESSED_VERSION_BUILD)" == "true" ]; then - BLESSED_GOOD="true" - echo "Blessed is up to date." >&2 - else - echo "Blessed is outdated." >&2 - if [ "$BLESSED_VERSION" != "Unknown" ]; then - install_python3_and_deps "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR.$PYTHON_VERSION_BUILD" "$PYAML_VERSION_MAJOR.$PYAML_VERSION_MINOR.$PYAML_VERSION_BUILD" - else - install_python3_and_deps "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR.$PYTHON_VERSION_BUILD" - fi - return 1 - fi - else - install_python3_and_deps - return 1 - fi -} - -function do_env_setup() { - echo "Setting up environment:" - if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then - echo "User is NOT in 'bluetooth' group. Adding:" >&2 - echo "sudo usermod -G bluetooth -a $USER" >&2 - echo "You will need to restart your system before the changes take effect." - sudo -E usermod -G "bluetooth" -a $USER - fi - - if [ ! "$(user_in_group docker)" == "true" ]; then - echo "User is NOT in 'docker' group. Adding:" >&2 - echo "sudo usermod -G docker -a $USER" >&2 - echo "You will need to restart your system before the changes take effect." - sudo -E usermod -G "docker" -a $USER - fi -} - -function do_docker_checks() { - if command_exists docker; then - DOCKER_VERSION_GOOD="false" - DOCKER_VERSION=$(docker version -f "{{.Server.Version}}" 2>&1) - echo "Command: docker version -f \"{{.Server.Version}}\"" - if [[ "$DOCKER_VERSION" == *"Cannot connect to the Docker daemon"* ]]; then - echo "Error getting docker version. Error when connecting to docker daemon. Check that docker is running." - if (whiptail --title "Docker and Docker-Compose" --yesno "Error getting docker version. Error when connecting to docker daemon. Check that docker is running.\n\nCommand: docker version -f \"{{.Server.Version}}\"\n\nExit?" 20 78); then - exit 1 - fi - elif [[ "$DOCKER_VERSION" == *" permission denied"* ]]; then - echo "Error getting docker version. Received permission denied error. Try running with: ./menu.sh --run-env-setup" - if (whiptail --title "Docker and Docker-Compose" --yesno "Error getting docker version. Received permission denied error.\n\nTry rerunning the menu with: ./menu.sh --run-env-setup\n\nExit?" 20 78); then - exit 1 - fi - return 0 - fi - - if [[ -z "$DOCKER_VERSION" ]]; then - echo "Error getting docker version. Error when running docker command. Check that docker is installed correctly." - fi - - DOCKER_VERSION_MAJOR=$(echo "$DOCKER_VERSION"| cut -d'.' -f 1) - DOCKER_VERSION_MINOR=$(echo "$DOCKER_VERSION"| cut -d'.' -f 2) - - DOCKER_VERSION_BUILD=$(echo "$DOCKER_VERSION"| cut -d'.' -f 3) - DOCKER_VERSION_BUILD=$(echo "$DOCKER_VERSION_BUILD"| cut -f1 -d"-") - - if [ "$(minimum_version_check $REQ_DOCKER_VERSION $DOCKER_VERSION_MAJOR $DOCKER_VERSION_MINOR $DOCKER_VERSION_BUILD )" == "true" ]; then - [ -f .docker_outofdate ] && rm .docker_outofdate - DOCKER_VERSION_GOOD="true" - echo "Docker version $DOCKER_VERSION >= $REQ_DOCKER_VERSION. Docker is good to go." >&2 - else - if [ ! -f .docker_outofdate ]; then - if (whiptail --title "Docker and Docker-Compose Version Issue" --yesno "Docker version is currently $DOCKER_VERSION which is less than $REQ_DOCKER_VERSION consider upgrading or you may experience issues. You will not be prompted again. You can manually upgrade by typing:\n sudo apt upgrade docker docker-compose\n\nAttempt to upgrade now?" 20 78); then - update_docker - else - touch .docker_outofdate - fi - fi - fi - else - [ -f .docker_outofdate ] && rm .docker_outofdate - echo "Docker not installed" >&2 - if [ ! -f .docker_notinstalled ]; then - if (whiptail --title "Docker and Docker-Compose" --yesno "Docker is not currently installed, and is required to run IOTstack. Would you like to install docker and docker-compose now?\nYou will not be prompted again." 20 78); then - [ -f .docker_notinstalled ] && rm .docker_notinstalled - echo "Setting up environment:" - if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then - echo "User is NOT in 'bluetooth' group. Adding:" >&2 - echo "sudo usermod -G bluetooth -a $USER" >&2 - echo "You will need to restart your system before the changes take effect." - sudo -E usermod -G "bluetooth" -a $USER - fi - - if [ ! "$(user_in_group docker)" == "true" ]; then - echo "User is NOT in 'docker' group. Adding:" >&2 - echo "sudo usermod -G docker -a $USER" >&2 - echo "You will need to restart your system before the changes take effect." - sudo -E usermod -G "docker" -a $USER - fi - install_docker - else - touch .docker_notinstalled - fi - fi - fi -} - -function do_project_checks() { +function project_checks() { echo "Checking for project update" >&2 git fetch origin $CURRENT_BRANCH if [[ "$(check_git_updates)" == "Need to pull" ]]; then echo "An update is available for IOTstack" >&2 - if [ ! -f .project_outofdate ]; then + if [ ! -f .ignore_project_outofdate ]; then if (whiptail --title "Project update" --yesno "An update is available for IOTstack\nYou will not be reminded again until after you update.\nYou can upgrade manually by typing:\n git pull origin $CURRENT_BRANCH \n\n\nWould you like to update now?" 14 78); then update_project else - touch .project_outofdate + touch .ignore_project_outofdate fi fi else - [ -f .project_outofdate ] && rm .project_outofdate + [ -f .ignore_project_outofdate ] && rm .ignore_project_outofdate echo "Project is up to date" >&2 fi } -function do_env_checks() { - GROUPSGOOD=0 - - if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then - GROUPSGOOD=1 - echo "User is NOT in 'bluetooth' group" >&2 - fi - - if [[ ! "$(user_in_group docker)" == "true" ]]; then - GROUPSGOOD=1 - echo "User is NOT in 'docker' group" >&2 - fi - - if [ "$GROUPSGOOD" == 1 ]; then - echo "!! You might experience issues with docker or bluetooth. To fix run: ./menu.sh --run-env-setup" - fi -} - # ---------------------------------------------- # Menu bootstrap entry point # ---------------------------------------------- - if [[ "$*" == *"--no-check"* ]]; then echo "Skipping preflight checks." else - do_project_checks - do_env_checks - do_python3_checks echo "Please enter sudo pasword if prompted" - do_docker_checks - if [[ "$DOCKER_VERSION_GOOD" == "true" ]] && \ - [[ "$PYTHON_VERSION_GOOD" == "true" ]] && \ - [[ "$PYAML_VERSION_GOOD" == "true" ]] && \ - [[ "$BLESSED_GOOD" == "true" ]]; then + project_checks + + if [[ "$(docker_checks)" == "fail" ]]; then + echo "Docker is not setup." + if (whiptail --title "Install Docker" --yesno "Docker or docker-compose doesn't seem to be installed. After installation the system will need to be rebooted.\r\n\r\nInstall Docker and docker-compose now?" 14 78); then + docker_installed_check + fi + fi + + if [[ "$(group_check)" == "fail" ]]; then + echo "User not in correct groups. Run:" + echo "bash ./menu.sh --run-env-setup" + fi + + if [[ "$DOCKER_VERSION_GOOD" == "true" ]]; then echo "Project dependencies up to date" echo "" else @@ -392,8 +100,10 @@ do ;; --no-check) echo "" ;; - --run-env-setup) # Sudo cannot be run from inside functions without -E flag. + --run-env-setup) echo "Setting up environment:" + generate_container_ssh + install_ssh_keys if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then echo "User is NOT in 'bluetooth' group. Adding:" >&2 echo "sudo -E usermod -G bluetooth -a $USER" >&2 @@ -416,21 +126,6 @@ do shift done -# This section is temporary, it's just for notifying people of potential breaking changes. -if [[ -f .new_install ]]; then - echo "Existing installation detected." -else - if [[ -f docker-compose.yml ]]; then - echo "Warning: Please ensure to read the following prompt" - sleep 1 - if (whiptail --title "Project update" --yesno "There has been a large update to IOTstack, and there may be breaking changes to your current setup. Would you like to switch to the older branch by having the command:\ngit checkout old-menu\n\nrun for you?\n\nIt's suggested that you backup your existing IOTstack instance if you select No\n\nIf you run into problems, please open an issue: https://github.com/SensorsIot/IOTstack/issues\n\nOr Discord: https://discord.gg/ZpKHnks\n\nRelease Notes: https://github.com/SensorsIot/IOTstack/blob/master/docs/New-Menu-Release-Notes.md" 24 95); then - echo "Running command: git checkout old-menu" - git checkout old-menu - sleep 2 - fi - fi - touch .new_install -fi - # Hand control to new menu -$PYTHON_CMD ./scripts/menu_main.py $ENCODING_TYPE +echo "Started!" +# $PYTHON_CMD ./scripts/menu_main.py $ENCODING_TYPE diff --git a/scripts/deps/__init__.py b/scripts/deps/__init__.py deleted file mode 100755 index e69de29bb..000000000 diff --git a/scripts/deps/chars.py b/scripts/deps/chars.py deleted file mode 100755 index 51cfa0d77..000000000 --- a/scripts/deps/chars.py +++ /dev/null @@ -1,72 +0,0 @@ -specialChars = { - "latin": { - "rightArrowFull": "►", - "upArrowFull": "▲", - "upArrowLine": "↑", - "downArrowFull": "▼", - "downArrowLine": "↓", - "borderVertical": "║", - "borderHorizontal": "═", - "borderTopLeft": "╔", - "borderTopRight": "╗", - "borderBottomLeft": "╚", - "borderBottomRight": "╝" - }, - "simple": { - "rightArrowFull": "→", - "upArrowFull": "↑", - "upArrowLine": "↑", - "downArrowFull": "↓", - "downArrowLine": "↓", - "borderVertical": "│", - "borderHorizontal": "─", - "borderTopLeft": "┌", - "borderTopRight": "┐", - "borderBottomLeft": "└", - "borderBottomRight": "┘" - }, - "ascii": { - "rightArrowFull": ">", - "upArrowFull": "^", - "upArrowLine": "^", - "downArrowFull": "v", - "downArrowLine": "v", - "borderVertical": "|", - "borderHorizontal": "-", - "borderTopLeft": "/", - "borderTopRight": "\\", - "borderBottomLeft": "\\", - "borderBottomRight": "/" - } -} - -def commonTopBorder(renderMode, size=80): - output = "" - output += "{btl}".format(btl=specialChars[renderMode]["borderTopLeft"]) - for i in range(size): - output += "{bh}".format(bh=specialChars[renderMode]["borderHorizontal"]) - output += "{btr}".format(btr=specialChars[renderMode]["borderTopRight"]) - return output - -def commonBottomBorder(renderMode, size=80): - output = "" - output += "{bbl}".format(bbl=specialChars[renderMode]["borderBottomLeft"]) - for i in range(size): - output += "{bh}".format(bh=specialChars[renderMode]["borderHorizontal"]) - output += "{bbr}".format(bbr=specialChars[renderMode]["borderBottomRight"]) - return output - -def padText(text, size=45): - output = "" - output += text - for i in range(size - len(text)): - output += " " - return output - -def commonEmptyLine(renderMode, size=80): - output = "" - output += "{bv}".format(bv=specialChars[renderMode]["borderVertical"]) - for i in range(size): - output += " " - output += "{bv}".format(bv=specialChars[renderMode]["borderVertical"]) - return output diff --git a/scripts/deps/common_functions.py b/scripts/deps/common_functions.py deleted file mode 100755 index b4309df48..000000000 --- a/scripts/deps/common_functions.py +++ /dev/null @@ -1,190 +0,0 @@ -import time -import string -import random -import sys -import os -import subprocess -from deps.consts import ifCheckList - -def generateRandomString(size = 0, chars = string.ascii_uppercase + string.ascii_lowercase + string.digits): - if size == 0: - size = random.randint(16, 24) - return ''.join(random.choice(chars) for _ in range(size)) - -def getNetworkDetails(inputList = None): - ifList = inputList - if (inputList == None): - ifList = ifCheckList - - results = { - "name": "", - "mac": "", - "ip": "" - } - - for (index, ifName) in enumerate(ifList): - try: - ip = getIpAddress(ifName) - mac = getMacAddress(ifName) - results["name"] = ifName - results["ip"] = ip - results["mac"] = mac - if (results["ip"] == "" or results["mac"] == ""): - continue - break - except: - continue - # pass - - return results - -def getMacAddress(ifName = None): - if (ifName == None): - print("getMacAddress: Need interface name") - return "" - - mac = "" - - if sys.platform == 'win32': - print("getMacAddress: Linux support only") - else: - FNULL = open(os.devnull, 'w') - ipRes = subprocess.Popen("/sbin/ifconfig %s" % ifName, shell=True, stdout=subprocess.PIPE, stderr=FNULL).communicate() - for line in ipRes[0].decode('utf-8').splitlines(): - if line.find('Ethernet') > -1: - mac = line.split()[1] - break - return mac - -def getIpAddress(ifName = None): - if (ifName == None): - print("getIpAddress: Need interface name") - return "" - - ip = "" - - if sys.platform == 'win32': - print("getIpAddress: Linux support only") - else: - FNULL = open(os.devnull, 'w') - ipRes = subprocess.Popen("/sbin/ifconfig %s" % ifName, shell=True, stdout=subprocess.PIPE, stderr=FNULL).communicate() - for line in ipRes[0].decode('utf-8').splitlines(): - if line.find('inet') > -1: - ip = line.split()[1] - break - return ip - -def getExternalPorts(serviceName, dockerComposeServicesYaml): - externalPorts = [] - try: - yamlService = dockerComposeServicesYaml[serviceName] - if "ports" in yamlService: - for (index, port) in enumerate(yamlService["ports"]): - try: - externalAndInternal = port.split(":") - externalPorts.append(externalAndInternal[0]) - except: - pass - except: - pass - return externalPorts - -def getInternalPorts(serviceName, dockerComposeServicesYaml): - externalPorts = [] - try: - yamlService = dockerComposeServicesYaml[serviceName] - if "ports" in yamlService: - for (index, port) in enumerate(yamlService["ports"]): - try: - externalAndInternal = port.split(":") - externalPorts.append(externalAndInternal[1]) - except: - pass - except: - pass - return externalPorts - -def checkPortConflicts(serviceName, currentPorts, dockerComposeServicesYaml): - portConflicts = [] - yamlService = dockerComposeServicesYaml[serviceName] - servicePorts = getExternalPorts(serviceName, dockerComposeServicesYaml) - for (index, servicePort) in enumerate(servicePorts): - for (index, currentPort) in enumerate(currentPorts): - if (servicePort == currentPort): - portConflicts.append([servicePort, serviceName]) - return portConflicts - -def checkDependsOn(serviceName, dockerComposeServicesYaml): - missingServices = [] - yamlService = dockerComposeServicesYaml[serviceName] - if "depends_on" in yamlService: - for (index, dependsOnName) in enumerate(yamlService["depends_on"]): - if not dependsOnName in dockerComposeServicesYaml: - missingServices.append([dependsOnName, serviceName]) - return missingServices - -def enterPortNumber(term, dockerComposeServicesYaml, currentServiceName, hotzoneLocation, createMenuFn): - newPortNumber = "" - try: - print(term.move_y(hotzoneLocation[0])) - print(term.center(" ")) - print(term.center(" ")) - print(term.center(" ")) - print(term.move_y(hotzoneLocation[0] + 1)) - time.sleep(0.1) # Prevent loop - newPortNumber = input(term.center("Enter new port number: ")) - # newPortNumber = sys.stdin.readline() - time.sleep(0.1) # Prevent loop - newPortNumber = int(str(newPortNumber)) - if 1 <= newPortNumber <= 65535: - time.sleep(0.2) # Prevent loop - internalPort = getInternalPorts(currentServiceName, dockerComposeServicesYaml)[0] - dockerComposeServicesYaml[currentServiceName]["ports"][0] = "{newExtPort}:{oldIntPort}".format( - newExtPort = newPortNumber, - oldIntPort = internalPort - ) - createMenuFn() - return True - else: - print(term.center(' {t.white_on_red} "{port}" {message} {t.normal} <-'.format(t=term, port=newPortNumber, message="is not a valid port"))) - time.sleep(2) # Give time to read error - return False - except Exception as err: - print(term.center(' {t.white_on_red} "{port}" {message} {t.normal} <-'.format(t=term, port=newPortNumber, message="is not a valid port"))) - print(term.center(' {t.white_on_red} Error: {errorMsg} {t.normal} <-'.format(t=term, errorMsg=err))) - time.sleep(2.5) # Give time to read error - return False - -def enterPortNumberWithWhiptail(term, dockerComposeServicesYaml, currentServiceName, hotzoneLocation, defaultPort): - newPortNumber = "" - try: - portProcess = subprocess.Popen(['./scripts/deps/portWhiptail.sh', defaultPort, currentServiceName], stdout=subprocess.PIPE) - portResult = portProcess.communicate()[0] - portResult = portResult.decode("utf-8").split(",") - newPortNumber = portResult[0] - returnCode = portResult[1] - time.sleep(0.1) # Prevent loop - - if not returnCode == "0": - return -1 - - newPortNumber = int(str(newPortNumber)) - if 1 <= newPortNumber <= 65535: - time.sleep(0.2) # Prevent loop - return newPortNumber - else: - print(term.center(' {t.white_on_red} "{port}" {message} {t.normal} <-'.format(t=term, port=newPortNumber, message="is not a valid port"))) - time.sleep(2) # Give time to read error - return -1 - except Exception as err: - print(term.center(' {t.white_on_red} "{port}" {message} {t.normal} <-'.format(t=term, port=newPortNumber, message="is not a valid port"))) - print(term.center(' {t.white_on_red} Error: {errorMsg} {t.normal} <-'.format(t=term, errorMsg=err))) - time.sleep(2.5) # Give time to read error - return -1 - -def literalPresenter(dumper, data): - if isinstance(data, str) and "\n" in data: - return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') - # if isinstance(data, None): - # return self.represent_scalar('tag:yaml.org,2002:null', u'') - return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"') \ No newline at end of file diff --git a/scripts/deps/consts.py b/scripts/deps/consts.py deleted file mode 100755 index 9e055cab8..000000000 --- a/scripts/deps/consts.py +++ /dev/null @@ -1,12 +0,0 @@ -servicesDirectory = './services/' -templatesDirectory = './.templates/' -volumesDirectory = './volumes/' -tempDirectory = './.tmp/' -scriptsDirectory = './scripts/' -buildSettingsFileName = '/build_settings.yml' -buildCache = servicesDirectory + 'docker-compose.save.yml' -composeOverrideFile = './compose-override.yml' -envFile = templatesDirectory + 'env.yml' -dockerPathOutput = './docker-compose.yml' -servicesFileName = 'service.yml' -ifCheckList = ['eth0', 'wlan0'] diff --git a/scripts/deps/version_check.py b/scripts/deps/version_check.py deleted file mode 100755 index aa3a272e1..000000000 --- a/scripts/deps/version_check.py +++ /dev/null @@ -1,36 +0,0 @@ -def checkVersion(requiredVersion, currentVersion): - requiredSplit = requiredVersion.split('.') - - if len(requiredSplit) < 2: - return False, 'Invalid Required Version', requiredVersion - - try: - requiredMajor = int(requiredSplit[0]) - requiredMinor = int(requiredSplit[1]) - requiredBuild = int(requiredSplit[2]) - except: - return False, 'Invalid Required Version', requiredVersion - - currentSplit = currentVersion.split('.') - - if len(currentSplit) < 2: - return False, 'Invalid Current Version', currentVersion - - try: - currentMajor = int(currentSplit[0]) - currentMinor = int(currentSplit[1]) - currentBuild = currentSplit[2].split("-")[0] - currentBuild = int(currentBuild) - except: - return False, 'Invalid Current Version', currentVersion - - if currentMajor > requiredMajor: - return True, '', [] - - if currentMajor == requiredMajor and currentMajor > requiredMinor: - return True, '', [] - - if currentMajor == requiredMajor and currentMinor == requiredMinor and currentBuild >= requiredBuild: - return True, '', [] - - return False, 'Version Check Fail', [currentMajor == requiredMajor, currentMinor == requiredMinor, currentBuild >= requiredBuild] \ No newline at end of file diff --git a/scripts/deps/yaml_merge.py b/scripts/deps/yaml_merge.py deleted file mode 100755 index fa953a337..000000000 --- a/scripts/deps/yaml_merge.py +++ /dev/null @@ -1,17 +0,0 @@ - -def mergeYaml(priorityYaml, defaultYaml): - finalYaml = {} - if isinstance(defaultYaml, dict): - for dk, dv in defaultYaml.items(): - if dk in priorityYaml: - finalYaml[dk] = mergeYaml(priorityYaml[dk], dv) - else: - finalYaml[dk] = dv - for pk, pv in priorityYaml.items(): - if pk in finalYaml: - finalYaml[pk] = mergeYaml(finalYaml[pk], pv) - else: - finalYaml[pk] = pv - else: - finalYaml = defaultYaml - return finalYaml diff --git a/scripts/python_deps_check.py b/scripts/python_deps_check.py deleted file mode 100755 index 115e6540b..000000000 --- a/scripts/python_deps_check.py +++ /dev/null @@ -1,34 +0,0 @@ -import sys -import yaml -import blessed -import ruamel.yaml - -if sys.argv[1] == "--pyyaml-version": - try: - print("pyyaml", yaml.__version__) - sys.exit(0) - except SystemExit: - sys.exit(0) - except: - print("could not get pyyaml version") - sys.exit(3) - -if sys.argv[1] == "--pyaml-version": - try: - print("ruamel.yaml", ruamel.yaml.__version__) - sys.exit(0) - except SystemExit: - sys.exit(0) - except: - print("could not get ruamel.yaml version") - sys.exit(3) - -if sys.argv[1] == "--blessed-version": - try: - print("blessed", blessed.__version__) - sys.exit(0) - except SystemExit: - sys.exit(0) - except: - print("could not get blessed version") - sys.exit(3) diff --git a/scripts/setup_iotstack.sh b/scripts/setup_iotstack.sh new file mode 100644 index 000000000..28edc7140 --- /dev/null +++ b/scripts/setup_iotstack.sh @@ -0,0 +1,184 @@ +#!/bin/bash + +# Minimum Software Versions +REQ_DOCKER_VERSION=18.2.0 + +# Required to generate and install a ssh key so menu containers can securely execute commands on host +AUTH_KEYS_FILE=~/.ssh/authorized_keys +CONTAINER_KEYS_FILE=./.internal/.ssh/id_rsa + +function command_exists() { + command -v "$@" > /dev/null 2>&1 +} + +function minimum_version_check() { + # Usage: minimum_version_check required_version current_major current_minor current_build + # Example: minimum_version_check "1.2.3" 1 2 3 + REQ_MIN_VERSION_MAJOR=$(echo "$1"| cut -d' ' -f 2 | cut -d'.' -f 1) + REQ_MIN_VERSION_MINOR=$(echo "$1"| cut -d' ' -f 2 | cut -d'.' -f 2) + REQ_MIN_VERSION_BUILD=$(echo "$1"| cut -d' ' -f 2 | cut -d'.' -f 3) + + CURR_VERSION_MAJOR=$2 + CURR_VERSION_MINOR=$3 + CURR_VERSION_BUILD=$4 + + VERSION_GOOD="Unknown" + + if [ -z "$CURR_VERSION_MAJOR" ]; then + echo "$VERSION_GOOD" + return 1 + fi + + if [ -z "$CURR_VERSION_MINOR" ]; then + echo "$VERSION_GOOD" + return 1 + fi + + if [ -z "$CURR_VERSION_BUILD" ]; then + echo "$VERSION_GOOD" + return 1 + fi + + if [ "${CURR_VERSION_MAJOR}" -ge $REQ_MIN_VERSION_MAJOR ]; then + VERSION_GOOD="true" + echo "$VERSION_GOOD" + return 0 + else + VERSION_GOOD="false" + fi + + if [ "${CURR_VERSION_MAJOR}" -ge $REQ_MIN_VERSION_MAJOR ] && \ + [ "${CURR_VERSION_MINOR}" -ge $REQ_MIN_VERSION_MINOR ]; then + VERSION_GOOD="true" + echo "$VERSION_GOOD" + return 0 + else + VERSION_GOOD="false" + fi + + if [ "${CURR_VERSION_MAJOR}" -ge $REQ_MIN_VERSION_MAJOR ] && \ + [ "${CURR_VERSION_MINOR}" -ge $REQ_MIN_VERSION_MINOR ] && \ + [ "${CURR_VERSION_BUILD}" -ge $REQ_MIN_VERSION_BUILD ]; then + VERSION_GOOD="true" + echo "$VERSION_GOOD" + return 0 + else + VERSION_GOOD="false" + fi + + echo "$VERSION_GOOD" +} + +function user_in_group() +{ + if grep -q $1 /etc/group ; then + if id -nGz "$USER" | grep -qzxF "$1"; then + echo "true" + else + echo "false" + fi + else + echo "notgroup" + fi +} + +function install_docker() { + if command_exists docker; then + echo "Docker already installed" >&2 + else + echo "Install Docker" >&2 + curl -fsSL https://get.docker.com | sh + sudo -E usermod -aG docker $USER + fi + + if command_exists docker-compose; then + echo "docker-compose already installed" >&2 + else + echo "Install docker-compose" >&2 + sudo -E apt install -y docker-compose + fi + + echo "" >&2 + echo "You should now restart your system" >&2 +} + +function docker_installed_check() { + DOCKER_GOOD="pass" + if ! command_exists docker; then + DOCKER_GOOD="fail" + echo "Docker is installed" >&2 + fi + + if ! command_exists docker-compose; then + DOCKER_GOOD="fail" + echo "docker-compose is installed" >&2 + fi + + echo $DOCKER_GOOD +} + +function group_setup() { + echo "Setting up groups:" + if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then + echo "User is NOT in 'bluetooth' group. Adding:" >&2 + echo "sudo usermod -G bluetooth -a $USER" >&2 + sudo -E usermod -G "bluetooth" -a $USER + fi + + if [ ! "$(user_in_group docker)" == "true" ]; then + echo "User is NOT in 'docker' group. Adding:" >&2 + echo "sudo usermod -G docker -a $USER" >&2 + sudo -E usermod -G "docker" -a $USER + fi + + echo "" >&2 + echo "Rebooting or logging off is advised." >&2 +} + +function group_check() { + echo "Setting up groups:" + NEED_GROUP_SETUP="false" + if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then + NEED_GROUP_SETUP="fail" + echo "User is NOT in 'bluetooth' group." >&2 + fi + + if [ ! "$(user_in_group docker)" == "true" ]; then + NEED_GROUP_SETUP="fail" + echo "User is NOT in 'docker' group." >&2 + fi + + echo $NEED_GROUP_SETUP +} + +function do_env_setup() { + sudo -E apt-get install git wget unzip -y +} + +function generate_container_ssh() { + cat /dev/null | ssh-keygen -q -N "" -f $CONTAINER_KEYS_FILE +} + +function install_ssh_keys() { + if [ -f "$CONTAINER_KEYS_FILE" ]; then + NEW_KEY="$(cat $CONTAINER_KEYS_FILE.pub)" + if grep -Fxq "$NEW_KEY" $AUTH_KEYS_FILE ; then + echo "Key already exists in '$AUTH_KEYS_FILE' Skipping..." + else + echo "$NEW_KEY" >> $AUTH_KEYS_FILE + echo "Key added." + fi + fi +} + +function do_iotstack_setup() { + git clone https://github.com/SensorsIot/IOTstack.git + cd IOTstack + + if [ $? -eq 0 ]; then + echo "IOTstack cloned" + else + echo "Could not find IOTstack directory" + exit 5 + fi +} diff --git a/scripts/yaml_merge.py b/scripts/yaml_merge.py deleted file mode 100755 index ad7477ac0..000000000 --- a/scripts/yaml_merge.py +++ /dev/null @@ -1,71 +0,0 @@ -import sys -import traceback -import ruamel.yaml - -yaml = ruamel.yaml.YAML() -yaml.preserve_quotes = True - -if sys.argv[1] == "--pyyaml-version": - try: - print("pyyaml", yaml.__version__) - sys.exit(0) - except SystemExit: - sys.exit(0) - except: - print("could not get pyyaml version") - sys.exit(3) - -if len(sys.argv) < 4: - print("Error: Not enough args") - print("Usage:") - print(" yaml_merge.py [inputFile] [mergeFile] [outputFile]") - print("") - print("Example:") - print(" yaml_merge.py ./.tmp/docker-compose.tmp.yml ./compose-override.yml ./docker-compose.yml") - sys.exit(4) - -try: - pathTempDockerCompose = sys.argv[1] - pathOverride = sys.argv[2] - pathOutput = sys.argv[3] - - def mergeYaml(priorityYaml, defaultYaml): - finalYaml = {} - if isinstance(defaultYaml, dict): - for dk, dv in defaultYaml.items(): - if dk in priorityYaml: - finalYaml[dk] = mergeYaml(priorityYaml[dk], dv) - else: - finalYaml[dk] = dv - for pk, pv in priorityYaml.items(): - if pk in finalYaml: - finalYaml[pk] = mergeYaml(finalYaml[pk], pv) - else: - finalYaml[pk] = pv - else: - finalYaml = defaultYaml - return finalYaml - - with open(r'%s' % pathTempDockerCompose) as fileTempDockerCompose: - yamlTempDockerCompose = yaml.load(fileTempDockerCompose) - - with open(r'%s' % pathOverride) as fileOverride: - yamlOverride = yaml.load(fileOverride) - - mergedYaml = mergeYaml(yamlOverride, yamlTempDockerCompose) - - with open(r'%s' % pathOutput, 'w') as outputFile: - yaml.dump(mergedYaml, outputFile, explicit_start=True, default_style='"') - - sys.exit(0) -except SystemExit: - sys.exit(0) -except: - print("Something went wrong: ") - print(sys.exc_info()) - print(traceback.print_exc()) - print("") - print("") - print("PyYaml Version: ", yaml.__version__) - print("") - sys.exit(2) From 8c4fd931b74722853cafa4c0f21f6c0f13ab02f1 Mon Sep 17 00:00:00 2001 From: Slyke Date: Sun, 17 Jan 2021 05:33:46 -0800 Subject: [PATCH 004/142] Finished install script. Worked on menu script --- .internal/api.Dockerfile | 2 +- .internal/ctrl_api.sh | 41 ++++--- .internal/ctrl_cli.sh | 51 --------- .internal/ctrl_pycli.sh | 60 +++++++++++ .internal/ctrl_wui.sh | 11 +- .internal/docker_menu.sh | 12 +-- .internal/meta.sh | 5 + .../{cli.Dockerfile => pycli.Dockerfile} | 4 +- .internal/{cli => pycli}/backup_restore.py | 0 .internal/{cli => pycli}/buildstack_menu.py | 0 .internal/{cli => pycli}/docker_commands.py | 0 .internal/{cli => pycli}/entry.py | 0 .internal/{cli => pycli}/menu_main.py | 0 .internal/{cli => pycli}/misc_commands.py | 0 .internal/{cli => pycli}/native_installs.py | 0 .internal/{cli => pycli}/requirements.txt | 0 .internal/wui.Dockerfile | 2 +- install.sh | 101 ++++++++++++++---- menu.sh | 78 ++++++++++---- scripts/setup_iotstack.sh | 32 ++++-- test.sh | 3 + 21 files changed, 272 insertions(+), 130 deletions(-) delete mode 100644 .internal/ctrl_cli.sh create mode 100644 .internal/ctrl_pycli.sh create mode 100644 .internal/meta.sh rename .internal/{cli.Dockerfile => pycli.Dockerfile} (64%) rename .internal/{cli => pycli}/backup_restore.py (100%) rename .internal/{cli => pycli}/buildstack_menu.py (100%) rename .internal/{cli => pycli}/docker_commands.py (100%) rename .internal/{cli => pycli}/entry.py (100%) rename .internal/{cli => pycli}/menu_main.py (100%) rename .internal/{cli => pycli}/misc_commands.py (100%) rename .internal/{cli => pycli}/native_installs.py (100%) rename .internal/{cli => pycli}/requirements.txt (100%) create mode 100644 test.sh diff --git a/.internal/api.Dockerfile b/.internal/api.Dockerfile index c8a5aaa35..f30272e4b 100644 --- a/.internal/api.Dockerfile +++ b/.internal/api.Dockerfile @@ -3,7 +3,7 @@ FROM node:14 WORKDIR /usr/iotstack_api # node_modules is ignored with this copy, as specified in .dockerignore -COPY api ./ +COPY ./.internal/api ./ RUN npm install EXPOSE 32128 diff --git a/.internal/ctrl_api.sh b/.internal/ctrl_api.sh index f3b8cff09..703936706 100644 --- a/.internal/ctrl_api.sh +++ b/.internal/ctrl_api.sh @@ -1,14 +1,19 @@ #!/bin/bash -VERSION=v0.0.1 +source ./.internal/meta.sh DNAME=iostack_api FULL_NAME="$DNAME:$VERSION" if [[ $IOTENV == "development" ]]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force - docker build --no-cache -t $FULL_NAME -f api.Dockerfile . + docker build --no-cache -t $FULL_NAME -f ./.internal/api.Dockerfile . else - docker build -t $FULL_NAME -f api.Dockerfile . + if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then + echo "Building '$FULL_NAME'" + docker build --quiet -t $FULL_NAME -f ./.internal/api.Dockerfile . + else + echo "Build for '$FULL_NAME' already exists. Skipping..." + fi fi if [ "$1" = "stop" ]; then @@ -17,27 +22,33 @@ else if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then echo "Starting IOTstack API Server" # docker run -d -p 32128:32128 \ - # --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ - # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds \ - # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ - # -e HOSTUSER="$(whoami)" \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + # -e HOSTUSER="$HOSTUSER" \ + # -e IOTSTACKPWD="$IOTSTACKPWD" \ + # -e CORS="list,of,ip,addresses" \ # --restart unless-stopped \ # $FULL_NAME # docker run -p 32128:32128 \ - # --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ - # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ - # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ # -e cors="yourLanIpHere:32777" \ - # -e HOSTUSER="$(whoami)" \ + # -e HOSTUSER="$HOSTUSER" \ + # -e IOTSTACKPWD="$IOTSTACKPWD" \ + # -e CORS="list,of,ip,addresses" \ # --restart unless-stopped \ # $FULL_NAME docker run -p 32128:32128 \ - --mount type=bind,source="$(pwd)"/templates,target=/usr/iotstack_api/templates,readonly \ - --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ - --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ - -e HOSTUSER="$(whoami)" \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + -e HOSTUSER="$HOSTUSER" \ + -e IOTSTACKPWD="$IOTSTACKPWD" \ + # -e CORS="list,of,ip,addresses" \ --restart unless-stopped \ -it $FULL_NAME /bin/bash else diff --git a/.internal/ctrl_cli.sh b/.internal/ctrl_cli.sh deleted file mode 100644 index b96cdd992..000000000 --- a/.internal/ctrl_cli.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -VERSION=v0.0.1 -DNAME=iostack_cli -FULL_NAME="$DNAME:$VERSION" - -if [[ $IOTENV == "development" ]]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force - docker build --no-cache -t $FULL_NAME -f cli.Dockerfile . -else - docker build --quiet -t $FULL_NAME -f cli.Dockerfile . -fi - -if [ "$1" = "stop" ]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) -else - if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then - echo "Starting IOTstack CLI instance" - - docker run \ - --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ - --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ - -e HOSTUSER="$(whoami)" \ - --restart no \ - -it $FULL_NAME - - # docker run -d \ - # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds \ - # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ - # -e HOSTUSER="$(whoami)" \ - # --restart no \ - # $FULL_NAME - - # docker run \ - # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ - # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ - # -e cors="yourLanIpHere:32777" \ - # -e HOSTUSER="$(whoami)" \ - # --restart no \ - # $FULL_NAME - - # docker run \ - # --mount type=bind,source="$(pwd)"/saved_builds,target=/usr/iotstack_api/builds,readonly \ - # --mount type=bind,source="$(pwd)"/.ssh,target=/root/.ssh,readonly \ - # -e HOSTUSER="$(whoami)" \ - # --restart no \ - # -it $FULL_NAME /bin/bash - else - echo "IOTstack CLI is running. Check with 'docker ps'." - fi -fi diff --git a/.internal/ctrl_pycli.sh b/.internal/ctrl_pycli.sh new file mode 100644 index 000000000..c595c3a79 --- /dev/null +++ b/.internal/ctrl_pycli.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +source ./.internal/meta.sh +DNAME=iostack_pycli +FULL_NAME="$DNAME:$VERSION" + +if [[ $IOTENV == "development" ]]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker build --no-cache -t $FULL_NAME -f ./.internal/pycli.Dockerfile . +else + if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then + echo "Building '$FULL_NAME'" + docker build --quiet -t $FULL_NAME -f ./.internal/pycli.Dockerfile . + else + echo "Build for '$FULL_NAME' already exists. Skipping..." + fi +fi + +if [ "$1" = "stop" ]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) +else + if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then + echo "Starting IOTstack PyCLI instance" + + docker run \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + -e HOSTUSER="$HOSTUSER" \ + -e IOTSTACKPWD="$IOTSTACKPWD" \ + --restart no \ + -it $FULL_NAME + + # docker run -d \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + # -e HOSTUSER="$HOSTUSER" \ + # -e IOTSTACKPWD="$IOTSTACKPWD" \ + # --restart no \ + # $FULL_NAME + + # docker run \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + # -e cors="yourLanIpHere:32777" \ + # -e HOSTUSER="$HOSTUSER" \ + # -e IOTSTACKPWD="$IOTSTACKPWD" \ + # --restart no \ + # $FULL_NAME + + # docker run \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + # -e HOSTUSER="$HOSTUSER" \ + # -e IOTSTACKPWD="$IOTSTACKPWD" \ + # --restart no \ + # -it $FULL_NAME /bin/bash + else + echo "IOTstack CLI is running. Check with 'docker ps'." + fi +fi diff --git a/.internal/ctrl_wui.sh b/.internal/ctrl_wui.sh index f9a6a9525..7952d3ce7 100644 --- a/.internal/ctrl_wui.sh +++ b/.internal/ctrl_wui.sh @@ -1,14 +1,19 @@ #!/bin/bash -VERSION=v0.0.1 +source ./.internal/meta.sh DNAME=iostack_wui FULL_NAME="$DNAME:$VERSION" if [[ $IOTENV == "development" ]]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force - docker build --no-cache -t $FULL_NAME -f wui.Dockerfile . + docker build --no-cache -t $FULL_NAME -f ./.internal/wui.Dockerfile . else - docker build -t $FULL_NAME -f wui.Dockerfile . + if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then + echo "Building '$FULL_NAME'" + docker build --quiet -t $FULL_NAME -f ./.internal/wui.Dockerfile . + else + echo "Build for '$FULL_NAME' already exists. Skipping..." + fi fi if [ "$1" = "stop" ]; then diff --git a/.internal/docker_menu.sh b/.internal/docker_menu.sh index 345b7b0ce..734940f81 100644 --- a/.internal/docker_menu.sh +++ b/.internal/docker_menu.sh @@ -1,11 +1,11 @@ #!/bin/bash if [ "$1" = "stop" ]; then - bash ./ctrl_api.sh stop - bash ./ctrl_wui.sh stop - # bash ./ctrl_cli.sh stop + bash ./.internal/ctrl_api.sh stop + bash ./.internal/ctrl_wui.sh stop + bash ./.internal/ctrl_pycli.sh stop else - bash ./ctrl_api.sh - bash ./ctrl_wui.sh - # bash ./ctrl_cli.sh + bash ./.internal/ctrl_api.sh + bash ./.internal/ctrl_wui.sh + bash ./.internal/ctrl_pycli.sh fi diff --git a/.internal/meta.sh b/.internal/meta.sh new file mode 100644 index 000000000..6ecdccf2e --- /dev/null +++ b/.internal/meta.sh @@ -0,0 +1,5 @@ +VERSION="v0.0.1" +IOTSTACKPWD="$(pwd)" +HOSTUSER="$(whoami)" +HOSTSSH_IP="host.docker.internal" +HOSTSSH_PORT="22" diff --git a/.internal/cli.Dockerfile b/.internal/pycli.Dockerfile similarity index 64% rename from .internal/cli.Dockerfile rename to .internal/pycli.Dockerfile index 0f1868a02..29874222c 100644 --- a/.internal/cli.Dockerfile +++ b/.internal/pycli.Dockerfile @@ -1,8 +1,8 @@ FROM python:3 -WORKDIR /usr/iotstack_cli +WORKDIR /usr/iotstack_pycli -COPY cli ./ +COPY ./.internal/pycli ./ RUN pip install --no-cache-dir -r requirements.txt CMD [ "python", "./entry.py" ] diff --git a/.internal/cli/backup_restore.py b/.internal/pycli/backup_restore.py similarity index 100% rename from .internal/cli/backup_restore.py rename to .internal/pycli/backup_restore.py diff --git a/.internal/cli/buildstack_menu.py b/.internal/pycli/buildstack_menu.py similarity index 100% rename from .internal/cli/buildstack_menu.py rename to .internal/pycli/buildstack_menu.py diff --git a/.internal/cli/docker_commands.py b/.internal/pycli/docker_commands.py similarity index 100% rename from .internal/cli/docker_commands.py rename to .internal/pycli/docker_commands.py diff --git a/.internal/cli/entry.py b/.internal/pycli/entry.py similarity index 100% rename from .internal/cli/entry.py rename to .internal/pycli/entry.py diff --git a/.internal/cli/menu_main.py b/.internal/pycli/menu_main.py similarity index 100% rename from .internal/cli/menu_main.py rename to .internal/pycli/menu_main.py diff --git a/.internal/cli/misc_commands.py b/.internal/pycli/misc_commands.py similarity index 100% rename from .internal/cli/misc_commands.py rename to .internal/pycli/misc_commands.py diff --git a/.internal/cli/native_installs.py b/.internal/pycli/native_installs.py similarity index 100% rename from .internal/cli/native_installs.py rename to .internal/pycli/native_installs.py diff --git a/.internal/cli/requirements.txt b/.internal/pycli/requirements.txt similarity index 100% rename from .internal/cli/requirements.txt rename to .internal/pycli/requirements.txt diff --git a/.internal/wui.Dockerfile b/.internal/wui.Dockerfile index b8f744005..94a5b7a40 100644 --- a/.internal/wui.Dockerfile +++ b/.internal/wui.Dockerfile @@ -3,7 +3,7 @@ FROM node:alpine WORKDIR /usr/iotstack_wui # node_modules is ignored with this copy, as specified in .dockerignore -COPY wui ./ +COPY ./.internal/wui ./ RUN npm install EXPOSE 32777 diff --git a/install.sh b/install.sh index 157176e6a..782746e57 100755 --- a/install.sh +++ b/install.sh @@ -6,26 +6,35 @@ REQ_DOCKER_VERSION=18.2.0 # Required to generate and install a ssh key so menu containers can securely execute commands on host AUTH_KEYS_FILE=~/.ssh/authorized_keys CONTAINER_KEYS_FILE=./.internal/.ssh/id_rsa +REBOOT_REQ="false" sys_arch=$(uname -m) while test $# -gt 0 do - case "$1" in - --no-ask) NOASKCONFIRM="true" - ;; - --*) echo "bad option $1" - ;; - esac - shift + case "$1" in + --no-ask) NOASKCONFIRM="true" + ;; + --*) echo "bad option $1" + ;; + esac + shift done echo "IOTstack Installation" +echo "Running as '$(whoami)' in '$(pwd)'" if [ "$EUID" -eq "0" ]; then echo "Please do not run as root" exit fi +if [ -f "./menu.sh" ]; then + echo "'./menu.sh' file detected, will not reclone. Is IOTstack already installed in this directory?" +fi + +echo "Please enter sudo password if prompted to do so." +echo "" + function command_exists() { command -v "$@" > /dev/null 2>&1 } @@ -101,12 +110,14 @@ function user_in_group() { } function install_docker() { + DOCKERREBOOT="false" if command_exists docker; then echo "Docker already installed" >&2 else echo "Install Docker" >&2 curl -fsSL https://get.docker.com | sh sudo -E usermod -aG docker $USER + DOCKERREBOOT="true" fi if command_exists docker-compose; then @@ -114,43 +125,67 @@ function install_docker() { else echo "Install docker-compose" >&2 sudo -E apt install -y docker-compose + DOCKERREBOOT="true" fi - echo "" >&2 - echo "You should now restart your system" >&2 + if [[ "$DOCKERREBOOT" == "true" ]]; then + REBOOT_REQ="true" + echo "" >&2 + echo "You should restart your system after IOTstack is installed" >&2 + fi } function do_group_setup() { - echo "Setting up groups:" + echo "Setting up groups..." + GROUPCHANGE="false" if [[ ! "$(user_in_group bluetooth)" == "notgroup" ]] && [[ ! "$(user_in_group bluetooth)" == "true" ]]; then echo "User is NOT in 'bluetooth' group. Adding:" >&2 echo "sudo usermod -G bluetooth -a $USER" >&2 sudo -E usermod -G "bluetooth" -a $USER + GROUPCHANGE="true" + else + echo "User already in bluetooth group" >&2 fi if [ ! "$(user_in_group docker)" == "true" ]; then echo "User is NOT in 'docker' group. Adding:" >&2 echo "sudo usermod -G docker -a $USER" >&2 sudo -E usermod -G "docker" -a $USER + GROUPCHANGE="true" + else + echo "User already in docker group" >&2 fi - echo "" >&2 - echo "Rebooting or logging off is advised." >&2 + if [[ "$GROUPCHANGE" == "true" ]]; then + REBOOT_REQ="true" + echo "" >&2 + echo "Rebooting or logging off is advised." >&2 + fi } function do_env_setup() { sudo -E apt-get install git wget unzip -y + if [ ! $? -eq 0 ]; then + echo "" >&2 + echo "Dependency install failed. Aborting installation" >&2 + exit 1 + fi } function do_iotstack_setup() { - git clone https://github.com/SensorsIot/IOTstack.git - cd IOTstack - - if [ $? -eq 0 ]; then - echo "IOTstack cloned" + if [ -f "./menu.sh" ]; then + echo "'./menu.sh' file detected, will not reclone." >&2 else - echo "Could not find IOTstack directory" - exit 5 + echo "IOTstack will be cloned into $(pwd)/IOTstack" >&2 + git clone https://github.com/SensorsIot/IOTstack.git + cd IOTstack + + if [ $? -eq 0 ]; then + echo "IOTstack cloned" >&2 + else + echo "Could not find IOTstack directory" >&2 + exit 5 + fi fi } @@ -159,20 +194,42 @@ function generate_container_ssh() { } function install_ssh_keys() { + touch $AUTH_KEYS_FILE if [ -f "$CONTAINER_KEYS_FILE" ]; then NEW_KEY="$(cat $CONTAINER_KEYS_FILE.pub)" if grep -Fxq "$NEW_KEY" $AUTH_KEYS_FILE ; then - echo "Key already exists in '$AUTH_KEYS_FILE' Skipping..." + echo "Key already exists in '$AUTH_KEYS_FILE' Skipping..." >&2 else - echo "$NEW_KEY" >> $AUTH_KEYS_FILE - echo "Key added." + echo "$NEW_KEY" >> $AUTH_KEYS_FILE >&2 + echo "Key added." >&2 fi fi } +# Entry point do_env_setup do_iotstack_setup generate_container_ssh install_ssh_keys install_docker do_group_setup + +echo "IOTstack setup completed" +if [[ "$REBOOT_REQ" == "true" ]]; then + if [[ "$NOASKCONFIRM" == "true" ]]; then + echo "Rebooting..." + sudo reboot + else + echo "" + echo "You need to reboot your system to ensure IOTstack runs correctly." + if (whiptail --title "Reboot Required" --yesno "A restart is required to ensure IOTstack runs correctly.\n\nAfter reboot start IOTstack by running:\n ./menu.sh\n\nFrom the IOTstack directory:\n $(pwd)\n\nReboot now?" 20 78); then + echo "Rebooting..." + sleep 1 + sudo reboot + fi + fi +fi + +echo "" +echo "Start IOTstack by running:" +echo " ./menu.sh" diff --git a/menu.sh b/menu.sh index cef77588d..7123953a3 100755 --- a/menu.sh +++ b/menu.sh @@ -4,13 +4,6 @@ CURRENT_BRANCH=$(git name-rev --name-only HEAD) # Minimum Software Versions REQ_DOCKER_VERSION=18.2.0 -REQ_PYTHON_VERSION=3.6.9 -REQ_PIP_VERSION=3.6.9 -REQ_PYAML_VERSION=0.16.12 -REQ_BLESSED_VERSION=1.17.5 - -PYTHON_CMD=python3 -VGET_CMD="$PYTHON_CMD ./scripts/python_deps_check.py" sys_arch=$(uname -m) @@ -18,6 +11,7 @@ sys_arch=$(uname -m) # Helper functions # ---------------------------------------------- source ./scripts/setup_iotstack.sh +source ./.internal/meta.sh function check_git_updates() { UPSTREAM=${1:-'@{u}'} @@ -71,26 +65,21 @@ else project_checks if [[ "$(docker_checks)" == "fail" ]]; then - echo "Docker is not setup." - if (whiptail --title "Install Docker" --yesno "Docker or docker-compose doesn't seem to be installed. After installation the system will need to be rebooted.\r\n\r\nInstall Docker and docker-compose now?" 14 78); then - docker_installed_check - fi + echo "Docker is not setup. Cannot continue" + exit 2 + fi + + if [[ "$(docker_checks)" == "outdated" ]]; then + echo "" + echo "Docker is outdated. You should consider updating. To be reprompted, type:" + echo " rm .ignore_docker_outofdate" + echo "" fi if [[ "$(group_check)" == "fail" ]]; then echo "User not in correct groups. Run:" echo "bash ./menu.sh --run-env-setup" fi - - if [[ "$DOCKER_VERSION_GOOD" == "true" ]]; then - echo "Project dependencies up to date" - echo "" - else - echo "Project dependencies not up to date. Menu may crash." - echo "To be prompted to update again, run command:" - echo " rm .docker_notinstalled || rm .docker_outofdate || rm .project_outofdate" - echo "" - fi fi while test $# -gt 0 @@ -126,6 +115,53 @@ do shift done +PREBUILT_IMAGES="true" +if [[ "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then + PREBUILT_IMAGES="false" +fi + +if [[ "$(docker images -q iostack_pycli:$VERSION 2> /dev/null)" == "" ]]; then + PREBUILT_IMAGES="false" +fi + +if [[ "$(docker images -q iostack_wui:$VERSION 2> /dev/null)" == "" ]]; then + PREBUILT_IMAGES="false" +fi + +if [[ "$PREBUILT_IMAGES" == "" ]]; then + echo "You either recently installed or upgraded IOTstack. The menu docker images need to be rebuilt in order for the menu to run correctly. This will take a few minutes." + + # Build all asynchronously, so it's faster. Give PyCLI a slight headstart to keep the user waiting the shortest time. + docker build --quiet -t iostack_pycli:$VERSION -f ./.internal/pycli.Dockerfile . & + sleep 1 + docker build --quiet -t iostack_api:$VERSION -f ./.internal/api.Dockerfile . & + sleep 2 + docker build --quiet -t iostack_wui:$VERSION -f ./.internal/wui.Dockerfile . & + + SLEEP_COUNTER=0 + API_REBUILD_DONE="false" + PYCLI_REBUILD_DONE="false" + + until [[ $SLEEP_COUNTER -gt 60 || ("$API_REBUILD_DONE" == "true" && "$PYCLI_REBUILD_DONE" == "true") ]]; do + if [[ ! "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then + API_REBUILD_DONE="true" + fi + + if [[ ! "$(docker images -q iostack_pycli:$VERSION 2> /dev/null)" == "" ]]; then + PYCLI_REBUILD_DONE="false" + fi + + printf(".") + sleep 1 + + ((SLEEP_COUNTER++)) + done +fi + +if [[ $SLEEP_COUNTER -gt 60 ]]; then + echo "Something seems to have gone wrong when rebuilding the menu docker images." +fi + # Hand control to new menu echo "Started!" # $PYTHON_CMD ./scripts/menu_main.py $ENCODING_TYPE diff --git a/scripts/setup_iotstack.sh b/scripts/setup_iotstack.sh index 28edc7140..ce4bd0563 100644 --- a/scripts/setup_iotstack.sh +++ b/scripts/setup_iotstack.sh @@ -102,15 +102,30 @@ function install_docker() { echo "You should now restart your system" >&2 } -function docker_installed_check() { - DOCKER_GOOD="pass" - if ! command_exists docker; then - DOCKER_GOOD="fail" +function docker_check() { + DOCKER_GOOD="fail" + + if command_exists docker; then echo "Docker is installed" >&2 + if [ "$(minimum_version_check $REQ_DOCKER_VERSION $DOCKER_VERSION_MAJOR $DOCKER_VERSION_MINOR $DOCKER_VERSION_BUILD )" == "true" ]; then + [ -f .ignore_docker_outofdate ] && rm .ignore_docker_outofdate + DOCKER_GOOD="true" + echo "Docker version $DOCKER_VERSION >= $REQ_DOCKER_VERSION. Docker is good to go." >&2 + else + DOCKER_GOOD="outdated" + if [ ! -f .ignore_docker_outofdate ]; then + if (whiptail --title "Docker and Docker-Compose Version Issue" --yesno "Docker version is currently $DOCKER_VERSION which is less than $REQ_DOCKER_VERSION consider upgrading or you may experience issues. You will not be prompted again. You can manually upgrade by typing:\n sudo apt upgrade docker docker-compose\n\nAttempt to upgrade now?" 20 78); then + update_docker + else + touch .ignore_docker_outofdate + fi + fi + fi + fi fi if ! command_exists docker-compose; then - DOCKER_GOOD="fail" + COMPOSE_GOOD="pass" echo "docker-compose is installed" >&2 fi @@ -160,13 +175,14 @@ function generate_container_ssh() { } function install_ssh_keys() { + touch $AUTH_KEYS_FILE if [ -f "$CONTAINER_KEYS_FILE" ]; then NEW_KEY="$(cat $CONTAINER_KEYS_FILE.pub)" if grep -Fxq "$NEW_KEY" $AUTH_KEYS_FILE ; then - echo "Key already exists in '$AUTH_KEYS_FILE' Skipping..." + echo "Key already exists in '$AUTH_KEYS_FILE' Skipping..." >&2 else - echo "$NEW_KEY" >> $AUTH_KEYS_FILE - echo "Key added." + echo "$NEW_KEY" >> $AUTH_KEYS_FILE >&2 + echo "Key added." >&2 fi fi } diff --git a/test.sh b/test.sh new file mode 100644 index 000000000..03083928e --- /dev/null +++ b/test.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +bash ./.internal/docker_menu.sh From 00c5d16e9716dde9a3ba6d0b0c7179ac24959570 Mon Sep 17 00:00:00 2001 From: Slyke Date: Sun, 17 Jan 2021 08:49:43 -0800 Subject: [PATCH 005/142] Got semi working menu bootstrap --- .internal/ctrl_api.sh | 54 ++++++++--------- .internal/ctrl_pycli.sh | 22 +++---- .internal/ctrl_wui.sh | 22 +++---- menu.sh | 122 ++++++++++++++++++++++---------------- scripts/setup_iotstack.sh | 9 +++ test.sh | 3 - 6 files changed, 130 insertions(+), 102 deletions(-) delete mode 100644 test.sh diff --git a/.internal/ctrl_api.sh b/.internal/ctrl_api.sh index 703936706..372c7aaaf 100644 --- a/.internal/ctrl_api.sh +++ b/.internal/ctrl_api.sh @@ -4,30 +4,41 @@ source ./.internal/meta.sh DNAME=iostack_api FULL_NAME="$DNAME:$VERSION" -if [[ $IOTENV == "development" ]]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force - docker build --no-cache -t $FULL_NAME -f ./.internal/api.Dockerfile . +if [ "$1" = "stop" ]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) 2> /dev/null else - if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then - echo "Building '$FULL_NAME'" - docker build --quiet -t $FULL_NAME -f ./.internal/api.Dockerfile . + if [[ $IOTENV == "development" ]]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker build --no-cache -t $FULL_NAME -f ./.internal/api.Dockerfile . else - echo "Build for '$FULL_NAME' already exists. Skipping..." + if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then + echo "Building '$FULL_NAME'" + docker build --quiet -t $FULL_NAME -f ./.internal/api.Dockerfile . + else + echo "Build for '$FULL_NAME' already exists. Skipping..." + fi fi -fi -if [ "$1" = "stop" ]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) -else if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then echo "Starting IOTstack API Server" - # docker run -d -p 32128:32128 \ + docker run -d -p 32128:32128 \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + -e HOSTUSER="$HOSTUSER" \ + -e IOTSTACKPWD="$IOTSTACKPWD" \ + -e CORS="comma.separated,list.of.ip,addresses" \ + --restart unless-stopped \ + $FULL_NAME + + # docker run -p 32128:32128 \ # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ - # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + # -e cors="yourLanIpHere:32777" \ # -e HOSTUSER="$HOSTUSER" \ # -e IOTSTACKPWD="$IOTSTACKPWD" \ - # -e CORS="list,of,ip,addresses" \ + # -e CORS="comma.separated,list.of.ip,addresses" \ # --restart unless-stopped \ # $FULL_NAME @@ -35,22 +46,11 @@ else # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ - # -e cors="yourLanIpHere:32777" \ # -e HOSTUSER="$HOSTUSER" \ # -e IOTSTACKPWD="$IOTSTACKPWD" \ - # -e CORS="list,of,ip,addresses" \ + # -e CORS="comma.separated,list.of.ip,addresses" \ # --restart unless-stopped \ - # $FULL_NAME - - docker run -p 32128:32128 \ - --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ - --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ - --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ - -e HOSTUSER="$HOSTUSER" \ - -e IOTSTACKPWD="$IOTSTACKPWD" \ - # -e CORS="list,of,ip,addresses" \ - --restart unless-stopped \ - -it $FULL_NAME /bin/bash + # -it $FULL_NAME /bin/bash else echo "IOTstack API Server is running" fi diff --git a/.internal/ctrl_pycli.sh b/.internal/ctrl_pycli.sh index c595c3a79..d7272935a 100644 --- a/.internal/ctrl_pycli.sh +++ b/.internal/ctrl_pycli.sh @@ -4,21 +4,21 @@ source ./.internal/meta.sh DNAME=iostack_pycli FULL_NAME="$DNAME:$VERSION" -if [[ $IOTENV == "development" ]]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force - docker build --no-cache -t $FULL_NAME -f ./.internal/pycli.Dockerfile . +if [ "$1" = "stop" ]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) 2> /dev/null else - if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then - echo "Building '$FULL_NAME'" - docker build --quiet -t $FULL_NAME -f ./.internal/pycli.Dockerfile . + if [[ $IOTENV == "development" ]]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker build --no-cache -t $FULL_NAME -f ./.internal/pycli.Dockerfile . else - echo "Build for '$FULL_NAME' already exists. Skipping..." + if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then + echo "Building '$FULL_NAME'" + docker build --quiet -t $FULL_NAME -f ./.internal/pycli.Dockerfile . + else + echo "Build for '$FULL_NAME' already exists. Skipping..." + fi fi -fi -if [ "$1" = "stop" ]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) -else if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then echo "Starting IOTstack PyCLI instance" diff --git a/.internal/ctrl_wui.sh b/.internal/ctrl_wui.sh index 7952d3ce7..22afaea88 100644 --- a/.internal/ctrl_wui.sh +++ b/.internal/ctrl_wui.sh @@ -4,21 +4,21 @@ source ./.internal/meta.sh DNAME=iostack_wui FULL_NAME="$DNAME:$VERSION" -if [[ $IOTENV == "development" ]]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force - docker build --no-cache -t $FULL_NAME -f ./.internal/wui.Dockerfile . +if [ "$1" = "stop" ]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) 2> /dev/null else - if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then - echo "Building '$FULL_NAME'" - docker build --quiet -t $FULL_NAME -f ./.internal/wui.Dockerfile . + if [[ $IOTENV == "development" ]]; then + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker build --no-cache -t $FULL_NAME -f ./.internal/wui.Dockerfile . else - echo "Build for '$FULL_NAME' already exists. Skipping..." + if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then + echo "Building '$FULL_NAME'" + docker build --quiet -t $FULL_NAME -f ./.internal/wui.Dockerfile . + else + echo "Build for '$FULL_NAME' already exists. Skipping..." + fi fi -fi -if [ "$1" = "stop" ]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) -else if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then echo "Starting IOTstack WUI Server" docker run -d -p 32777:32777 -e PORT=32777 --restart unless-stopped $FULL_NAME diff --git a/menu.sh b/menu.sh index 7123953a3..410d965ab 100755 --- a/menu.sh +++ b/menu.sh @@ -64,6 +64,12 @@ else project_checks + if [[ "$(check_container_ssh)" == "false" ]]; then + echo "SSH keys for containers do not exist. the menu containers will not be able to execute commands on your host." + echo "To regenerate these keys, run:" + echo " bash ./menu.sh --run-env-setup" + fi + if [[ "$(docker_checks)" == "fail" ]]; then echo "Docker is not setup. Cannot continue" exit 2 @@ -78,7 +84,64 @@ else if [[ "$(group_check)" == "fail" ]]; then echo "User not in correct groups. Run:" - echo "bash ./menu.sh --run-env-setup" + echo " bash ./menu.sh --run-env-setup" + fi + + # ---------------------------------------------- + # Check state of running menu instances + # ---------------------------------------------- + PREBUILT_IMAGES="true" + if [[ "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then + PREBUILT_IMAGES="false" + fi + + if [[ "$(docker images -q iostack_pycli:$VERSION 2> /dev/null)" == "" ]]; then + PREBUILT_IMAGES="false" + fi + + if [[ "$(docker images -q iostack_wui:$VERSION 2> /dev/null)" == "" ]]; then + PREBUILT_IMAGES="false" + fi + + if [[ "$PREBUILT_IMAGES" == "false" ]]; then + echo "You either recently installed or upgraded IOTstack. The menu docker images need to be rebuilt in order for the menu to run correctly. This will take about a minute." + bash ./.internal/docker_menu.sh stop > /dev/null & + + sleep 1 + + # Build all asynchronously, so it's faster. Give PyCLI a slight headstart to keep the user waiting the shortest time. + docker build --quiet -t iostack_pycli:$VERSION -f ./.internal/pycli.Dockerfile . > /dev/null & + sleep 1 + docker build --quiet -t iostack_api:$VERSION -f ./.internal/api.Dockerfile . > /dev/null & + sleep 2 + docker build --quiet -t iostack_wui:$VERSION -f ./.internal/wui.Dockerfile . > /dev/null & + + SLEEP_COUNTER=0 + API_REBUILD_DONE="not completed" + PYCLI_REBUILD_DONE="not completed" + + until [[ $SLEEP_COUNTER -gt 300 || ("$API_REBUILD_DONE" == "completed" && "$PYCLI_REBUILD_DONE" == "completed") ]]; do + if [[ ! "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then + API_REBUILD_DONE="completed" + fi + + if [[ ! "$(docker images -q iostack_pycli:$VERSION 2> /dev/null)" == "" ]]; then + PYCLI_REBUILD_DONE="completed" + fi + + printf(".") + sleep 1 + + ((SLEEP_COUNTER++)) + done + fi + + if [[ $SLEEP_COUNTER -gt 300 ]]; then + echo "" + echo "Something seems to have gone wrong when rebuilding the menu docker images." + echo "API Rebuild: $API_REBUILD_DONE" + echo "PyCLI Rebuild: $PYCLI_REBUILD_DONE" + echo "" fi fi @@ -115,53 +178,12 @@ do shift done -PREBUILT_IMAGES="true" -if [[ "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then - PREBUILT_IMAGES="false" -fi - -if [[ "$(docker images -q iostack_pycli:$VERSION 2> /dev/null)" == "" ]]; then - PREBUILT_IMAGES="false" -fi - -if [[ "$(docker images -q iostack_wui:$VERSION 2> /dev/null)" == "" ]]; then - PREBUILT_IMAGES="false" -fi - -if [[ "$PREBUILT_IMAGES" == "" ]]; then - echo "You either recently installed or upgraded IOTstack. The menu docker images need to be rebuilt in order for the menu to run correctly. This will take a few minutes." - - # Build all asynchronously, so it's faster. Give PyCLI a slight headstart to keep the user waiting the shortest time. - docker build --quiet -t iostack_pycli:$VERSION -f ./.internal/pycli.Dockerfile . & - sleep 1 - docker build --quiet -t iostack_api:$VERSION -f ./.internal/api.Dockerfile . & - sleep 2 - docker build --quiet -t iostack_wui:$VERSION -f ./.internal/wui.Dockerfile . & - - SLEEP_COUNTER=0 - API_REBUILD_DONE="false" - PYCLI_REBUILD_DONE="false" - - until [[ $SLEEP_COUNTER -gt 60 || ("$API_REBUILD_DONE" == "true" && "$PYCLI_REBUILD_DONE" == "true") ]]; do - if [[ ! "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then - API_REBUILD_DONE="true" - fi - - if [[ ! "$(docker images -q iostack_pycli:$VERSION 2> /dev/null)" == "" ]]; then - PYCLI_REBUILD_DONE="false" - fi - - printf(".") - sleep 1 - - ((SLEEP_COUNTER++)) - done -fi - -if [[ $SLEEP_COUNTER -gt 60 ]]; then - echo "Something seems to have gone wrong when rebuilding the menu docker images." +# If PyCLI is already running reattach +PYCLI_ID="$(docker ps --format '{{.ID}} {{.Image}}' | grep -w iostack_pycli:$VERSION | cut -d ' ' -f1 | head -n 1)" +if [[ "$PYCLI_ID" == "" ]]; then + bash ./.internal/docker_menu.sh +else + bash ./.internal/ctrl_api.sh > /dev/null + echo "PyCLI menu is already running. Reattaching..." + docker attach --sig-proxy=false $PYCLI_ID fi - -# Hand control to new menu -echo "Started!" -# $PYTHON_CMD ./scripts/menu_main.py $ENCODING_TYPE diff --git a/scripts/setup_iotstack.sh b/scripts/setup_iotstack.sh index ce4bd0563..b77f3f7ea 100644 --- a/scripts/setup_iotstack.sh +++ b/scripts/setup_iotstack.sh @@ -187,6 +187,15 @@ function install_ssh_keys() { fi } +function check_container_ssh() { + KEYS_EXIST="false" + if [[ -f "$CONTAINER_KEYS_FILE" && -f "$CONTAINER_KEYS_FILE.pub" ]]; then + KEYS_EXIST="true" + fi + + echo $KEYS_EXIST +} + function do_iotstack_setup() { git clone https://github.com/SensorsIot/IOTstack.git cd IOTstack diff --git a/test.sh b/test.sh deleted file mode 100644 index 03083928e..000000000 --- a/test.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -bash ./.internal/docker_menu.sh From 249ab968383d8dc1cd5d5e4359bcfaaf7e957c65 Mon Sep 17 00:00:00 2001 From: Slyke Date: Tue, 19 Jan 2021 15:08:21 -0800 Subject: [PATCH 006/142] Fixed some of the pycli menu items, added in env var overwriting. added development mode to menu container bootstrap --- .internal/api/src/index.js | 4 +- .internal/ctrl_api.sh | 88 ++++++++++++++++++++---------- .internal/ctrl_pycli.sh | 10 ++++ .internal/ctrl_wui.sh | 14 ++++- .internal/meta.sh | 8 +-- .internal/pycli/deps/__init__.py | 0 .internal/pycli/deps/chars.py | 72 ++++++++++++++++++++++++ .internal/pycli/deps/host_exec.py | 23 ++++++++ .internal/pycli/entry.py | 61 +++++++++++++-------- .internal/pycli/menu_main.py | 32 +++-------- .internal/pycli/misc_commands.py | 15 +++-- .internal/pycli/native_installs.py | 24 ++++---- menu.sh | 33 ++++++++--- scripts/setup_iotstack.sh | 49 ++++++++++++----- 14 files changed, 311 insertions(+), 122 deletions(-) create mode 100644 .internal/pycli/deps/__init__.py create mode 100644 .internal/pycli/deps/chars.py create mode 100644 .internal/pycli/deps/host_exec.py diff --git a/.internal/api/src/index.js b/.internal/api/src/index.js index d19bda475..61869debf 100644 --- a/.internal/api/src/index.js +++ b/.internal/api/src/index.js @@ -72,11 +72,11 @@ const processEnvVars = (envs) => { try { additionalCorsList = [ ...additionalCorsList, - ...cors?.split(',') ?? [] + ...cors?.split(/[\s,]+/) ?? [] ]; additionalCorsList = [ ...additionalCorsList, - ...CORS?.split(',') ?? [] + ...CORS?.split(/[\s,]+/) ?? [] ]; } catch (err) { console.error('processEnvVars: Error on cors:'); diff --git a/.internal/ctrl_api.sh b/.internal/ctrl_api.sh index 372c7aaaf..310aa3d63 100644 --- a/.internal/ctrl_api.sh +++ b/.internal/ctrl_api.sh @@ -9,48 +9,78 @@ if [ "$1" = "stop" ]; then else if [[ $IOTENV == "development" ]]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker node:14 # Docker occasionally fails to pull image when building when it is not cached. docker build --no-cache -t $FULL_NAME -f ./.internal/api.Dockerfile . else if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then echo "Building '$FULL_NAME'" + docker node:14 # Docker occasionally fails to pull image when building when it is not cached. docker build --quiet -t $FULL_NAME -f ./.internal/api.Dockerfile . else echo "Build for '$FULL_NAME' already exists. Skipping..." fi fi + CORS_LIST="" + for sepspace in "$(hostname --all-ip-addresses)"; do + sepspace="$(echo $sepspace | xargs)" + CORS_LIST="$CORS_LIST $sepspace:32777 " + done + if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then - echo "Starting IOTstack API Server" - docker run -d -p 32128:32128 \ - --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ - --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds \ - --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ - -e HOSTUSER="$HOSTUSER" \ - -e IOTSTACKPWD="$IOTSTACKPWD" \ - -e CORS="comma.separated,list.of.ip,addresses" \ - --restart unless-stopped \ - $FULL_NAME + if [[ $IOTENV == "development" ]]; then + echo "Starting in development watch mode the IOTstack API Server" + docker run -p 32128:32128 \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/api,target=/usr/iotstack_api \ + -e HOSTUSER="$HOSTUSER" \ + -e IOTSTACKPWD="$IOTSTACKPWD" \ + -e CORS="$CORS_LIST" \ + -e HOSTSSH_ADDR="$HOSTSSH_ADDR" \ + -e HOSTSSH_PORT="$HOSTSSH_PORT" \ + --restart unless-stopped \ + $FULL_NAME + else + echo "Starting IOTstack API Server" + docker run -d -p 32128:32128 \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + -e HOSTUSER="$HOSTUSER" \ + -e IOTSTACKPWD="$IOTSTACKPWD" \ + -e CORS="$CORS_LIST" \ + -e HOSTSSH_ADDR="$HOSTSSH_ADDR" \ + -e HOSTSSH_PORT="$HOSTSSH_PORT" \ + --restart unless-stopped \ + $FULL_NAME - # docker run -p 32128:32128 \ - # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ - # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ - # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ - # -e cors="yourLanIpHere:32777" \ - # -e HOSTUSER="$HOSTUSER" \ - # -e IOTSTACKPWD="$IOTSTACKPWD" \ - # -e CORS="comma.separated,list.of.ip,addresses" \ - # --restart unless-stopped \ - # $FULL_NAME + # docker run -p 32128:32128 \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + # -e cors="yourLanIpHere:32777" \ + # -e HOSTUSER="$HOSTUSER" \ + # -e IOTSTACKPWD="$IOTSTACKPWD" \ + # -e CORS="$(CORS_LIST)" \ + # -e HOSTSSH_ADDR="$HOSTSSH_ADDR" \ + # -e HOSTSSH_PORT="$HOSTSSH_PORT" \ + # --restart unless-stopped \ + # $FULL_NAME - # docker run -p 32128:32128 \ - # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ - # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ - # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ - # -e HOSTUSER="$HOSTUSER" \ - # -e IOTSTACKPWD="$IOTSTACKPWD" \ - # -e CORS="comma.separated,list.of.ip,addresses" \ - # --restart unless-stopped \ - # -it $FULL_NAME /bin/bash + # docker run -p 32128:32128 \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/templates,target=/usr/iotstack_api/templates,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/saved_builds,target=/usr/iotstack_api/builds,readonly \ + # --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ + # -e HOSTUSER="$HOSTUSER" \ + # -e IOTSTACKPWD="$IOTSTACKPWD" \ + # -e CORS="$(CORS_LIST)" \ + # -e HOSTSSH_ADDR="$HOSTSSH_ADDR" \ + # -e HOSTSSH_PORT="$HOSTSSH_PORT" \ + # --restart unless-stopped \ + # -it $FULL_NAME /bin/bash + fi else echo "IOTstack API Server is running" fi diff --git a/.internal/ctrl_pycli.sh b/.internal/ctrl_pycli.sh index d7272935a..65d620b19 100644 --- a/.internal/ctrl_pycli.sh +++ b/.internal/ctrl_pycli.sh @@ -8,11 +8,19 @@ if [ "$1" = "stop" ]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) 2> /dev/null else if [[ $IOTENV == "development" ]]; then + echo "[Development] Stopping container:" + echo "docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force" docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + echo "" + echo "Rebuilding container:" + echo "docker build --no-cache -t $FULL_NAME -f ./.internal/pycli.Dockerfile ." + docker pull python:3 # Docker occasionally fails to pull image when building when it is not cached. docker build --no-cache -t $FULL_NAME -f ./.internal/pycli.Dockerfile . + echo "" else if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then echo "Building '$FULL_NAME'" + docker pull python:3 # Docker occasionally fails to pull image when building when it is not cached. docker build --quiet -t $FULL_NAME -f ./.internal/pycli.Dockerfile . else echo "Build for '$FULL_NAME' already exists. Skipping..." @@ -27,6 +35,8 @@ else --mount type=bind,source="$IOTSTACKPWD"/.internal/.ssh,target=/root/.ssh,readonly \ -e HOSTUSER="$HOSTUSER" \ -e IOTSTACKPWD="$IOTSTACKPWD" \ + -e HOSTSSH_ADDR="$HOSTSSH_ADDR" \ + -e HOSTSSH_PORT="$HOSTSSH_PORT" \ --restart no \ -it $FULL_NAME diff --git a/.internal/ctrl_wui.sh b/.internal/ctrl_wui.sh index 22afaea88..31b76f34e 100644 --- a/.internal/ctrl_wui.sh +++ b/.internal/ctrl_wui.sh @@ -9,10 +9,12 @@ if [ "$1" = "stop" ]; then else if [[ $IOTENV == "development" ]]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker node:alpine # Docker occasionally fails to pull image when building when it is not cached. docker build --no-cache -t $FULL_NAME -f ./.internal/wui.Dockerfile . else if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then echo "Building '$FULL_NAME'" + docker node:alpine # Docker occasionally fails to pull image when building when it is not cached. docker build --quiet -t $FULL_NAME -f ./.internal/wui.Dockerfile . else echo "Build for '$FULL_NAME' already exists. Skipping..." @@ -20,8 +22,16 @@ else fi if ! docker ps --format '{{.Image}}' | grep -w $FULL_NAME &> /dev/null; then - echo "Starting IOTstack WUI Server" - docker run -d -p 32777:32777 -e PORT=32777 --restart unless-stopped $FULL_NAME + if [[ $IOTENV == "development" ]]; then + echo "Starting in development watch mode the IOTstack WUI Server" + docker run -p 32777:32777 \ + -e PORT=32777 \ + --mount type=bind,source="$IOTSTACKPWD"/.internal/wui,target=/usr/iotstack_wui \ + --restart unless-stopped $FULL_NAME + else + echo "Starting IOTstack WUI Server" + docker run -d -p 32777:32777 -e PORT=32777 --restart unless-stopped $FULL_NAME + fi else echo "IOTstack WUI Server is running" fi diff --git a/.internal/meta.sh b/.internal/meta.sh index 6ecdccf2e..9fbc38ac5 100644 --- a/.internal/meta.sh +++ b/.internal/meta.sh @@ -1,5 +1,5 @@ VERSION="v0.0.1" -IOTSTACKPWD="$(pwd)" -HOSTUSER="$(whoami)" -HOSTSSH_IP="host.docker.internal" -HOSTSSH_PORT="22" +IOTSTACKPWD="${IOTSTACK_IOTSTACKPWD:-$(pwd)}" +HOSTUSER="${IOTSTACK_HOSTUSER:-$(whoami)}" +HOSTSSH_ADDR="${IOTSTACK_HOSTSSH_ADDR:-host.docker.internal}" +HOSTSSH_PORT="${IOTSTACK_HOSTSSH_PORT:-22}" diff --git a/.internal/pycli/deps/__init__.py b/.internal/pycli/deps/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/.internal/pycli/deps/chars.py b/.internal/pycli/deps/chars.py new file mode 100644 index 000000000..51cfa0d77 --- /dev/null +++ b/.internal/pycli/deps/chars.py @@ -0,0 +1,72 @@ +specialChars = { + "latin": { + "rightArrowFull": "►", + "upArrowFull": "▲", + "upArrowLine": "↑", + "downArrowFull": "▼", + "downArrowLine": "↓", + "borderVertical": "║", + "borderHorizontal": "═", + "borderTopLeft": "╔", + "borderTopRight": "╗", + "borderBottomLeft": "╚", + "borderBottomRight": "╝" + }, + "simple": { + "rightArrowFull": "→", + "upArrowFull": "↑", + "upArrowLine": "↑", + "downArrowFull": "↓", + "downArrowLine": "↓", + "borderVertical": "│", + "borderHorizontal": "─", + "borderTopLeft": "┌", + "borderTopRight": "┐", + "borderBottomLeft": "└", + "borderBottomRight": "┘" + }, + "ascii": { + "rightArrowFull": ">", + "upArrowFull": "^", + "upArrowLine": "^", + "downArrowFull": "v", + "downArrowLine": "v", + "borderVertical": "|", + "borderHorizontal": "-", + "borderTopLeft": "/", + "borderTopRight": "\\", + "borderBottomLeft": "\\", + "borderBottomRight": "/" + } +} + +def commonTopBorder(renderMode, size=80): + output = "" + output += "{btl}".format(btl=specialChars[renderMode]["borderTopLeft"]) + for i in range(size): + output += "{bh}".format(bh=specialChars[renderMode]["borderHorizontal"]) + output += "{btr}".format(btr=specialChars[renderMode]["borderTopRight"]) + return output + +def commonBottomBorder(renderMode, size=80): + output = "" + output += "{bbl}".format(bbl=specialChars[renderMode]["borderBottomLeft"]) + for i in range(size): + output += "{bh}".format(bh=specialChars[renderMode]["borderHorizontal"]) + output += "{bbr}".format(bbr=specialChars[renderMode]["borderBottomRight"]) + return output + +def padText(text, size=45): + output = "" + output += text + for i in range(size - len(text)): + output += " " + return output + +def commonEmptyLine(renderMode, size=80): + output = "" + output += "{bv}".format(bv=specialChars[renderMode]["borderVertical"]) + for i in range(size): + output += " " + output += "{bv}".format(bv=specialChars[renderMode]["borderVertical"]) + return output diff --git a/.internal/pycli/deps/host_exec.py b/.internal/pycli/deps/host_exec.py new file mode 100644 index 000000000..d8a8e81c6 --- /dev/null +++ b/.internal/pycli/deps/host_exec.py @@ -0,0 +1,23 @@ +import os +import subprocess + +hostUser = os.getenv('HOSTUSER') +iotstackPwd = os.getenv('IOTSTACKPWD') +hostAddress = os.getenv('HOSTSSH_ADDR') +hostPort = os.getenv('HOSTSSH_PORT') + +def getCommandString(command, iotstackPwd=iotstackPwd, hostUser=hostUser, hostAddress=hostAddress): + return "ssh -t -o StrictHostKeychecking=no {hostUser}@{hostAddress} -p {hostPort} 'cd {iotstackPwd} && {command}' 2> /dev/null".format( + hostUser=hostUser, + iotstackPwd=iotstackPwd, + hostAddress=hostAddress, + hostPort=hostPort, + command=command + ) + +def execSilent(command): + execRes = subprocess.check_output(getCommandString(command), stderr=subprocess.PIPE, shell=True) + return execRes.decode('ascii').strip() + +def execInteractive(command): + return subprocess.call(getCommandString(command), shell=True) diff --git a/.internal/pycli/entry.py b/.internal/pycli/entry.py index 2569bfc4d..2a62aed78 100644 --- a/.internal/pycli/entry.py +++ b/.internal/pycli/entry.py @@ -3,37 +3,54 @@ import blessed import yaml import ruamel.yaml +from deps.host_exec import execSilent import subprocess import os +import sys +import traceback hostUser = os.getenv('HOSTUSER') +iotstackPwd = os.getenv('IOTSTACKPWD') +hostAddress = os.getenv('HOSTSSH_ADDR') +hostPort = os.getenv('HOSTSSH_PORT') print('blessed Version:', blessed.__version__) print('ruamel.yaml Version:', ruamel.yaml.__version__) print('PyYAML Version:', yaml.__version__) print('') print('hostUser: ', hostUser) +print('iotstackPwd: ', iotstackPwd) +print('SSH hostAddress: ', hostAddress) +print('SSH hostPort: ', hostPort) print('') -testInput = print('Remote test: ') -res1 = subprocess.check_output(""" -ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'touch ~/tat.file' -""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) - -res2 = subprocess.check_output(""" -ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'echo "hi" >> ~/tat.file' -""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) - -res3 = subprocess.check_output(""" -ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'cat ~/tat.file' -""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) - -res4 = subprocess.check_output(""" -ssh -t -o StrictHostKeychecking=no {hostUser}@host.docker.internal 'rm ~/tat.file' -""".format(hostUser=hostUser), stderr=subprocess.PIPE, shell=True) - -testInput = print(res3.decode('ascii')) -print('') - -testInput = input('Enter input: ') -print('Input you entered', testInput) +try: + print('Checking connectivity to host...') + touchRes = execSilent('touch ./.tmp/rtest.file') + touchRes = execSilent('echo "exec success" >> ./.tmp/rtest.file') + readRes = execSilent('cat ./.tmp/rtest.file') + rmRes = execSilent('rm ./.tmp/rtest.file') + + if readRes != 'exec success': + print('Error attempting to execute commands on the host. You may need to regenerate SSH keys by running:') + print(' ./menu.sh --run-env-setup') + print('') + print('Or configure SSH to use correct ports.') + input("Press Enter to continue to menu...") + +except Exception: + print('Error attempting to execute commands on the host. You may need to regenerate SSH keys by running:') + print(' ./menu.sh --run-env-setup') + print('') + print('Or configure SSH to use correct ports.') + print('') + print('Error reported:') + print(sys.exc_info()) + traceback.print_exc() + print('') + input("Press Enter to continue to menu...") + +os.system('python menu_main.py') + +# testInput = input('Enter input: ') +# print('Input you entered', testInput) diff --git a/.internal/pycli/menu_main.py b/.internal/pycli/menu_main.py index 107a3d545..89af0efff 100644 --- a/.internal/pycli/menu_main.py +++ b/.internal/pycli/menu_main.py @@ -8,7 +8,6 @@ import types import signal from deps.chars import specialChars -from deps.version_check import checkVersion term = Terminal() @@ -99,7 +98,7 @@ def buildStack(): global screenActive buildComplete = None - buildstackFilePath = "./scripts/buildstack_menu.py" + buildstackFilePath = "./buildstack_menu.py" with open(buildstackFilePath, "rb") as pythonDynamicImportFile: code = compile(pythonDynamicImportFile.read(), buildstackFilePath, "exec") execGlobals = { @@ -132,7 +131,7 @@ def runExampleMenu(): def dockerCommands(): global needsRender - dockerCommandsFilePath = "./scripts/docker_commands.py" + dockerCommandsFilePath = "./docker_commands.py" with open(dockerCommandsFilePath, "rb") as pythonDynamicImportFile: code = compile(pythonDynamicImportFile.read(), dockerCommandsFilePath, "exec") # execGlobals = globals() @@ -149,7 +148,7 @@ def dockerCommands(): def miscCommands(): global needsRender - dockerCommandsFilePath = "./scripts/misc_commands.py" + dockerCommandsFilePath = "./misc_commands.py" with open(dockerCommandsFilePath, "rb") as pythonDynamicImportFile: code = compile(pythonDynamicImportFile.read(), dockerCommandsFilePath, "exec") # execGlobals = globals() @@ -167,7 +166,7 @@ def miscCommands(): def nativeInstalls(): global needsRender global screenActive - dockerCommandsFilePath = "./scripts/native_installs.py" + dockerCommandsFilePath = "./native_installs.py" with open(dockerCommandsFilePath, "rb") as pythonDynamicImportFile: code = compile(pythonDynamicImportFile.read(), dockerCommandsFilePath, "exec") # currGlobals = globals() @@ -185,7 +184,7 @@ def nativeInstalls(): def backupAndRestore(): global needsRender global screenActive - dockerCommandsFilePath = "./scripts/backup_restore.py" + dockerCommandsFilePath = "./backup_restore.py" with open(dockerCommandsFilePath, "rb") as pythonDynamicImportFile: code = compile(pythonDynamicImportFile.read(), dockerCommandsFilePath, "exec") # currGlobals = globals() @@ -291,17 +290,6 @@ def upgradeDocker(): } } -def checkDockerVersion(): - try: - getDockerVersion = subprocess.Popen(['docker', 'version', '-f', '"{{.Server.Version}}"'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - getDockerVersion.wait() - currentDockerVersion, stdError = getDockerVersion.communicate() - currentDockerVersion = currentDockerVersion.decode("utf-8").rstrip().replace('"', '') - except Exception as err: - print("Error attempting to run docker command:", err) - - return checkVersion(requiredDockerVersion, currentDockerVersion) - def checkProjectUpdates(): getCurrentBranch = subprocess.Popen(["git", "name-rev", "--name-only", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) getCurrentBranch.wait() @@ -334,7 +322,7 @@ def removeMenuItemByLabel(potentialItemKey): potentialMenu[potentialItemKey]["added"] = False mainMenuList.pop(i) -def doPotentialMenuCheck(projectStatus, dockerVersion=True, promptFiles=False): +def doPotentialMenuCheck(projectStatus, promptFiles=False): global needsRender if (promptFiles == True): @@ -361,11 +349,6 @@ def doPotentialMenuCheck(projectStatus, dockerVersion=True, promptFiles=False): # if (added): # needsRender = 1 - if (dockerVersion == False): - added = addPotentialMenuItem("dockerNotUpdated") - if (added): - needsRender = 1 - def checkIfPromptFilesExist(): if os.path.exists(".project_outofdate"): return True @@ -423,7 +406,6 @@ def isMenuItemSelectable(menu, index): # Entrypoint if __name__ == '__main__': projectStatus = checkProjectUpdates() # Async - dockerVersion, reason, data = checkDockerVersion() promptFiles = checkIfPromptFilesExist() term = Terminal() @@ -442,7 +424,7 @@ def isMenuItemSelectable(menu, index): mainRender(needsRender, mainMenuList, currentMenuItemIndex) needsRender = 0 - doPotentialMenuCheck(projectStatus=projectStatus, dockerVersion=dockerVersion, promptFiles=promptFiles) + doPotentialMenuCheck(projectStatus=projectStatus, promptFiles=promptFiles) key = term.inkey(timeout=projectStatusPollRateRefresh) if key.is_sequence: diff --git a/.internal/pycli/misc_commands.py b/.internal/pycli/misc_commands.py index 8c311c5d6..de7ec615c 100644 --- a/.internal/pycli/misc_commands.py +++ b/.internal/pycli/misc_commands.py @@ -5,11 +5,11 @@ def main(): from blessed import Terminal from deps.chars import specialChars, commonTopBorder, commonBottomBorder, commonEmptyLine - global renderMode import time - import subprocess + from deps.host_exec import execInteractive global signal + global renderMode global dockerCommandsSelectionInProgress global mainMenuList global currentMenuItemIndex @@ -25,7 +25,8 @@ def main(): def setSwapinessTo0(): print(term.clear()) print("Set swapiness to 0:") - subprocess.call("./scripts/disable_swap.sh disableswap", shell=True) + print("bash ./scripts/disable_swap.sh disableswap") + execInteractive('bash ./scripts/disable_swap.sh disableswap') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True @@ -35,7 +36,8 @@ def uninstallSwapfile(): print("Disabling swap...") setSwapinessTo0() print("Uninstall Swapfile:") - subprocess.call("./scripts/disable_swap.sh uninstallswap", shell=True) + print("bash ./scripts/disable_swap.sh uninstallswap") + execInteractive('bash ./scripts/disable_swap.sh uninstallswap') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True @@ -43,7 +45,8 @@ def uninstallSwapfile(): def installLog2Ram(): print(term.clear()) print("Install log2ram:") - subprocess.call("./scripts/install_log2ram.sh", shell=True) + print("bash ./scripts/install_log2ram.sh") + execInteractive('bash ./scripts/install_log2ram.sh') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True @@ -52,7 +55,7 @@ def installGithubSshKeys(): print(term.clear()) print("Install Github SSH Keys:") print("bash ./scripts/install_ssh_keys.sh") - subprocess.call("bash ./scripts/install_ssh_keys.sh", shell=True) + execInteractive('bash ./scripts/host_installers/install_ssh_keys.sh') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True diff --git a/.internal/pycli/native_installs.py b/.internal/pycli/native_installs.py index 7e9e4280d..f0542084a 100644 --- a/.internal/pycli/native_installs.py +++ b/.internal/pycli/native_installs.py @@ -4,10 +4,10 @@ def main(): from blessed import Terminal from deps.chars import specialChars, commonTopBorder, commonBottomBorder, commonEmptyLine - global renderMode + from deps.host_exec import execInteractive import time - import subprocess + global renderMode global signal global dockerCommandsSelectionInProgress global mainMenuList @@ -33,8 +33,8 @@ def onResize(sig, action): def installHassIo(): print(term.clear()) print("Install Home Assistant Supervisor") - print("./.native/hassio_supervisor.sh") - res = subprocess.call("./.native/hassio_supervisor.sh", shell=True) + print("bash ./scripts/host_installers/hassio_supervisor.sh") + res = execInteractive('bash ./scripts/host_installers/hassio_supervisor.sh') print("") if res == 0: print("Preinstallation complete. Your system may run slow for a few hours as Hass.io installs its services.") @@ -48,8 +48,8 @@ def installHassIo(): def installRtl433(): print(term.clear()) print("Install RTL_433") - print("bash ./.native/rtl_433.sh") - subprocess.call("bash ./.native/rtl_433.sh", shell=True) + print("bash ./scripts/host_installers/rtl_433.sh") + execInteractive('bash ./scripts/host_installers/rtl_433.sh') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True @@ -57,8 +57,8 @@ def installRtl433(): def installRpiEasy(): print(term.clear()) print("Install RPIEasy") - print("bash ./.native/rpieasy.sh") - subprocess.call("bash ./.native/rpieasy.sh", shell=True) + print("bash ./scripts/host_installers/rpieasy.sh") + execInteractive('bash ./scripts/host_installers/rpieasy.sh') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True @@ -67,8 +67,8 @@ def installDockerAndCompose(): print(term.clear()) print("Install docker") print("Install docker-compose") - print("bash ./scripts/install_docker.sh install") - subprocess.call("bash ./scripts/install_docker.sh install", shell=True) + print("bash ./scripts/host_installers/install_docker.sh install") + execInteractive('bash ./scripts/host_installers/install_docker.sh install') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True @@ -77,8 +77,8 @@ def upgradeDockerAndCompose(): print(term.clear()) print("Install docker") print("Install docker-compose") - print("bash ./scripts/install_docker.sh upgrade") - subprocess.call("bash ./scripts/install_docker.sh upgrade", shell=True) + print("bash ./scripts/host_installers/install_docker.sh upgrade") + execInteractive('bash ./scripts/host_installers/install_docker.sh upgrade') print("") input("Process terminated. Press [Enter] to show menu and continue.") return True diff --git a/menu.sh b/menu.sh index 410d965ab..517b929a8 100755 --- a/menu.sh +++ b/menu.sh @@ -64,32 +64,46 @@ else project_checks + echo "" + printf "Checking Container keys... " if [[ "$(check_container_ssh)" == "false" ]]; then echo "SSH keys for containers do not exist. the menu containers will not be able to execute commands on your host." echo "To regenerate these keys, run:" echo " bash ./menu.sh --run-env-setup" + else + echo "Keys found." fi - if [[ "$(docker_checks)" == "fail" ]]; then + echo "" + printf "Checking Docker state... " + DOCKER_CHECK_RESULT="$(docker_check)" + if [[ "$DOCKER_CHECK_RESULT" == "fail" ]]; then echo "Docker is not setup. Cannot continue" exit 2 fi - if [[ "$(docker_checks)" == "outdated" ]]; then + if [[ "$DOCKER_CHECK_RESULT" == "outdated" ]]; then echo "" echo "Docker is outdated. You should consider updating. To be reprompted, type:" echo " rm .ignore_docker_outofdate" echo "" fi + echo "" + printf "Checking User group... " if [[ "$(group_check)" == "fail" ]]; then echo "User not in correct groups. Run:" echo " bash ./menu.sh --run-env-setup" + else + echo "User in required groups." fi # ---------------------------------------------- # Check state of running menu instances # ---------------------------------------------- + echo "" + printf "Checking menu container state... " + PREBUILT_IMAGES="true" if [[ "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then PREBUILT_IMAGES="false" @@ -104,7 +118,7 @@ else fi if [[ "$PREBUILT_IMAGES" == "false" ]]; then - echo "You either recently installed or upgraded IOTstack. The menu docker images need to be rebuilt in order for the menu to run correctly. This will take about a minute." + echo "You either recently installed or upgraded IOTstack. The menu docker images need to be rebuilt in order for the menu to run correctly. This will take about a minute and is completely automatic." bash ./.internal/docker_menu.sh stop > /dev/null & sleep 1 @@ -121,15 +135,15 @@ else PYCLI_REBUILD_DONE="not completed" until [[ $SLEEP_COUNTER -gt 300 || ("$API_REBUILD_DONE" == "completed" && "$PYCLI_REBUILD_DONE" == "completed") ]]; do - if [[ ! "$(docker images -q iostack_api:$VERSION 2> /dev/null)" == "" ]]; then + if [[ ! "$(docker images -q iostack_api:$VERSION)" == "" ]]; then API_REBUILD_DONE="completed" fi - if [[ ! "$(docker images -q iostack_pycli:$VERSION 2> /dev/null)" == "" ]]; then + if [[ ! "$(docker images -q iostack_pycli:$VERSION)" == "" ]]; then PYCLI_REBUILD_DONE="completed" fi - printf(".") + printf . sleep 1 ((SLEEP_COUNTER++)) @@ -144,6 +158,8 @@ else echo "" fi fi +echo " Menu check completed." +echo "" while test $# -gt 0 do @@ -152,6 +168,8 @@ do ;; --no-check) echo "" ;; + --stop) echo "Stopping all menu containers" && bash ./.internal/docker_menu.sh stop + ;; --run-env-setup) echo "Setting up environment:" generate_container_ssh @@ -178,7 +196,8 @@ do shift done -# If PyCLI is already running reattach +echo "Spinning up menu containers... " +# If PyCLI is already running then reattach PYCLI_ID="$(docker ps --format '{{.ID}} {{.Image}}' | grep -w iostack_pycli:$VERSION | cut -d ' ' -f1 | head -n 1)" if [[ "$PYCLI_ID" == "" ]]; then bash ./.internal/docker_menu.sh diff --git a/scripts/setup_iotstack.sh b/scripts/setup_iotstack.sh index b77f3f7ea..e948796d3 100644 --- a/scripts/setup_iotstack.sh +++ b/scripts/setup_iotstack.sh @@ -107,24 +107,47 @@ function docker_check() { if command_exists docker; then echo "Docker is installed" >&2 - if [ "$(minimum_version_check $REQ_DOCKER_VERSION $DOCKER_VERSION_MAJOR $DOCKER_VERSION_MINOR $DOCKER_VERSION_BUILD )" == "true" ]; then - [ -f .ignore_docker_outofdate ] && rm .ignore_docker_outofdate - DOCKER_GOOD="true" - echo "Docker version $DOCKER_VERSION >= $REQ_DOCKER_VERSION. Docker is good to go." >&2 - else - DOCKER_GOOD="outdated" - if [ ! -f .ignore_docker_outofdate ]; then - if (whiptail --title "Docker and Docker-Compose Version Issue" --yesno "Docker version is currently $DOCKER_VERSION which is less than $REQ_DOCKER_VERSION consider upgrading or you may experience issues. You will not be prompted again. You can manually upgrade by typing:\n sudo apt upgrade docker docker-compose\n\nAttempt to upgrade now?" 20 78); then - update_docker - else - touch .ignore_docker_outofdate - fi + DOCKER_VERSION=$(docker version -f "{{.Server.Version}}" 2>&1) + + if [[ "$DOCKER_VERSION" == *"Cannot connect to the Docker daemon"* ]]; then + echo "Error getting docker version. Error when connecting to docker daemon. Check that docker is running." >&2 + if (whiptail --title "Docker and Docker-Compose" --yesno "Error getting docker version. Error when connecting to docker daemon. Check that docker is running.\n\nCommand: docker version -f \"{{.Server.Version}}\"\n\nExit?" 20 78 >&2); then + exit 1 + fi + elif [[ "$DOCKER_VERSION" == *" permission denied"* ]]; then + echo "Error getting docker version. Received permission denied error. Try running with: ./menu.sh --run-env-setup" >&2 + if (whiptail --title "Docker and Docker-Compose" --yesno "Error getting docker version. Received permission denied error.\n\nTry rerunning the menu with: ./menu.sh --run-env-setup\n\nExit?" 20 78 >&2); then + exit 1 + fi + fi + + if [[ -z "$DOCKER_VERSION" ]]; then + echo "Error getting docker version. Error when running docker command. Check that docker is installed correctly." >&2 + fi + + DOCKER_VERSION_MAJOR=$(echo "$DOCKER_VERSION"| cut -d'.' -f 1) + DOCKER_VERSION_MINOR=$(echo "$DOCKER_VERSION"| cut -d'.' -f 2) + + DOCKER_VERSION_BUILD=$(echo "$DOCKER_VERSION"| cut -d'.' -f 3) + DOCKER_VERSION_BUILD=$(echo "$DOCKER_VERSION_BUILD"| cut -f1 -d"-") + + if [[ "$(minimum_version_check $REQ_DOCKER_VERSION $DOCKER_VERSION_MAJOR $DOCKER_VERSION_MINOR $DOCKER_VERSION_BUILD )" == "true" ]]; then + [ -f .ignore_docker_outofdate ] && rm .ignore_docker_outofdate + DOCKER_GOOD="true" + echo "Docker version $DOCKER_VERSION >= $REQ_DOCKER_VERSION. Docker is good to go." >&2 + else + DOCKER_GOOD="outdated" + if [ ! -f .ignore_docker_outofdate ]; then + if (whiptail --title "Docker and Docker-Compose Version Issue" --yesno "Docker version is currently $DOCKER_VERSION which is less than $REQ_DOCKER_VERSION consider upgrading or you may experience issues. You will not be prompted again. You can manually upgrade by typing:\n sudo apt upgrade docker docker-compose\n\nAttempt to upgrade now?" 20 78 >&2); then + update_docker + else + touch .ignore_docker_outofdate fi fi fi fi - if ! command_exists docker-compose; then + if command_exists docker-compose; then COMPOSE_GOOD="pass" echo "docker-compose is installed" >&2 fi From 75b46360901f53641d15dc4254609b6b9a9e1ac2 Mon Sep 17 00:00:00 2001 From: Slyke Date: Wed, 20 Jan 2021 12:29:06 -0800 Subject: [PATCH 007/142] Added checks for error paths --- .internal/ctrl_api.sh | 2 +- .internal/ctrl_pycli.sh | 2 +- .internal/ctrl_wui.sh | 2 +- .internal/pycli/backup_restore.py | 25 +++++++++++++-------- .internal/pycli/docker_commands.py | 35 +++++++++++++++++------------- .internal/pycli/entry.py | 7 +++--- menu.sh | 17 +++++++++++++++ 7 files changed, 59 insertions(+), 31 deletions(-) diff --git a/.internal/ctrl_api.sh b/.internal/ctrl_api.sh index 310aa3d63..dfb1e9e69 100644 --- a/.internal/ctrl_api.sh +++ b/.internal/ctrl_api.sh @@ -8,7 +8,7 @@ if [ "$1" = "stop" ]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) 2> /dev/null else if [[ $IOTENV == "development" ]]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) 2> /dev/null || docker rmi $FULL_NAME --force 2> /dev/null docker node:14 # Docker occasionally fails to pull image when building when it is not cached. docker build --no-cache -t $FULL_NAME -f ./.internal/api.Dockerfile . else diff --git a/.internal/ctrl_pycli.sh b/.internal/ctrl_pycli.sh index 65d620b19..6df292972 100644 --- a/.internal/ctrl_pycli.sh +++ b/.internal/ctrl_pycli.sh @@ -10,7 +10,7 @@ else if [[ $IOTENV == "development" ]]; then echo "[Development] Stopping container:" echo "docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force" - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) 2> /dev/null || docker rmi $FULL_NAME --force 2> /dev/null echo "" echo "Rebuilding container:" echo "docker build --no-cache -t $FULL_NAME -f ./.internal/pycli.Dockerfile ." diff --git a/.internal/ctrl_wui.sh b/.internal/ctrl_wui.sh index 31b76f34e..e04222825 100644 --- a/.internal/ctrl_wui.sh +++ b/.internal/ctrl_wui.sh @@ -8,7 +8,7 @@ if [ "$1" = "stop" ]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME ) 2> /dev/null else if [[ $IOTENV == "development" ]]; then - docker stop $(docker ps -q --filter ancestor=$FULL_NAME) || docker rmi $FULL_NAME --force + docker stop $(docker ps -q --filter ancestor=$FULL_NAME) 2> /dev/null || docker rmi $FULL_NAME --force 2> /dev/null docker node:alpine # Docker occasionally fails to pull image when building when it is not cached. docker build --no-cache -t $FULL_NAME -f ./.internal/wui.Dockerfile . else diff --git a/.internal/pycli/backup_restore.py b/.internal/pycli/backup_restore.py index e13b8d0a5..a72a91ffc 100644 --- a/.internal/pycli/backup_restore.py +++ b/.internal/pycli/backup_restore.py @@ -5,11 +5,11 @@ def main(): from blessed import Terminal from deps.chars import specialChars, commonTopBorder, commonBottomBorder, commonEmptyLine - global renderMode import time - import subprocess + from deps.host_exec import execInteractive global signal + global renderMode global backupRestoreSelectionInProgress global mainMenuList global currentMenuItemIndex @@ -25,7 +25,8 @@ def main(): def runBackup(): global needsRender print("Execute Backup:") - subprocess.call("./scripts/backup.sh", shell=True) + print("bash ./scripts/backup.sh") + execInteractive('bash ./scripts/backup.sh') print("") print("Backup completed.") print("Press [Up] or [Down] arrow key to show the menu if it has scrolled too far.") @@ -36,9 +37,13 @@ def runBackup(): def dropboxInstall(): global needsRender print("Install Dropbox:") - subprocess.call("git clone https://github.com/andreafabrizi/Dropbox-Uploader.git ~/Dropbox-Uploader", shell=True) - subprocess.call("chmod +x ~/Dropbox-Uploader/dropbox_uploader.sh", shell=True) - subprocess.call("cd ~/Dropbox-Uploader && ./dropbox_uploader.sh", shell=True) + print("git clone https://github.com/andreafabrizi/Dropbox-Uploader.git ~/Dropbox-Uploader") + execInteractive('git clone https://github.com/andreafabrizi/Dropbox-Uploader.git ~/Dropbox-Uploader') + print("chmod +x ~/Dropbox-Uploader/dropbox_uploader.sh") + execInteractive('chmod +x ~/Dropbox-Uploader/dropbox_uploader.sh') + print("cd ~/Dropbox-Uploader && ./dropbox_uploader.sh") + execInteractive('cd ~/Dropbox-Uploader && ./dropbox_uploader.sh') + time.sleep(1) # Give time to see errors print("") print("Dropbox install finished") print("Press [Up] or [Down] arrow key to show the menu if it has scrolled too far.") @@ -50,7 +55,7 @@ def rcloneInstall(): global needsRender print("Install rClone:") print("sudo apt install -y rclone") - subprocess.call("sudo apt install -y rclone", shell=True) + execInteractive('sudo apt install -y rclone') print("") print("rClone install finished") print("Please run 'rclone config' to configure the rclone google drive backup") @@ -61,7 +66,8 @@ def rcloneInstall(): def rCloneSetup(): global needsRender print("Setup rclone:") - subprocess.call("rclone config", shell=True) + print("rclone config") + execInteractive('rclone config') print("") print("rclone setup completed. Press [Up] or [Down] arrow key to show the menu if it has scrolled too far.") time.sleep(1) @@ -71,7 +77,8 @@ def rCloneSetup(): def runRestore(): global needsRender print("Execute Restore:") - subprocess.call("./scripts/restore.sh", shell=True) + print('bash ./scripts/restore.sh') + execInteractive('bash ./scripts/restore.sh') print("") print("Restore completed.") print("Press [Up] or [Down] arrow key to show the menu if it has scrolled too far.") diff --git a/.internal/pycli/docker_commands.py b/.internal/pycli/docker_commands.py index e3bfa9c97..732ef79a1 100644 --- a/.internal/pycli/docker_commands.py +++ b/.internal/pycli/docker_commands.py @@ -6,7 +6,7 @@ def main(): from deps.chars import specialChars, commonTopBorder, commonBottomBorder, commonEmptyLine import math import time - import subprocess + from deps.host_exec import execInteractive global dockerCommandsSelectionInProgress global renderMode @@ -31,7 +31,7 @@ def onResize(sig, action): def startStack(): print("Start Stack:") print("docker-compose up -d --remove-orphans") - subprocess.call("docker-compose up -d", shell=True) + execInteractive('docker-compose up -d --remove-orphans') print("") print("Stack Started") input("Process terminated. Press [Enter] to show menu and continue.") @@ -42,11 +42,12 @@ def restartStack(): print("Restarting Stack...") print("Stop Stack:") print("docker-compose down") + execInteractive('docker-compose down') subprocess.call("docker-compose down", shell=True) print("") print("Start Stack:") print("docker-compose up -d --remove-orphans") - subprocess.call("docker-compose up -d", shell=True) + execInteractive('docker-compose up -d --remove-orphans') # print("docker-compose restart") # subprocess.call("docker-compose restart", shell=True) print("") @@ -58,7 +59,7 @@ def restartStack(): def stopStack(): print("Stop Stack:") print("docker-compose down") - subprocess.call("docker-compose down", shell=True) + execInteractive('docker-compose down') print("") print("Stack Stopped") input("Process terminated. Press [Enter] to show menu and continue.") @@ -66,18 +67,22 @@ def stopStack(): return True def stopAllStack(): + print("Menu containers will shutdown") + time.sleep(0.5) print("Stop All Stack:") + time.sleep(0.2) print("docker container stop $(docker container ls -aq)") - subprocess.call("docker container stop $(docker container ls -aq)", shell=True) + time.sleep(0.2) + execInteractive('docker container stop $(docker container ls -aq)') print("") input("Process terminated. Press [Enter] to show menu and continue.") needsRender = 1 return True def pruneVolumes(): - print("Stop All Stack:") - print("docker container stop $(docker container ls -aq)") - subprocess.call("docker container stop $(docker container ls -aq)", shell=True) + print("Prune Volumes:") + print("docker system prune --volumes") + execInteractive('docker system prune --volumes') print("") input("Process terminated. Press [Enter] to show menu and continue.") needsRender = 1 @@ -86,16 +91,16 @@ def pruneVolumes(): def updateAllContainers(): print("Update All Containers:") print("docker-compose down") - subprocess.call("docker-compose down", shell=True) + execInteractive('docker-compose down') print("") print("docker-compose pull") - subprocess.call("docker-compose pull", shell=True) + execInteractive('docker-compose pull') print("") print("docker-compose build") - subprocess.call("docker-compose build", shell=True) + execInteractive('docker-compose build') print("") print("docker-compose up -d") - subprocess.call("docker-compose up -d", shell=True) + execInteractive('docker-compose up -d') print("") input("Process terminated. Press [Enter] to show menu and continue.") needsRender = 1 @@ -104,7 +109,7 @@ def updateAllContainers(): def deleteAndPruneVolumes(): print("Delete and prune volumes:") print("docker system prune --volumes") - subprocess.call("docker system prune --volumes", shell=True) + execInteractive('docker system prune --volumes') print("") input("Process terminated. Press [Enter] to show menu and continue.") needsRender = 1 @@ -113,7 +118,7 @@ def deleteAndPruneVolumes(): def deleteAndPruneImages(): print("Delete and prune volumes:") print("docker image prune -a") - subprocess.call("docker image prune -a", shell=True) + execInteractive('docker image prune -a') print("") input("Process terminated. Press [Enter] to show menu and continue.") needsRender = 1 @@ -126,7 +131,7 @@ def monitorLogs(): print("") print("docker-compose logs -f") time.sleep(0.5) - subprocess.call("docker-compose logs -f", shell=True) + execInteractive('docker-compose logs -f') print("") time.sleep(0.5) input("Process terminated. Press [Enter] to show menu and continue.") diff --git a/.internal/pycli/entry.py b/.internal/pycli/entry.py index 2a62aed78..7be9f7cda 100644 --- a/.internal/pycli/entry.py +++ b/.internal/pycli/entry.py @@ -31,7 +31,9 @@ readRes = execSilent('cat ./.tmp/rtest.file') rmRes = execSilent('rm ./.tmp/rtest.file') - if readRes != 'exec success': + if readRes == 'exec success': + print('Connection and remote command execution successful') + else: print('Error attempting to execute commands on the host. You may need to regenerate SSH keys by running:') print(' ./menu.sh --run-env-setup') print('') @@ -51,6 +53,3 @@ input("Press Enter to continue to menu...") os.system('python menu_main.py') - -# testInput = input('Enter input: ') -# print('Input you entered', testInput) diff --git a/menu.sh b/menu.sh index 517b929a8..f7dc40561 100755 --- a/menu.sh +++ b/menu.sh @@ -13,6 +13,8 @@ sys_arch=$(uname -m) source ./scripts/setup_iotstack.sh source ./.internal/meta.sh +SKIPCHECKS="false" + function check_git_updates() { UPSTREAM=${1:-'@{u}'} LOCAL=$(git rev-parse @) @@ -59,6 +61,7 @@ function project_checks() { # ---------------------------------------------- if [[ "$*" == *"--no-check"* ]]; then echo "Skipping preflight checks." + SKIPCHECKS="true" else echo "Please enter sudo pasword if prompted" @@ -118,6 +121,7 @@ else fi if [[ "$PREBUILT_IMAGES" == "false" ]]; then + echo " Rebuild requied" echo "You either recently installed or upgraded IOTstack. The menu docker images need to be rebuilt in order for the menu to run correctly. This will take about a minute and is completely automatic." bash ./.internal/docker_menu.sh stop > /dev/null & @@ -148,6 +152,8 @@ else ((SLEEP_COUNTER++)) done + + echo "" fi if [[ $SLEEP_COUNTER -gt 300 ]]; then @@ -197,6 +203,17 @@ do done echo "Spinning up menu containers... " + +if [[ "$SKIPCHECKS" == "false" ]]; then + if nc -w 1 localhost 32777 ; then + echo "WUI detected on localhost:32777" + fi + + if nc -w 1 localhost 32128 ; then + echo "API detected on localhost:32128" + fi +fi + # If PyCLI is already running then reattach PYCLI_ID="$(docker ps --format '{{.ID}} {{.Image}}' | grep -w iostack_pycli:$VERSION | cut -d ' ' -f1 | head -n 1)" if [[ "$PYCLI_ID" == "" ]]; then From 4c9a817f2e6994559ff3820cf204668ccbbc32be Mon Sep 17 00:00:00 2001 From: Slyke Date: Sat, 23 Jan 2021 10:29:18 -0800 Subject: [PATCH 008/142] Added basic volume options --- .internal/api/src/settings.js | 2 +- .internal/wui/.eslintcache | 2 +- .internal/wui/.gitignore | 2 + .internal/wui/package-lock.json | 4 +- .internal/wui/package.json | 3 +- .../general/volumesConfig.jsx | 95 +++++++++++++++++++ .../src/features/serviceUiControls/index.js | 4 +- .../wui/src/utils/configOptionLoader.jsx | 11 ++- .internal/wui/src/utils/parsers.js | 37 +++++++- 9 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 .internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx diff --git a/.internal/api/src/settings.js b/.internal/api/src/settings.js index 435102ebb..edb60d18b 100644 --- a/.internal/api/src/settings.js +++ b/.internal/api/src/settings.js @@ -5,7 +5,7 @@ const Settings = ({ env, logger, version }) => { const retr = { cors: { - origins: ["localhost", "127.0.0.1", "localhost:32777", "127.0.0.1:32777"], + origins: ["localhost", "127.0.0.1", "localhost:32777", "127.0.0.1:32777", "localhost:3000"], headers: ["Content-Type" ,"Origin", "Accept"] }, paths: { diff --git a/.internal/wui/.eslintcache b/.internal/wui/.eslintcache index 8ee4bccb1..23e525070 100644 --- a/.internal/wui/.eslintcache +++ b/.internal/wui/.eslintcache @@ -1 +1 @@ -[{"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/index.js":"1","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/App.js":"2","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/counter/Counter.js":"3","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/index.js":"4","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/counter.js":"5","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/router.jsx":"6","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/asyncDispatchMiddleware.js":"7","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/promiseMiddleware.js":"8","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/constants.js":"9","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/templates.js":"10","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/config.js":"11","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/servicesGridItem/index.jsx":"12","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceMetadataReducer.js":"13","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceMetadata.action.js":"14","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/configs.js":"15","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedServicesReducer.js":"16","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateSelectedServices.action.js":"17","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/Sidebar/index.js":"18","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/notFound/index.js":"19","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/buildHistory/index.jsx":"20","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/help/index.jsx":"21","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/scripts/index.jsx":"22","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildHistoryListReducer.js":"23","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getBuildHistoryList.action.js":"24","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/builds.js":"25","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildHistoryGridItem/index.jsx":"26","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/BuildSidebar/index.jsx":"27","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateFilterTags.action.js":"28","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedFilterTagsReducer.js":"29","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildIssuesReducer.js":"30","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/checkBuildIssues.action.js":"31","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/buildStackReducer.js":"32","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/buildStack.action.js":"33","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildCompletedModal/index.jsx":"34","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getScript.action.js":"35","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getScriptTemplatesReducer.js":"36","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/downloadBuild.action.js":"37","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceConfigModal/index.jsx":"38","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/index.js":"39","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/portConfig.jsx":"40","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/buildOptionSync.js":"41","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceConfigOptionsReducer.js":"42","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceConfigOptions.action.js":"43","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/configOptionLoader.jsx":"44","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/parsers.js":"45","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/mainBuild/index.jsx":"46","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplateList.action.js":"47","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplateListReducer.js":"48","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getNetworkTemplateListReducer.js":"49","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getNetworkTemplateList.action.js":"50","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplatesReducer.js":"51","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplates.action.js":"52","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/networkConfig.jsx":"53","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/logging.jsx":"54"},{"size":353,"mtime":1606908594887,"results":"55","hashOfConfig":"56"},{"size":789,"mtime":1607430281547,"results":"57","hashOfConfig":"56"},{"size":1634,"mtime":1607288886088,"results":"58","hashOfConfig":"59"},{"size":1612,"mtime":1610356071552,"results":"60","hashOfConfig":"56"},{"size":1551,"mtime":1606908622214,"results":"61","hashOfConfig":"56"},{"size":1231,"mtime":1610350276543,"results":"62","hashOfConfig":"56"},{"size":607,"mtime":1607109560543,"results":"63","hashOfConfig":"56"},{"size":711,"mtime":1607260096944,"results":"64","hashOfConfig":"56"},{"size":160,"mtime":1607109631094,"results":"65","hashOfConfig":"56"},{"size":5035,"mtime":1610354111429,"results":"66","hashOfConfig":"56"},{"size":98,"mtime":1607121110848,"results":"67","hashOfConfig":"56"},{"size":11600,"mtime":1610356264839,"results":"68","hashOfConfig":"56"},{"size":1878,"mtime":1607294201436,"results":"69","hashOfConfig":"56"},{"size":375,"mtime":1607260125923,"results":"70","hashOfConfig":"56"},{"size":2528,"mtime":1609913218191,"results":"71","hashOfConfig":"56"},{"size":1105,"mtime":1607294167538,"results":"72","hashOfConfig":"56"},{"size":534,"mtime":1607292532075,"results":"73","hashOfConfig":"56"},{"size":4770,"mtime":1607430353516,"results":"74","hashOfConfig":"56"},{"size":206,"mtime":1607342162060,"results":"75","hashOfConfig":"56"},{"size":1626,"mtime":1610349813009,"results":"76","hashOfConfig":"56"},{"size":204,"mtime":1607342542038,"results":"77","hashOfConfig":"56"},{"size":213,"mtime":1607342531957,"results":"78","hashOfConfig":"56"},{"size":947,"mtime":1607430599186,"results":"79","hashOfConfig":"56"},{"size":340,"mtime":1607430711272,"results":"80","hashOfConfig":"56"},{"size":5471,"mtime":1608852677675,"results":"81","hashOfConfig":"56"},{"size":3558,"mtime":1610347837498,"results":"82","hashOfConfig":"56"},{"size":10365,"mtime":1610350599948,"results":"83","hashOfConfig":"56"},{"size":540,"mtime":1607529608604,"results":"84","hashOfConfig":"56"},{"size":1079,"mtime":1607529487594,"results":"85","hashOfConfig":"56"},{"size":894,"mtime":1607816383799,"results":"86","hashOfConfig":"56"},{"size":358,"mtime":1607816378529,"results":"87","hashOfConfig":"56"},{"size":902,"mtime":1608450868778,"results":"88","hashOfConfig":"56"},{"size":394,"mtime":1608448546580,"results":"89","hashOfConfig":"56"},{"size":3624,"mtime":1610275595190,"results":"90","hashOfConfig":"56"},{"size":390,"mtime":1608850637136,"results":"91","hashOfConfig":"56"},{"size":1714,"mtime":1608802587649,"results":"92","hashOfConfig":"56"},{"size":318,"mtime":1608852934388,"results":"93","hashOfConfig":"56"},{"size":3907,"mtime":1610440735107,"results":"94","hashOfConfig":"56"},{"size":203,"mtime":1610613848946,"results":"95","hashOfConfig":"56"},{"size":2975,"mtime":1610540007725,"results":"96","hashOfConfig":"56"},{"size":2379,"mtime":1610267137497,"results":"97","hashOfConfig":"56"},{"size":1922,"mtime":1609913154250,"results":"98","hashOfConfig":"56"},{"size":419,"mtime":1609913346831,"results":"99","hashOfConfig":"56"},{"size":1244,"mtime":1610614282569,"results":"100","hashOfConfig":"56"},{"size":1299,"mtime":1610540194952,"results":"101","hashOfConfig":"56"},{"size":3836,"mtime":1610356472899,"results":"102","hashOfConfig":"56"},{"size":369,"mtime":1610350419464,"results":"103","hashOfConfig":"56"},{"size":972,"mtime":1610350671817,"results":"104","hashOfConfig":"56"},{"size":972,"mtime":1610352205750,"results":"105","hashOfConfig":"56"},{"size":369,"mtime":1610351960667,"results":"106","hashOfConfig":"56"},{"size":962,"mtime":1610356100446,"results":"107","hashOfConfig":"56"},{"size":340,"mtime":1610354130554,"results":"108","hashOfConfig":"56"},{"size":2716,"mtime":1610613869470,"results":"109","hashOfConfig":"56"},{"size":1630,"mtime":1610614530760,"results":"110","hashOfConfig":"56"},{"filePath":"111","messages":"112","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},"d20lrd",{"filePath":"114","messages":"115","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"116","messages":"117","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"118"},"9qp08d",{"filePath":"119","messages":"120","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"121","messages":"122","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"123","messages":"124","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"125","messages":"126","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"127","messages":"128","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"129","messages":"130","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"131","messages":"132","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"133","messages":"134","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"135","messages":"136","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"137","usedDeprecatedRules":"113"},{"filePath":"138","messages":"139","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"140","messages":"141","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"142","messages":"143","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"144","messages":"145","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"146","messages":"147","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"148","messages":"149","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"150","messages":"151","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"152","messages":"153","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"154","usedDeprecatedRules":"113"},{"filePath":"155","messages":"156","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"157","messages":"158","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"159","messages":"160","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"161","messages":"162","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"163","messages":"164","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"165","messages":"166","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"167","messages":"168","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"169","usedDeprecatedRules":"113"},{"filePath":"170","messages":"171","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"172","messages":"173","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"174","messages":"175","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"176","messages":"177","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"178","messages":"179","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"180","messages":"181","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"182","messages":"183","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"184","messages":"185","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"186","messages":"187","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"188","messages":"189","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"190","messages":"191","errorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"192","usedDeprecatedRules":"113"},{"filePath":"193","messages":"194","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"195","messages":"196","errorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":"197","usedDeprecatedRules":"113"},{"filePath":"198","messages":"199","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"200","messages":"201","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"202","messages":"203","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"204","messages":"205","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"206","messages":"207","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"208","messages":"209","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"210","usedDeprecatedRules":"113"},{"filePath":"211","messages":"212","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"213","messages":"214","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"215","messages":"216","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"217","messages":"218","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"219","messages":"220","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"221","messages":"222","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"113"},{"filePath":"223","messages":"224","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"225","messages":"226","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/index.js",[],["227","228"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/App.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/counter/Counter.js",[],["229","230"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/index.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/counter.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/router.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/asyncDispatchMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/middlewares/promiseMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/constants.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/templates.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/config.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/servicesGridItem/index.jsx",["231"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Skeleton from '@material-ui/lab/Skeleton';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Button from '@material-ui/core/Button';\nimport Link from '@material-ui/core/Link';\nimport ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ServiceConfigModal from '../serviceConfigModal';\nimport { useTheme } from '@material-ui/core/styles';\nimport {\n getBuildIssuesAction\n} from '../../actions/checkBuildIssues.action';\nimport {\n getServiceMetadataAction\n} from '../../actions/getServiceMetadata.action';\nimport {\n getServiceConfigOptionsAction\n} from '../../actions/getServiceConfigOptions.action';\nimport {\n addSelectedService,\n removeSelectedService\n} from '../../actions/updateSelectedServices.action';\nimport styles from './services-grid-item.module.css';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceMetadata: (serviceName) => dispatch(getServiceMetadataAction(serviceName)),\n dispatchGetServiceConfigOptions: (serviceName) => dispatch(getServiceConfigOptionsAction(serviceName)),\n dispatchGetBuildIssues: (selectedServices, serviceConfigurations) => dispatch(getBuildIssuesAction(selectedServices, serviceConfigurations)),\n dispatchAddSelectedService: (serviceName) => dispatch(addSelectedService(serviceName)),\n dispatchRemoveSelectedService: (serviceName) => dispatch(removeSelectedService(serviceName))\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n templateList: selector(state => state.templateList),\n configServiceMetadata: selector(state => state.configServiceMetadata),\n configServiceConfigOptions: selector(state => state.configServiceConfigOptions),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues)\n };\n};\n\nconst useStyles = makeStyles({\n serviceCard: {\n \"&:hover\": {\n borderColor: ({ theme }) => theme.palette.text.primary\n }\n }\n});\n\nconst ServiceItem = (props) => {\n const theme = useTheme();\n const classes = useStyles({ props, theme });\n // console.log('theme.palette', theme.palette)\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n serviceName,\n networkTemplateList,\n serviceTemplates,\n dispatchGetServiceMetadata,\n dispatchGetServiceConfigOptions,\n dispatchAddSelectedService,\n dispatchRemoveSelectedService,\n dispatchGetBuildIssues,\n configServiceMetadata,\n configServiceConfigOptions,\n selectedServices,\n hideServiceTags,\n buildIssues,\n buildOptions,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const [isLoading, setIsLoading] = useState(false);\n const [serviceMetadata, setServiceMetadata] = useState({});\n const [serviceMetadataError, setServiceMetadataError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceMetadata.services.completed[serviceName] === 'undefined'\n && typeof configServiceMetadata.services.failed[serviceName] === 'undefined'\n && !configServiceMetadata.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceMetadata(serviceName);\n }\n\n setIsLoading(false);\n\n if (typeof configServiceMetadata.services.completed[serviceName] === 'object') {\n setServiceMetadata(configServiceMetadata.services.completed[serviceName].payload);\n } else if (!configServiceMetadata.services.pending.includes(serviceName)) {\n setServiceMetadataError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceMetadata,\n configServiceMetadata.services.completed,\n configServiceMetadata.services.pending,\n configServiceMetadata.services.failed\n ]);\n\n const [serviceConfigOptions, setServiceConfigOptions] = useState({});\n const [serviceConfigOptionsError, setServiceConfigOptionsError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceConfigOptions.services.completed[serviceName] === 'undefined'\n && typeof configServiceConfigOptions.services.failed[serviceName] === 'undefined'\n && !configServiceConfigOptions.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceConfigOptions(serviceName);\n }\n\n // setIsLoading(false);\n\n if (typeof configServiceConfigOptions.services.completed[serviceName] === 'object') {\n setServiceConfigOptions(configServiceConfigOptions.services.completed[serviceName].payload);\n } else if (!configServiceConfigOptions.services.pending.includes(serviceName)) {\n setServiceConfigOptionsError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceConfigOptions,\n configServiceConfigOptions.services.completed,\n configServiceConfigOptions.services.pending,\n configServiceConfigOptions.services.failed\n ]);\n\n const [updated, setIsUpdated] = useState(false);\n useEffect(() => {\n if (updated) {\n dispatchGetBuildIssues(selectedServices.selectedServices, {});\n }\n setIsUpdated(false);\n }, [\n updated,\n serviceName,\n selectedServices.selectedServices,\n dispatchGetBuildIssues\n ]);\n\n const [hasIssue, setHasIssue] = useState(false);\n useEffect(() => {\n if (!selectedServices.selectedServices.includes(serviceName)) {\n return void setHasIssue(false);\n }\n const issueList = buildIssues?.payload?.issueList ?? {};\n if (Array.isArray(issueList.services)) {\n issueList.services.forEach((service) => {\n if (service.name === serviceName) {\n return void setHasIssue(true);\n }\n });\n }\n }, [buildIssues, selectedServices.selectedServices, serviceName]);\n\n const handleBuildSelectChange = (evt) => {\n setIsUpdated(true);\n if (evt.target.checked) {\n return dispatchAddSelectedService(serviceName);\n }\n return dispatchRemoveSelectedService(serviceName);\n }\n\n const [modalOpen, setModalOpen] = useState(false);\n\n const serviceComponent = () => {\n return (\n \n setModalOpen(false)}\n serviceMetadata={serviceMetadata}\n serviceConfigOptions={serviceConfigOptions}\n serviceName={serviceName}\n buildOptions={buildOptions}\n setBuildOptions={setBuildOptions}\n setServiceOptions={setServiceOptions}\n getBuildOptions={getBuildOptions}\n buildOptionsInit={buildOptionsInit}\n setTemporaryBuildOptions={setTemporaryBuildOptions}\n getTemporaryBuildOptions={getTemporaryBuildOptions}\n setTemporaryServiceOptions={setTemporaryServiceOptions}\n setupTemporaryBuildOptions={setupTemporaryBuildOptions}\n saveTemporaryBuildOptions={saveTemporaryBuildOptions}\n networkTemplateList={networkTemplateList}\n serviceTemplates={serviceTemplates}\n />\n {serviceMetadata.displayName}\n \n {!serviceMetadata.iconUri\n && (\n \n \n \n )}\n {serviceMetadata.iconUri\n && (\n \n
\n {`${serviceMetadata.displayName}\n
\n
\n )}\n
\n \n \n \n \n \n }\n label={`Add ${serviceMetadata.displayName} to build`}\n />\n \n \n \n {serviceMetadata.displayName} Help and Docs\n \n \n \n )\n };\n\n const errorComponent = () => {\n return (\n \n
Error loading: {serviceName}
\n
Try refreshing, and ensuring the API server is running correctly.
\n
\n )\n };\n\n const loadingComponent = () => {\n return (\n \n Loading '{serviceName}' metadata...\n \n \n \n \n \n \n \n \n \n \n \n \n \n )\n };\n\n const highlightClass = () => {\n if (selectedServices.selectedServices.includes(serviceName)) {\n if (hasIssue) {\n return styles.serviceError;\n } else {\n return styles.selectedForBuild;\n }\n }\n\n return '';\n };\n\n const tagIsHidden = (hiddenTags, serviceTags) => {\n let hide = false;\n\n hiddenTags.forEach((hiddenTag) => {\n serviceTags.forEach((serviceTag) => {\n if (hiddenTag === serviceTag) {\n hide = true;\n }\n });\n });\n\n return hide;\n }\n\n if (!isLoading && tagIsHidden(hideServiceTags.hideServiceTags, serviceMetadata.serviceTypeTags)) {\n return null;\n }\n\n return (\n \n \n {isLoading\n && (loadingComponent())}\n {!isLoading\n && serviceMetadata.displayName\n && (\n serviceComponent()\n )}\n {!isLoading\n && serviceMetadataError.hasError === true\n && (\n errorComponent()\n )}\n \n \n );\n};\n\nexport default ServiceItem;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceMetadataReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceMetadata.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/configs.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedServicesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateSelectedServices.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/Sidebar/index.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/notFound/index.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/buildHistory/index.jsx",["232"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport BuildHistoryGridItem from '../../features/buildHistoryGridItem'\nimport {\n getBuildHistoryListAction\n} from '../../actions/getBuildHistoryList.action';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetBuildHistoryList: () => dispatch(getBuildHistoryListAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n buildHistory: selector(state => state.buildHistory)\n };\n};\n\nconst Main = (props) => {\n\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const { dispatchGetBuildHistoryList, buildHistory } = props;\n\n useEffect(() => {\n dispatchGetBuildHistoryList();\n }, []);\n\n return (\n \n
\n \n {typeof buildHistory.payload !== 'undefined' && Object.keys(buildHistory.payload.buildsList).map((buildDetailsTime) => {\n return (\n \n \n \n );\n })}\n \n
\n
\n );\n}\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/help/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/scripts/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildHistoryListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getBuildHistoryList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/services/builds.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildHistoryGridItem/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/BuildSidebar/index.jsx",["233","234"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\n// import Tooltip from '@material-ui/core/Tooltip';\nimport Button from '@material-ui/core/Button';\n// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport Divider from '@material-ui/core/Divider';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n// import { makeStyles, useTheme } from '@material-ui/core/styles';\nimport styles from './build-sidebar.module.css';\nimport {\n addTagToHideListAction,\n removeTagFromHideListAction\n} from '../../actions/updateFilterTags.action';\nimport {\n createAndBuildStackAction\n} from '../../actions/buildStack.action';\nimport {\n getScriptFromTemplateAction\n} from '../../actions/getScript.action';\nimport {\n downloadBuildFile\n} from '../../actions/downloadBuild.action';\nimport BuildCompletedModal from '../buildCompletedModal';\nimport { API_STATUS } from '../../constants'\n\n// const useStyles = makeStyles({\n// serviceCard: {\n// \"&:hover\": {\n// borderColor: ({ theme }) => theme.palette.text.primary\n// }\n// }\n// });\n\nconst getUniqueTagsFromTemplates = ({ serviceTemplateListPayload, metadataList }) => {\n const tagList = [];\n if (Array.isArray(serviceTemplateListPayload)) {\n serviceTemplateListPayload.forEach((service) => {\n if (metadataList[service] && metadataList[service].payload && Array.isArray(metadataList[service].payload.serviceTypeTags)) {\n metadataList[service].payload.serviceTypeTags.forEach((tag) => {\n if (!tagList.includes(tag)) {\n tagList.push(tag);\n }\n });\n }\n });\n }\n tagList.sort();\n return tagList;\n};\n\nconst buildIssueListItem = (name, issueType, issueText) => {\n return (\n {name} [{issueType}] - {issueText}\n );\n};\n\nconst buildIssuesRender = (issues) => {\n const unknownError = !(\n issues.payload\n && issues.payload.issueList\n && Array.isArray(issues.payload.issueList.services)\n && Array.isArray(issues.payload.issueList.networks)\n && Array.isArray(issues.payload.issueList.other)\n );\n\n const noIssues = (\n !unknownError\n && issues.payload.issueList.services.length === 0\n && issues.payload.issueList.networks.length === 0\n && issues.payload.issueList.other.length === 0\n );\n\n return (\n \n Build Issues:\n \n {issues.status === API_STATUS.SUCCESS\n && (\n \n {Array.isArray(issues.payload.issueList.services)\n && issues.payload.issueList.services.length > 0\n && (\n \n \n Services:\n \n
    \n {issues.payload.issueList.services.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.networks)\n && issues.payload.issueList.networks.length > 0\n && (\n \n \n Networks:\n \n
    \n {issues.payload.issueList.networks.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.other)\n && issues.payload.issueList.other.length > 0\n && (\n \n \n Other Issues:\n \n
    \n {issues.payload.issueList.other.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {noIssues\n && (\n \n \n No build issues\n \n \n )}\n {!noIssues\n && (\n \n \n You can still attempt to build when issues are reported.\n \n \n )}\n {unknownError\n && (\n \n \n An unknown error occured retrieving build issues\n \n \n )}\n
\n )}\n {issues.status === API_STATUS.PENDING\n && (\n Loading...\n )}\n {issues.status === API_STATUS.FAILURE\n && (\n Failed to get build issues from API\n )}\n {issues.status === API_STATUS.UNINIT\n && (\n No changes detected\n )}\n
\n
\n );\n};\n\nconst buildList = (selectedServices) => {\n return (\n \n Building Services:\n \n {selectedServices.join(', ')}\n \n \n );\n};\n\nconst buildServices = (dispatchBuildStack) => {\n return (\n \n Build:\n \n \n \n \n );\n};\n\nconst Sidebar = (props) => {\n // const theme = useTheme();\n // const classes = useStyles({ props, theme });\n\n const mapStateToProps = (selector) => {\n return {\n configServiceMetadata: selector(state => state.configServiceMetadata),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues),\n buildStack: selector(state => state.buildStack),\n scriptTemplates: selector(state => state.scriptTemplates)\n };\n };\n const mapDispatchToProps = (dispatch) => {\n return {\n dispatchAddTagToHideList: (tag) => dispatch(addTagToHideListAction(tag)),\n dispatchRemoveTagFromHideList: (tag) => dispatch(removeTagFromHideListAction(tag)),\n dispatchBuildStack: (selectedServices, serviceConfigurations) => dispatch(createAndBuildStackAction(selectedServices, serviceConfigurations)),\n dispatchGetScriptTemplates: ({ scriptName, options, linkRef }) => dispatch(getScriptFromTemplateAction({ scriptName, options, linkRef })),\n dispatchDownloadBuildFile: ({ build, type, linkRef }) => dispatch(downloadBuildFile({ build, type, linkRef }))\n };\n };\n \n props = {\n ...props,\n ...mapStateToProps(useSelector),\n ...mapDispatchToProps(useDispatch()),\n };\n\n const [modalOpen, setModalOpen] = useState(false);\n useEffect(() => {\n if (props.buildStack.status === API_STATUS.SUCCESS) {\n setModalOpen(true);\n }\n }, [\n props.buildStack\n ]);\n\n const {\n serviceTemplateList,\n configServiceMetadata,\n selectedServices,\n buildIssues,\n hideServiceTags,\n dispatchRemoveTagFromHideList,\n dispatchAddTagToHideList,\n dispatchBuildStack,\n dispatchGetScriptTemplates,\n dispatchDownloadBuildFile,\n buildStack,\n scriptTemplates\n } = props;\n\n const downloadLinkRef = React.useRef(null);\n\n const handleBuildSelectChange = (evt, tagName) => {\n if (evt.target.checked) {\n return dispatchAddTagToHideList(tagName);\n }\n return dispatchRemoveTagFromHideList(tagName);\n };\n\n const serviceFilter = (serviceTemplateListPayload, servicesMetadata) => {\n return (\n \n Hide by tag:\n \n {\n getUniqueTagsFromTemplates({ serviceTemplateListPayload, metadataList: servicesMetadata }).map((tag) => {\n return (\n -1}\n onChange={(evt) => handleBuildSelectChange(evt, tag)}\n name=\"checkedB\"\n color=\"primary\"\n />\n }\n label={tag}\n />\n );\n })\n }\n \n \n );\n };\n \n return (\n \n
\n setModalOpen(false)}\n buildStack={buildStack}\n scriptTemplates={scriptTemplates}\n dispatchGetScriptTemplates={dispatchGetScriptTemplates}\n dispatchDownloadBuildFile={dispatchDownloadBuildFile}\n downloadLinkRef={downloadLinkRef}\n />\n \n {serviceFilter(serviceTemplateList.payload, configServiceMetadata.services.completed)}\n \n {buildIssuesRender(buildIssues)}\n \n {buildList(selectedServices.selectedServices)}\n \n {buildServices(() => {\n if (Array.isArray(selectedServices.selectedServices) && selectedServices.selectedServices.length > 0) {\n dispatchBuildStack(selectedServices.selectedServices);\n }\n })}\n \n \n );\n};\n\nexport default Sidebar;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/updateFilterTags.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/updateSelectedFilterTagsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getBuildIssuesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/checkBuildIssues.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/buildStackReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/buildStack.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/buildCompletedModal/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getScript.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getScriptTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/downloadBuild.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceConfigModal/index.jsx",["235","236","237","238"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Modal from '@material-ui/core/Modal';\nimport Grid from '@material-ui/core/Grid';\nimport Button from \"@material-ui/core/Button\";\nimport Box from '@material-ui/core/Box';\nimport getConfigComponents from '../../utils/configOptionLoader';\nimport {\n deleteTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst getModalStyle = () => {\n const top = 10;\n const left = 50;\n\n return {\n top: `${top}%`,\n left: `${left}%`,\n maxHeight: '75%',\n overflow: 'hidden',\n overflowY: 'scroll',\n transform: `translate(-50%, 0%)`,\n };\n};\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n position: 'absolute',\n width: '50%',\n backgroundColor: theme.palette.background.paper,\n border: '2px solid #000',\n boxShadow: theme.shadows[5],\n padding: theme.spacing(2, 4, 3),\n },\n}));\n\nconst ServiceConfigModal = (props) => {\n const {\n isOpen,\n handleClose,\n serviceName,\n networkTemplateList,\n serviceMetadata,\n serviceConfigOptions,\n buildOptions,\n serviceTemplates,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const closeModal = (event) => {\n deleteTemporaryBuildOptions();\n if (typeof handleClose === 'function') {\n handleClose(event);\n }\n }\n\n const classes = useStyles();\n const [modalStyle] = React.useState(getModalStyle);\n const body = (\n
\n

{serviceMetadata ? serviceMetadata.displayName : ''} ({serviceName}) Configuration

\n \n {getConfigComponents(serviceConfigOptions ?? []).map((ConfigComponent, index) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n \n \n \n \n \n \n
\n );\n\n return (\n \n {body}\n \n );\n};\n\nexport default ServiceConfigModal;","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/index.js",["239"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/portConfig.jsx",["240","241","242","243","244","245","246"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getExternalPort,\n replaceExternalPort,\n getInternalPort\n} from '../../../utils/parsers';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [portSettings, setPortSettings] = useState(getBuildOptions()?.services?.[serviceName]?.ports || {});\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n ports: portSettings\n });\n }, [\n portSettings\n ]);\n\n const onChangeCb = (portKey, portLabelValue, event) => {\n const newPort = event.target.value;\n // const defaultTemplatePort = defaultValue(portKey, portKey);\n setPortSettings({\n ...portSettings,\n [portKey]: replaceExternalPort((portSettings[portKey] || portKey), newPort)\n });\n if (typeof(onChange) === 'function') {\n onChange(portKey, portLabelValue, newPort);\n }\n };\n\n const defaultValue = (portValueKey, defaultValue) => {\n const servicePorts = tempBuildOptions?.services?.[serviceName] ?? {};\n return servicePorts?.ports?.[portValueKey] ?? defaultValue;\n };\n\n return (\n \n \n {serviceConfigOptions && Object.keys(serviceConfigOptions.labeledPorts).map((portValueKey) => {\n const currentPortSetting = portSettings[portValueKey] || defaultValue(portValueKey, portValueKey);\n if ((serviceTemplates[serviceName]?.ports?.[portValueKey] ?? []).indexOf(portValueKey)) { // Only show ports that exist in the YAML template\n return (\n \n { onChangeCb(portValueKey, serviceConfigOptions.labeledPorts[portValueKey], event) }}\n value={getExternalPort(currentPortSetting)}\n />\n \n );\n }\n\n return null;\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/buildOptionSync.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceConfigOptionsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceConfigOptions.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/configOptionLoader.jsx",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/utils/parsers.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/pages/mainBuild/index.jsx",["247"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport Box from '@material-ui/core/Box';\nimport ServiceGridItem from '../../features/servicesGridItem';\nimport BuildSidebar from '../../features/BuildSidebar';\nimport { getServiceTemplateListAction } from '../../actions/getServiceTemplateList.action';\nimport { getServiceTemplatesAction } from '../../actions/getServiceTemplates.action';\nimport { getNetworkTemplateListAction } from '../../actions/getNetworkTemplateList.action';\nimport {\n getBuildOptions,\n setBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceTemplatesList: () => dispatch(getServiceTemplateListAction()),\n dispatchGetNetworkTemplatesList: () => dispatch(getNetworkTemplateListAction()),\n dispatchGetServiceTemplates: () => dispatch(getServiceTemplatesAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n serviceTemplateList: selector(state => state.serviceTemplateList),\n networkTemplateList: selector(state => state.networkTemplateList),\n serviceTemplates: selector(state => state.serviceTemplates)\n };\n};\n\nconst Main = (props) => {\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n dispatchGetServiceTemplatesList,\n dispatchGetNetworkTemplatesList,\n dispatchGetServiceTemplates,\n serviceTemplateList,\n networkTemplateList,\n serviceTemplates\n } = props;\n const buildOptions = getBuildOptions();\n\n useEffect(() => {\n dispatchGetServiceTemplatesList();\n dispatchGetNetworkTemplatesList();\n dispatchGetServiceTemplates();\n }, []);\n\n return (\n \n
\n \n \n \n {Array.isArray(serviceTemplateList.payload) && serviceTemplateList.payload.map((templateName) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n\n
\n
\n );\n};\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getNetworkTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getNetworkTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/reducers/getServiceTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/actions/getServiceTemplates.action.js",[],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/networkConfig.jsx",["248","249","250","251","252","253","254","255","256","257"],"/c/Users/Slyke/Documents/repos/IOTrender/iotstack_ui/src/features/serviceUiControls/general/logging.jsx",["258","259","260","261","262","263","264","265","266","267"],{"ruleId":"268","replacedBy":"269"},{"ruleId":"270","replacedBy":"271"},{"ruleId":"268","replacedBy":"272"},{"ruleId":"270","replacedBy":"273"},{"ruleId":"274","severity":1,"message":"275","line":127,"column":10,"nodeType":"276","messageId":"277","endLine":127,"endColumn":35},{"ruleId":"278","severity":1,"message":"279","line":34,"column":6,"nodeType":"280","endLine":34,"endColumn":8,"suggestions":"281"},{"ruleId":"282","severity":1,"message":"283","line":300,"column":7,"nodeType":"284","endLine":300,"endColumn":34},{"ruleId":"285","severity":1,"message":"286","line":300,"column":7,"nodeType":"284","endLine":300,"endColumn":34},{"ruleId":"274","severity":1,"message":"287","line":1,"column":27,"nodeType":"276","messageId":"277","endLine":1,"endColumn":35},{"ruleId":"274","severity":1,"message":"288","line":1,"column":37,"nodeType":"276","messageId":"277","endLine":1,"endColumn":46},{"ruleId":"274","severity":1,"message":"289","line":10,"column":3,"nodeType":"276","messageId":"277","endLine":10,"endColumn":28},{"ruleId":"274","severity":1,"message":"290","line":46,"column":5,"nodeType":"276","messageId":"277","endLine":46,"endColumn":17},{"ruleId":"291","severity":1,"message":"292","line":5,"column":1,"nodeType":"293","endLine":9,"endColumn":3},{"ruleId":"274","severity":1,"message":"294","line":16,"column":5,"nodeType":"276","messageId":"277","endLine":16,"endColumn":20},{"ruleId":"274","severity":1,"message":"295","line":18,"column":5,"nodeType":"276","messageId":"277","endLine":18,"endColumn":21},{"ruleId":"274","severity":1,"message":"296","line":19,"column":5,"nodeType":"276","messageId":"277","endLine":19,"endColumn":22},{"ruleId":"274","severity":1,"message":"297","line":20,"column":5,"nodeType":"276","messageId":"277","endLine":20,"endColumn":29},{"ruleId":"274","severity":1,"message":"298","line":23,"column":5,"nodeType":"276","messageId":"277","endLine":23,"endColumn":31},{"ruleId":"274","severity":1,"message":"299","line":24,"column":5,"nodeType":"276","messageId":"277","endLine":24,"endColumn":30},{"ruleId":"278","severity":1,"message":"300","line":37,"column":6,"nodeType":"280","endLine":39,"endColumn":4,"suggestions":"301"},{"ruleId":"278","severity":1,"message":"302","line":60,"column":6,"nodeType":"280","endLine":60,"endColumn":8,"suggestions":"303"},{"ruleId":"274","severity":1,"message":"304","line":9,"column":5,"nodeType":"276","messageId":"277","endLine":9,"endColumn":25},{"ruleId":"274","severity":1,"message":"294","line":11,"column":5,"nodeType":"276","messageId":"277","endLine":11,"endColumn":20},{"ruleId":"274","severity":1,"message":"295","line":13,"column":5,"nodeType":"276","messageId":"277","endLine":13,"endColumn":21},{"ruleId":"274","severity":1,"message":"296","line":14,"column":5,"nodeType":"276","messageId":"277","endLine":14,"endColumn":22},{"ruleId":"274","severity":1,"message":"297","line":16,"column":5,"nodeType":"276","messageId":"277","endLine":16,"endColumn":29},{"ruleId":"274","severity":1,"message":"298","line":19,"column":5,"nodeType":"276","messageId":"277","endLine":19,"endColumn":31},{"ruleId":"274","severity":1,"message":"299","line":20,"column":5,"nodeType":"276","messageId":"277","endLine":20,"endColumn":30},{"ruleId":"274","severity":1,"message":"305","line":25,"column":9,"nodeType":"276","messageId":"277","endLine":25,"endColumn":25},{"ruleId":"278","severity":1,"message":"306","line":36,"column":6,"nodeType":"280","endLine":36,"endColumn":8,"suggestions":"307"},{"ruleId":"278","severity":1,"message":"300","line":43,"column":6,"nodeType":"280","endLine":45,"endColumn":4,"suggestions":"308"},{"ruleId":"274","severity":1,"message":"304","line":10,"column":5,"nodeType":"276","messageId":"277","endLine":10,"endColumn":25},{"ruleId":"274","severity":1,"message":"294","line":12,"column":5,"nodeType":"276","messageId":"277","endLine":12,"endColumn":20},{"ruleId":"274","severity":1,"message":"295","line":14,"column":5,"nodeType":"276","messageId":"277","endLine":14,"endColumn":21},{"ruleId":"274","severity":1,"message":"296","line":15,"column":5,"nodeType":"276","messageId":"277","endLine":15,"endColumn":22},{"ruleId":"274","severity":1,"message":"297","line":16,"column":5,"nodeType":"276","messageId":"277","endLine":16,"endColumn":29},{"ruleId":"274","severity":1,"message":"298","line":19,"column":5,"nodeType":"276","messageId":"277","endLine":19,"endColumn":31},{"ruleId":"274","severity":1,"message":"299","line":20,"column":5,"nodeType":"276","messageId":"277","endLine":20,"endColumn":30},{"ruleId":"274","severity":1,"message":"309","line":21,"column":5,"nodeType":"276","messageId":"277","endLine":21,"endColumn":21},{"ruleId":"274","severity":1,"message":"305","line":25,"column":9,"nodeType":"276","messageId":"277","endLine":25,"endColumn":25},{"ruleId":"278","severity":1,"message":"300","line":33,"column":6,"nodeType":"280","endLine":35,"endColumn":4,"suggestions":"310"},"no-native-reassign",["311"],"no-negated-in-lhs",["312"],["311"],["312"],"no-unused-vars","'serviceConfigOptionsError' is assigned a value but never used.","Identifier","unusedVar","react-hooks/exhaustive-deps","React Hook useEffect has a missing dependency: 'dispatchGetBuildHistoryList'. Either include it or remove the dependency array.","ArrayExpression",["313"],"jsx-a11y/anchor-has-content","Anchors must have content and the content must be accessible by a screen reader.","JSXOpeningElement","jsx-a11y/anchor-is-valid","The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md","'useState' is defined but never used.","'useEffect' is defined but never used.","'saveTemporaryBuildOptions' is defined but never used.","'buildOptions' is assigned a value but never used.","import/no-anonymous-default-export","Assign object to a variable before exporting as module default","ExportDefaultDeclaration","'setBuildOptions' is assigned a value but never used.","'buildOptionsInit' is assigned a value but never used.","'setServiceOptions' is assigned a value but never used.","'setTemporaryBuildOptions' is assigned a value but never used.","'setupTemporaryBuildOptions' is assigned a value but never used.","'saveTemporaryBuildOptions' is assigned a value but never used.","React Hook useEffect has missing dependencies: 'getTemporaryBuildOptions', 'serviceName', and 'setTemporaryServiceOptions'. Either include them or remove the dependency array.",["314"],"React Hook useEffect has missing dependencies: 'dispatchGetNetworkTemplatesList', 'dispatchGetServiceTemplates', and 'dispatchGetServiceTemplatesList'. Either include them or remove the dependency array.",["315"],"'serviceConfigOptions' is assigned a value but never used.","'tempBuildOptions' is assigned a value but never used.","React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceName', and 'serviceTemplates'. Either include them or remove the dependency array.",["316"],["317"],"'serviceTemplates' is assigned a value but never used.",["318"],"no-global-assign","no-unsafe-negation",{"desc":"319","fix":"320"},{"desc":"321","fix":"322"},{"desc":"323","fix":"324"},{"desc":"325","fix":"326"},{"desc":"327","fix":"328"},{"desc":"329","fix":"330"},"Update the dependencies array to be: [dispatchGetBuildHistoryList]",{"range":"331","text":"332"},"Update the dependencies array to be: [getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",{"range":"333","text":"334"},"Update the dependencies array to be: [dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",{"range":"335","text":"336"},"Update the dependencies array to be: [getBuildOptions, serviceName, serviceTemplates]",{"range":"337","text":"338"},"Update the dependencies array to be: [getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",{"range":"339","text":"340"},"Update the dependencies array to be: [getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",{"range":"341","text":"342"},[893,895],"[dispatchGetBuildHistoryList]",[1020,1042],"[getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",[2011,2013],"[dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",[1109,1111],"[getBuildOptions, serviceName, serviceTemplates]",[1298,1327],"[getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",[991,1015],"[getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]"] \ No newline at end of file +[{"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/index.js":"1","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/App.js":"2","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/index.js":"3","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/router.jsx":"4","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/counter.js":"5","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js":"6","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js":"7","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js":"8","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js":"9","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js":"10","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js":"11","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js":"12","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js":"13","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js":"14","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js":"15","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js":"16","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js":"17","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js":"18","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/constants.js":"19","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js":"20","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js":"21","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js":"22","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js":"23","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js":"24","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js":"25","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js":"26","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getScript.action.js":"27","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js":"28","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js":"29","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js":"30","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/notFound/index.js":"31","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js":"32","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx":"33","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx":"34","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx":"35","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/help/index.jsx":"36","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/builds.js":"37","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/templates.js":"38","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/configs.js":"39","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js":"40","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/config.js":"41","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx":"42","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx":"43","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx":"44","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js":"45","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx":"46","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx":"47","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx":"48","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js":"49","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx":"50","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx":"51","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx":"52","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx":"53","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/parsers.js":"54"},{"size":353,"mtime":1606908594887,"results":"55","hashOfConfig":"56"},{"size":789,"mtime":1607430281547,"results":"57","hashOfConfig":"56"},{"size":1612,"mtime":1610356071552,"results":"58","hashOfConfig":"56"},{"size":1231,"mtime":1610350276543,"results":"59","hashOfConfig":"56"},{"size":1551,"mtime":1606908622214,"results":"60","hashOfConfig":"56"},{"size":962,"mtime":1610356100446,"results":"61","hashOfConfig":"56"},{"size":972,"mtime":1610350671817,"results":"62","hashOfConfig":"56"},{"size":972,"mtime":1610352205750,"results":"63","hashOfConfig":"56"},{"size":1105,"mtime":1607294167538,"results":"64","hashOfConfig":"56"},{"size":1878,"mtime":1607294201436,"results":"65","hashOfConfig":"56"},{"size":894,"mtime":1607816383799,"results":"66","hashOfConfig":"56"},{"size":1922,"mtime":1609913154250,"results":"67","hashOfConfig":"56"},{"size":947,"mtime":1607430599186,"results":"68","hashOfConfig":"56"},{"size":1079,"mtime":1607529487594,"results":"69","hashOfConfig":"56"},{"size":1714,"mtime":1608802587649,"results":"70","hashOfConfig":"56"},{"size":902,"mtime":1608450868778,"results":"71","hashOfConfig":"56"},{"size":607,"mtime":1607109560543,"results":"72","hashOfConfig":"56"},{"size":711,"mtime":1607260096944,"results":"73","hashOfConfig":"56"},{"size":160,"mtime":1607109631094,"results":"74","hashOfConfig":"56"},{"size":340,"mtime":1610354130554,"results":"75","hashOfConfig":"56"},{"size":369,"mtime":1610350419464,"results":"76","hashOfConfig":"56"},{"size":369,"mtime":1610351960667,"results":"77","hashOfConfig":"56"},{"size":534,"mtime":1607292532075,"results":"78","hashOfConfig":"56"},{"size":340,"mtime":1607430711272,"results":"79","hashOfConfig":"56"},{"size":358,"mtime":1607816378529,"results":"80","hashOfConfig":"56"},{"size":375,"mtime":1607260125923,"results":"81","hashOfConfig":"56"},{"size":390,"mtime":1608850637136,"results":"82","hashOfConfig":"56"},{"size":419,"mtime":1609913346831,"results":"83","hashOfConfig":"56"},{"size":540,"mtime":1607529608604,"results":"84","hashOfConfig":"56"},{"size":394,"mtime":1608448546580,"results":"85","hashOfConfig":"56"},{"size":206,"mtime":1607342162060,"results":"86","hashOfConfig":"56"},{"size":4770,"mtime":1607430353516,"results":"87","hashOfConfig":"56"},{"size":3836,"mtime":1610356472899,"results":"88","hashOfConfig":"56"},{"size":1626,"mtime":1610349813009,"results":"89","hashOfConfig":"56"},{"size":213,"mtime":1607342531957,"results":"90","hashOfConfig":"56"},{"size":204,"mtime":1607342542038,"results":"91","hashOfConfig":"56"},{"size":5471,"mtime":1608852677675,"results":"92","hashOfConfig":"56"},{"size":5035,"mtime":1610354111429,"results":"93","hashOfConfig":"56"},{"size":2528,"mtime":1609913218191,"results":"94","hashOfConfig":"56"},{"size":2379,"mtime":1610267137497,"results":"95","hashOfConfig":"56"},{"size":98,"mtime":1610733891137,"results":"96","hashOfConfig":"56"},{"size":3558,"mtime":1610347837498,"results":"97","hashOfConfig":"56"},{"size":11600,"mtime":1610356264839,"results":"98","hashOfConfig":"56"},{"size":10365,"mtime":1610350599948,"results":"99","hashOfConfig":"56"},{"size":318,"mtime":1608852934388,"results":"100","hashOfConfig":"56"},{"size":3624,"mtime":1610275595190,"results":"101","hashOfConfig":"56"},{"size":3907,"mtime":1610440735107,"results":"102","hashOfConfig":"56"},{"size":1438,"mtime":1611364238145,"results":"103","hashOfConfig":"56"},{"size":261,"mtime":1611364236143,"results":"104","hashOfConfig":"56"},{"size":2716,"mtime":1610613869470,"results":"105","hashOfConfig":"56"},{"size":1630,"mtime":1610614530760,"results":"106","hashOfConfig":"56"},{"size":2975,"mtime":1610540007725,"results":"107","hashOfConfig":"56"},{"size":2915,"mtime":1611426491458,"results":"108","hashOfConfig":"56"},{"size":2145,"mtime":1611366674505,"results":"109","hashOfConfig":"56"},{"filePath":"110","messages":"111","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},"fw5a4t",{"filePath":"113","messages":"114","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"115","messages":"116","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"117","messages":"118","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"119","messages":"120","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"121","messages":"122","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"123","messages":"124","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"125","messages":"126","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"127","messages":"128","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"129","messages":"130","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"131","messages":"132","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"133","messages":"134","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"135","messages":"136","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"137","messages":"138","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"139","messages":"140","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"141","messages":"142","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"143","messages":"144","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"145","messages":"146","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"147","messages":"148","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"149","messages":"150","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"151","messages":"152","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"153","messages":"154","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"155","messages":"156","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"157","messages":"158","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"159","messages":"160","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"161","messages":"162","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"163","messages":"164","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"165","messages":"166","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"167","messages":"168","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"169","messages":"170","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"171","messages":"172","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"173","messages":"174","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"175","messages":"176","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"177","usedDeprecatedRules":"112"},{"filePath":"178","messages":"179","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"180","usedDeprecatedRules":"112"},{"filePath":"181","messages":"182","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"183","messages":"184","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"185","messages":"186","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"187","messages":"188","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"189","messages":"190","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"191","messages":"192","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"193","messages":"194","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"195","messages":"196","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"197","messages":"198","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"199","usedDeprecatedRules":"112"},{"filePath":"200","messages":"201","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"202","usedDeprecatedRules":"112"},{"filePath":"203","messages":"204","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"205","messages":"206","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"207","messages":"208","errorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"209","usedDeprecatedRules":"112"},{"filePath":"210","messages":"211","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"212","messages":"213","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"214","usedDeprecatedRules":"112"},{"filePath":"215","messages":"216","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":"217","usedDeprecatedRules":"112"},{"filePath":"218","messages":"219","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":"220","usedDeprecatedRules":"112"},{"filePath":"221","messages":"222","errorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":"223","usedDeprecatedRules":"112"},{"filePath":"224","messages":"225","errorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"226","messages":"227","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/index.js",[],["228","229"],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/App.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/router.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/counter.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/constants.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getScript.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/notFound/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx",["230"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport Box from '@material-ui/core/Box';\nimport ServiceGridItem from '../../features/servicesGridItem';\nimport BuildSidebar from '../../features/BuildSidebar';\nimport { getServiceTemplateListAction } from '../../actions/getServiceTemplateList.action';\nimport { getServiceTemplatesAction } from '../../actions/getServiceTemplates.action';\nimport { getNetworkTemplateListAction } from '../../actions/getNetworkTemplateList.action';\nimport {\n getBuildOptions,\n setBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceTemplatesList: () => dispatch(getServiceTemplateListAction()),\n dispatchGetNetworkTemplatesList: () => dispatch(getNetworkTemplateListAction()),\n dispatchGetServiceTemplates: () => dispatch(getServiceTemplatesAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n serviceTemplateList: selector(state => state.serviceTemplateList),\n networkTemplateList: selector(state => state.networkTemplateList),\n serviceTemplates: selector(state => state.serviceTemplates)\n };\n};\n\nconst Main = (props) => {\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n dispatchGetServiceTemplatesList,\n dispatchGetNetworkTemplatesList,\n dispatchGetServiceTemplates,\n serviceTemplateList,\n networkTemplateList,\n serviceTemplates\n } = props;\n const buildOptions = getBuildOptions();\n\n useEffect(() => {\n dispatchGetServiceTemplatesList();\n dispatchGetNetworkTemplatesList();\n dispatchGetServiceTemplates();\n }, []);\n\n return (\n \n
\n \n \n \n {Array.isArray(serviceTemplateList.payload) && serviceTemplateList.payload.map((templateName) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n\n
\n
\n );\n};\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx",["231"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport BuildHistoryGridItem from '../../features/buildHistoryGridItem'\nimport {\n getBuildHistoryListAction\n} from '../../actions/getBuildHistoryList.action';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetBuildHistoryList: () => dispatch(getBuildHistoryListAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n buildHistory: selector(state => state.buildHistory)\n };\n};\n\nconst Main = (props) => {\n\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const { dispatchGetBuildHistoryList, buildHistory } = props;\n\n useEffect(() => {\n dispatchGetBuildHistoryList();\n }, []);\n\n return (\n \n
\n \n {typeof buildHistory.payload !== 'undefined' && Object.keys(buildHistory.payload.buildsList).map((buildDetailsTime) => {\n return (\n \n \n \n );\n })}\n \n
\n
\n );\n}\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/help/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/builds.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/templates.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/configs.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/config.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx",["232"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Skeleton from '@material-ui/lab/Skeleton';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Button from '@material-ui/core/Button';\nimport Link from '@material-ui/core/Link';\nimport ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ServiceConfigModal from '../serviceConfigModal';\nimport { useTheme } from '@material-ui/core/styles';\nimport {\n getBuildIssuesAction\n} from '../../actions/checkBuildIssues.action';\nimport {\n getServiceMetadataAction\n} from '../../actions/getServiceMetadata.action';\nimport {\n getServiceConfigOptionsAction\n} from '../../actions/getServiceConfigOptions.action';\nimport {\n addSelectedService,\n removeSelectedService\n} from '../../actions/updateSelectedServices.action';\nimport styles from './services-grid-item.module.css';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceMetadata: (serviceName) => dispatch(getServiceMetadataAction(serviceName)),\n dispatchGetServiceConfigOptions: (serviceName) => dispatch(getServiceConfigOptionsAction(serviceName)),\n dispatchGetBuildIssues: (selectedServices, serviceConfigurations) => dispatch(getBuildIssuesAction(selectedServices, serviceConfigurations)),\n dispatchAddSelectedService: (serviceName) => dispatch(addSelectedService(serviceName)),\n dispatchRemoveSelectedService: (serviceName) => dispatch(removeSelectedService(serviceName))\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n templateList: selector(state => state.templateList),\n configServiceMetadata: selector(state => state.configServiceMetadata),\n configServiceConfigOptions: selector(state => state.configServiceConfigOptions),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues)\n };\n};\n\nconst useStyles = makeStyles({\n serviceCard: {\n \"&:hover\": {\n borderColor: ({ theme }) => theme.palette.text.primary\n }\n }\n});\n\nconst ServiceItem = (props) => {\n const theme = useTheme();\n const classes = useStyles({ props, theme });\n // console.log('theme.palette', theme.palette)\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n serviceName,\n networkTemplateList,\n serviceTemplates,\n dispatchGetServiceMetadata,\n dispatchGetServiceConfigOptions,\n dispatchAddSelectedService,\n dispatchRemoveSelectedService,\n dispatchGetBuildIssues,\n configServiceMetadata,\n configServiceConfigOptions,\n selectedServices,\n hideServiceTags,\n buildIssues,\n buildOptions,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const [isLoading, setIsLoading] = useState(false);\n const [serviceMetadata, setServiceMetadata] = useState({});\n const [serviceMetadataError, setServiceMetadataError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceMetadata.services.completed[serviceName] === 'undefined'\n && typeof configServiceMetadata.services.failed[serviceName] === 'undefined'\n && !configServiceMetadata.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceMetadata(serviceName);\n }\n\n setIsLoading(false);\n\n if (typeof configServiceMetadata.services.completed[serviceName] === 'object') {\n setServiceMetadata(configServiceMetadata.services.completed[serviceName].payload);\n } else if (!configServiceMetadata.services.pending.includes(serviceName)) {\n setServiceMetadataError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceMetadata,\n configServiceMetadata.services.completed,\n configServiceMetadata.services.pending,\n configServiceMetadata.services.failed\n ]);\n\n const [serviceConfigOptions, setServiceConfigOptions] = useState({});\n const [serviceConfigOptionsError, setServiceConfigOptionsError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceConfigOptions.services.completed[serviceName] === 'undefined'\n && typeof configServiceConfigOptions.services.failed[serviceName] === 'undefined'\n && !configServiceConfigOptions.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceConfigOptions(serviceName);\n }\n\n // setIsLoading(false);\n\n if (typeof configServiceConfigOptions.services.completed[serviceName] === 'object') {\n setServiceConfigOptions(configServiceConfigOptions.services.completed[serviceName].payload);\n } else if (!configServiceConfigOptions.services.pending.includes(serviceName)) {\n setServiceConfigOptionsError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceConfigOptions,\n configServiceConfigOptions.services.completed,\n configServiceConfigOptions.services.pending,\n configServiceConfigOptions.services.failed\n ]);\n\n const [updated, setIsUpdated] = useState(false);\n useEffect(() => {\n if (updated) {\n dispatchGetBuildIssues(selectedServices.selectedServices, {});\n }\n setIsUpdated(false);\n }, [\n updated,\n serviceName,\n selectedServices.selectedServices,\n dispatchGetBuildIssues\n ]);\n\n const [hasIssue, setHasIssue] = useState(false);\n useEffect(() => {\n if (!selectedServices.selectedServices.includes(serviceName)) {\n return void setHasIssue(false);\n }\n const issueList = buildIssues?.payload?.issueList ?? {};\n if (Array.isArray(issueList.services)) {\n issueList.services.forEach((service) => {\n if (service.name === serviceName) {\n return void setHasIssue(true);\n }\n });\n }\n }, [buildIssues, selectedServices.selectedServices, serviceName]);\n\n const handleBuildSelectChange = (evt) => {\n setIsUpdated(true);\n if (evt.target.checked) {\n return dispatchAddSelectedService(serviceName);\n }\n return dispatchRemoveSelectedService(serviceName);\n }\n\n const [modalOpen, setModalOpen] = useState(false);\n\n const serviceComponent = () => {\n return (\n \n setModalOpen(false)}\n serviceMetadata={serviceMetadata}\n serviceConfigOptions={serviceConfigOptions}\n serviceName={serviceName}\n buildOptions={buildOptions}\n setBuildOptions={setBuildOptions}\n setServiceOptions={setServiceOptions}\n getBuildOptions={getBuildOptions}\n buildOptionsInit={buildOptionsInit}\n setTemporaryBuildOptions={setTemporaryBuildOptions}\n getTemporaryBuildOptions={getTemporaryBuildOptions}\n setTemporaryServiceOptions={setTemporaryServiceOptions}\n setupTemporaryBuildOptions={setupTemporaryBuildOptions}\n saveTemporaryBuildOptions={saveTemporaryBuildOptions}\n networkTemplateList={networkTemplateList}\n serviceTemplates={serviceTemplates}\n />\n {serviceMetadata.displayName}\n \n {!serviceMetadata.iconUri\n && (\n \n \n \n )}\n {serviceMetadata.iconUri\n && (\n \n
\n {`${serviceMetadata.displayName}\n
\n
\n )}\n
\n \n \n \n \n \n }\n label={`Add ${serviceMetadata.displayName} to build`}\n />\n \n \n \n {serviceMetadata.displayName} Help and Docs\n \n \n \n )\n };\n\n const errorComponent = () => {\n return (\n \n
Error loading: {serviceName}
\n
Try refreshing, and ensuring the API server is running correctly.
\n
\n )\n };\n\n const loadingComponent = () => {\n return (\n \n Loading '{serviceName}' metadata...\n \n \n \n \n \n \n \n \n \n \n \n \n \n )\n };\n\n const highlightClass = () => {\n if (selectedServices.selectedServices.includes(serviceName)) {\n if (hasIssue) {\n return styles.serviceError;\n } else {\n return styles.selectedForBuild;\n }\n }\n\n return '';\n };\n\n const tagIsHidden = (hiddenTags, serviceTags) => {\n let hide = false;\n\n hiddenTags.forEach((hiddenTag) => {\n serviceTags.forEach((serviceTag) => {\n if (hiddenTag === serviceTag) {\n hide = true;\n }\n });\n });\n\n return hide;\n }\n\n if (!isLoading && tagIsHidden(hideServiceTags.hideServiceTags, serviceMetadata.serviceTypeTags)) {\n return null;\n }\n\n return (\n \n \n {isLoading\n && (loadingComponent())}\n {!isLoading\n && serviceMetadata.displayName\n && (\n serviceComponent()\n )}\n {!isLoading\n && serviceMetadataError.hasError === true\n && (\n errorComponent()\n )}\n \n \n );\n};\n\nexport default ServiceItem;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx",["233","234"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\n// import Tooltip from '@material-ui/core/Tooltip';\nimport Button from '@material-ui/core/Button';\n// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport Divider from '@material-ui/core/Divider';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n// import { makeStyles, useTheme } from '@material-ui/core/styles';\nimport styles from './build-sidebar.module.css';\nimport {\n addTagToHideListAction,\n removeTagFromHideListAction\n} from '../../actions/updateFilterTags.action';\nimport {\n createAndBuildStackAction\n} from '../../actions/buildStack.action';\nimport {\n getScriptFromTemplateAction\n} from '../../actions/getScript.action';\nimport {\n downloadBuildFile\n} from '../../actions/downloadBuild.action';\nimport BuildCompletedModal from '../buildCompletedModal';\nimport { API_STATUS } from '../../constants'\n\n// const useStyles = makeStyles({\n// serviceCard: {\n// \"&:hover\": {\n// borderColor: ({ theme }) => theme.palette.text.primary\n// }\n// }\n// });\n\nconst getUniqueTagsFromTemplates = ({ serviceTemplateListPayload, metadataList }) => {\n const tagList = [];\n if (Array.isArray(serviceTemplateListPayload)) {\n serviceTemplateListPayload.forEach((service) => {\n if (metadataList[service] && metadataList[service].payload && Array.isArray(metadataList[service].payload.serviceTypeTags)) {\n metadataList[service].payload.serviceTypeTags.forEach((tag) => {\n if (!tagList.includes(tag)) {\n tagList.push(tag);\n }\n });\n }\n });\n }\n tagList.sort();\n return tagList;\n};\n\nconst buildIssueListItem = (name, issueType, issueText) => {\n return (\n {name} [{issueType}] - {issueText}\n );\n};\n\nconst buildIssuesRender = (issues) => {\n const unknownError = !(\n issues.payload\n && issues.payload.issueList\n && Array.isArray(issues.payload.issueList.services)\n && Array.isArray(issues.payload.issueList.networks)\n && Array.isArray(issues.payload.issueList.other)\n );\n\n const noIssues = (\n !unknownError\n && issues.payload.issueList.services.length === 0\n && issues.payload.issueList.networks.length === 0\n && issues.payload.issueList.other.length === 0\n );\n\n return (\n \n Build Issues:\n \n {issues.status === API_STATUS.SUCCESS\n && (\n \n {Array.isArray(issues.payload.issueList.services)\n && issues.payload.issueList.services.length > 0\n && (\n \n \n Services:\n \n
    \n {issues.payload.issueList.services.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.networks)\n && issues.payload.issueList.networks.length > 0\n && (\n \n \n Networks:\n \n
    \n {issues.payload.issueList.networks.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.other)\n && issues.payload.issueList.other.length > 0\n && (\n \n \n Other Issues:\n \n
    \n {issues.payload.issueList.other.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {noIssues\n && (\n \n \n No build issues\n \n \n )}\n {!noIssues\n && (\n \n \n You can still attempt to build when issues are reported.\n \n \n )}\n {unknownError\n && (\n \n \n An unknown error occured retrieving build issues\n \n \n )}\n
\n )}\n {issues.status === API_STATUS.PENDING\n && (\n Loading...\n )}\n {issues.status === API_STATUS.FAILURE\n && (\n Failed to get build issues from API\n )}\n {issues.status === API_STATUS.UNINIT\n && (\n No changes detected\n )}\n
\n
\n );\n};\n\nconst buildList = (selectedServices) => {\n return (\n \n Building Services:\n \n {selectedServices.join(', ')}\n \n \n );\n};\n\nconst buildServices = (dispatchBuildStack) => {\n return (\n \n Build:\n \n \n \n \n );\n};\n\nconst Sidebar = (props) => {\n // const theme = useTheme();\n // const classes = useStyles({ props, theme });\n\n const mapStateToProps = (selector) => {\n return {\n configServiceMetadata: selector(state => state.configServiceMetadata),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues),\n buildStack: selector(state => state.buildStack),\n scriptTemplates: selector(state => state.scriptTemplates)\n };\n };\n const mapDispatchToProps = (dispatch) => {\n return {\n dispatchAddTagToHideList: (tag) => dispatch(addTagToHideListAction(tag)),\n dispatchRemoveTagFromHideList: (tag) => dispatch(removeTagFromHideListAction(tag)),\n dispatchBuildStack: (selectedServices, serviceConfigurations) => dispatch(createAndBuildStackAction(selectedServices, serviceConfigurations)),\n dispatchGetScriptTemplates: ({ scriptName, options, linkRef }) => dispatch(getScriptFromTemplateAction({ scriptName, options, linkRef })),\n dispatchDownloadBuildFile: ({ build, type, linkRef }) => dispatch(downloadBuildFile({ build, type, linkRef }))\n };\n };\n \n props = {\n ...props,\n ...mapStateToProps(useSelector),\n ...mapDispatchToProps(useDispatch()),\n };\n\n const [modalOpen, setModalOpen] = useState(false);\n useEffect(() => {\n if (props.buildStack.status === API_STATUS.SUCCESS) {\n setModalOpen(true);\n }\n }, [\n props.buildStack\n ]);\n\n const {\n serviceTemplateList,\n configServiceMetadata,\n selectedServices,\n buildIssues,\n hideServiceTags,\n dispatchRemoveTagFromHideList,\n dispatchAddTagToHideList,\n dispatchBuildStack,\n dispatchGetScriptTemplates,\n dispatchDownloadBuildFile,\n buildStack,\n scriptTemplates\n } = props;\n\n const downloadLinkRef = React.useRef(null);\n\n const handleBuildSelectChange = (evt, tagName) => {\n if (evt.target.checked) {\n return dispatchAddTagToHideList(tagName);\n }\n return dispatchRemoveTagFromHideList(tagName);\n };\n\n const serviceFilter = (serviceTemplateListPayload, servicesMetadata) => {\n return (\n \n Hide by tag:\n \n {\n getUniqueTagsFromTemplates({ serviceTemplateListPayload, metadataList: servicesMetadata }).map((tag) => {\n return (\n -1}\n onChange={(evt) => handleBuildSelectChange(evt, tag)}\n name=\"checkedB\"\n color=\"primary\"\n />\n }\n label={tag}\n />\n );\n })\n }\n \n \n );\n };\n \n return (\n \n
\n setModalOpen(false)}\n buildStack={buildStack}\n scriptTemplates={scriptTemplates}\n dispatchGetScriptTemplates={dispatchGetScriptTemplates}\n dispatchDownloadBuildFile={dispatchDownloadBuildFile}\n downloadLinkRef={downloadLinkRef}\n />\n \n {serviceFilter(serviceTemplateList.payload, configServiceMetadata.services.completed)}\n \n {buildIssuesRender(buildIssues)}\n \n {buildList(selectedServices.selectedServices)}\n \n {buildServices(() => {\n if (Array.isArray(selectedServices.selectedServices) && selectedServices.selectedServices.length > 0) {\n dispatchBuildStack(selectedServices.selectedServices);\n }\n })}\n \n \n );\n};\n\nexport default Sidebar;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx",["235","236","237","238"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Modal from '@material-ui/core/Modal';\nimport Grid from '@material-ui/core/Grid';\nimport Button from \"@material-ui/core/Button\";\nimport Box from '@material-ui/core/Box';\nimport getConfigComponents from '../../utils/configOptionLoader';\nimport {\n deleteTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst getModalStyle = () => {\n const top = 10;\n const left = 50;\n\n return {\n top: `${top}%`,\n left: `${left}%`,\n maxHeight: '75%',\n overflow: 'hidden',\n overflowY: 'scroll',\n transform: `translate(-50%, 0%)`,\n };\n};\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n position: 'absolute',\n width: '50%',\n backgroundColor: theme.palette.background.paper,\n border: '2px solid #000',\n boxShadow: theme.shadows[5],\n padding: theme.spacing(2, 4, 3),\n },\n}));\n\nconst ServiceConfigModal = (props) => {\n const {\n isOpen,\n handleClose,\n serviceName,\n networkTemplateList,\n serviceMetadata,\n serviceConfigOptions,\n buildOptions,\n serviceTemplates,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const closeModal = (event) => {\n deleteTemporaryBuildOptions();\n if (typeof handleClose === 'function') {\n handleClose(event);\n }\n }\n\n const classes = useStyles();\n const [modalStyle] = React.useState(getModalStyle);\n const body = (\n
\n

{serviceMetadata ? serviceMetadata.displayName : ''} ({serviceName}) Configuration

\n \n {getConfigComponents(serviceConfigOptions ?? []).map((ConfigComponent, index) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n \n \n \n \n \n \n
\n );\n\n return (\n \n {body}\n \n );\n};\n\nexport default ServiceConfigModal;","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js",["239"],"import PortConfig from './general/portConfig';\nimport NetworkConfig from './general/networkConfig';\nimport Logging from './general/logging';\nimport Volumes from './general/volumesConfig';\n\nexport default {\n PortConfig,\n NetworkConfig,\n Logging,\n Volumes\n};\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx",["240","241","242","243","244","245","246","247","248","249"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n\nconst NetworkConfig = (props) => {\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n networkTemplateList,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [modifiedNetworkList, setModifiedNetworkList] = useState({});\n useEffect(() => {\n const defaultOnNetworks = { ...getBuildOptions()?.services?.[serviceName]?.networks ?? {} };\n serviceTemplates[serviceName]?.networks?.forEach((networkName) => {\n defaultOnNetworks[networkName] = true;\n });\n setModifiedNetworkList({\n ...defaultOnNetworks\n });\n }, []);\n\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n networks: modifiedNetworkList\n });\n }, [\n modifiedNetworkList\n ]);\n\n const onChangeCb = (networkName, event) => {\n const networkSelected = event.target.checked;\n setModifiedNetworkList({\n ...modifiedNetworkList,\n [networkName]: networkSelected\n });\n if (typeof(onChange) === 'function') {\n onChange(networkName, networkName);\n }\n };\n\n const defaultValue = (networkName) => {\n return (serviceTemplates[serviceName]?.networks ?? []).includes(networkName);\n };\n\n return (\n \n IOTstack Networks:\n \n {(networkTemplateList?.payload ?? []).map((networkName) => {\n return (\n \n onChangeCb(networkName, evt) }\n name={networkName}\n color=\"primary\"\n />\n }\n label={networkName}\n />\n \n );\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default NetworkConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx",["250","251","252","253","254","255","256","257","258","259"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Box from '@material-ui/core/Box';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [loggingEnabled, setLoggingEnabled] = useState(getBuildOptions()?.services?.[serviceName]?.loggingEnabled ?? true);\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n loggingEnabled\n });\n }, [\n loggingEnabled\n ]);\n\n const onChangeCb = (event) => {\n const newSetting = event.target.checked;\n setLoggingEnabled(newSetting);\n if (typeof(onChange) === 'function') {\n onChange(newSetting);\n }\n };\n\n return (\n \n \n onChangeCb(evt) }\n name={\"logging\"}\n color=\"primary\"\n />\n }\n label={`Enable Logging for ${serviceName}`}\n />\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx",["260","261","262","263","264","265","266"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getExternalPort,\n replaceExternalPort,\n getInternalPort\n} from '../../../utils/parsers';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [portSettings, setPortSettings] = useState(getBuildOptions()?.services?.[serviceName]?.ports || {});\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n ports: portSettings\n });\n }, [\n portSettings\n ]);\n\n const onChangeCb = (portKey, portLabelValue, event) => {\n const newPort = event.target.value;\n // const defaultTemplatePort = defaultValue(portKey, portKey);\n setPortSettings({\n ...portSettings,\n [portKey]: replaceExternalPort((portSettings[portKey] || portKey), newPort)\n });\n if (typeof(onChange) === 'function') {\n onChange(portKey, portLabelValue, newPort);\n }\n };\n\n const defaultValue = (portValueKey, defaultValue) => {\n const servicePorts = tempBuildOptions?.services?.[serviceName] ?? {};\n return servicePorts?.ports?.[portValueKey] ?? defaultValue;\n };\n\n return (\n \n \n {serviceConfigOptions && Object.keys(serviceConfigOptions.labeledPorts).map((portValueKey) => {\n const currentPortSetting = portSettings[portValueKey] || defaultValue(portValueKey, portValueKey);\n if ((serviceTemplates[serviceName]?.ports?.[portValueKey] ?? []).indexOf(portValueKey)) { // Only show ports that exist in the YAML template\n return (\n \n { onChangeCb(portValueKey, serviceConfigOptions.labeledPorts[portValueKey], event) }}\n value={getExternalPort(currentPortSetting)}\n />\n \n );\n }\n\n return null;\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx",["267","268","269","270","271","272","273","274","275","276","277","278","279"],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/parsers.js",[],{"ruleId":"280","replacedBy":"281"},{"ruleId":"282","replacedBy":"283"},{"ruleId":"284","severity":1,"message":"285","line":60,"column":6,"nodeType":"286","endLine":60,"endColumn":8,"suggestions":"287"},{"ruleId":"284","severity":1,"message":"288","line":34,"column":6,"nodeType":"286","endLine":34,"endColumn":8,"suggestions":"289"},{"ruleId":"290","severity":1,"message":"291","line":127,"column":10,"nodeType":"292","messageId":"293","endLine":127,"endColumn":35},{"ruleId":"294","severity":1,"message":"295","line":300,"column":7,"nodeType":"296","endLine":300,"endColumn":34},{"ruleId":"297","severity":1,"message":"298","line":300,"column":7,"nodeType":"296","endLine":300,"endColumn":34},{"ruleId":"290","severity":1,"message":"299","line":1,"column":27,"nodeType":"292","messageId":"293","endLine":1,"endColumn":35},{"ruleId":"290","severity":1,"message":"300","line":1,"column":37,"nodeType":"292","messageId":"293","endLine":1,"endColumn":46},{"ruleId":"290","severity":1,"message":"301","line":10,"column":3,"nodeType":"292","messageId":"293","endLine":10,"endColumn":28},{"ruleId":"290","severity":1,"message":"302","line":46,"column":5,"nodeType":"292","messageId":"293","endLine":46,"endColumn":17},{"ruleId":"303","severity":1,"message":"304","line":6,"column":1,"nodeType":"305","endLine":11,"endColumn":3},{"ruleId":"290","severity":1,"message":"306","line":9,"column":5,"nodeType":"292","messageId":"293","endLine":9,"endColumn":25},{"ruleId":"290","severity":1,"message":"307","line":11,"column":5,"nodeType":"292","messageId":"293","endLine":11,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":13,"column":5,"nodeType":"292","messageId":"293","endLine":13,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":14,"column":5,"nodeType":"292","messageId":"293","endLine":14,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":29},{"ruleId":"290","severity":1,"message":"311","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":30},{"ruleId":"290","severity":1,"message":"313","line":25,"column":9,"nodeType":"292","messageId":"293","endLine":25,"endColumn":25},{"ruleId":"284","severity":1,"message":"314","line":36,"column":6,"nodeType":"286","endLine":36,"endColumn":8,"suggestions":"315"},{"ruleId":"284","severity":1,"message":"316","line":43,"column":6,"nodeType":"286","endLine":45,"endColumn":4,"suggestions":"317"},{"ruleId":"290","severity":1,"message":"306","line":10,"column":5,"nodeType":"292","messageId":"293","endLine":10,"endColumn":25},{"ruleId":"290","severity":1,"message":"307","line":12,"column":5,"nodeType":"292","messageId":"293","endLine":12,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":14,"column":5,"nodeType":"292","messageId":"293","endLine":14,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":15,"column":5,"nodeType":"292","messageId":"293","endLine":15,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":29},{"ruleId":"290","severity":1,"message":"311","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":30},{"ruleId":"290","severity":1,"message":"318","line":21,"column":5,"nodeType":"292","messageId":"293","endLine":21,"endColumn":21},{"ruleId":"290","severity":1,"message":"313","line":25,"column":9,"nodeType":"292","messageId":"293","endLine":25,"endColumn":25},{"ruleId":"284","severity":1,"message":"316","line":33,"column":6,"nodeType":"286","endLine":35,"endColumn":4,"suggestions":"319"},{"ruleId":"290","severity":1,"message":"307","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":18,"column":5,"nodeType":"292","messageId":"293","endLine":18,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":29},{"ruleId":"290","severity":1,"message":"311","line":23,"column":5,"nodeType":"292","messageId":"293","endLine":23,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":24,"column":5,"nodeType":"292","messageId":"293","endLine":24,"endColumn":30},{"ruleId":"284","severity":1,"message":"316","line":37,"column":6,"nodeType":"286","endLine":39,"endColumn":4,"suggestions":"320"},{"ruleId":"290","severity":1,"message":"306","line":14,"column":5,"nodeType":"292","messageId":"293","endLine":14,"endColumn":25},{"ruleId":"290","severity":1,"message":"307","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":18,"column":5,"nodeType":"292","messageId":"293","endLine":18,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":29},{"ruleId":"290","severity":1,"message":"321","line":22,"column":5,"nodeType":"292","messageId":"293","endLine":22,"endColumn":31},{"ruleId":"290","severity":1,"message":"311","line":23,"column":5,"nodeType":"292","messageId":"293","endLine":23,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":24,"column":5,"nodeType":"292","messageId":"293","endLine":24,"endColumn":30},{"ruleId":"290","severity":1,"message":"318","line":25,"column":5,"nodeType":"292","messageId":"293","endLine":25,"endColumn":21},{"ruleId":"290","severity":1,"message":"322","line":26,"column":5,"nodeType":"292","messageId":"293","endLine":26,"endColumn":13},{"ruleId":"290","severity":1,"message":"313","line":29,"column":9,"nodeType":"292","messageId":"293","endLine":29,"endColumn":25},{"ruleId":"290","severity":1,"message":"323","line":32,"column":10,"nodeType":"292","messageId":"293","endLine":32,"endColumn":24},{"ruleId":"290","severity":1,"message":"324","line":32,"column":26,"nodeType":"292","messageId":"293","endLine":32,"endColumn":43},"no-native-reassign",["325"],"no-negated-in-lhs",["326"],"react-hooks/exhaustive-deps","React Hook useEffect has missing dependencies: 'dispatchGetNetworkTemplatesList', 'dispatchGetServiceTemplates', and 'dispatchGetServiceTemplatesList'. Either include them or remove the dependency array.","ArrayExpression",["327"],"React Hook useEffect has a missing dependency: 'dispatchGetBuildHistoryList'. Either include it or remove the dependency array.",["328"],"no-unused-vars","'serviceConfigOptionsError' is assigned a value but never used.","Identifier","unusedVar","jsx-a11y/anchor-has-content","Anchors must have content and the content must be accessible by a screen reader.","JSXOpeningElement","jsx-a11y/anchor-is-valid","The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md","'useState' is defined but never used.","'useEffect' is defined but never used.","'saveTemporaryBuildOptions' is defined but never used.","'buildOptions' is assigned a value but never used.","import/no-anonymous-default-export","Assign object to a variable before exporting as module default","ExportDefaultDeclaration","'serviceConfigOptions' is assigned a value but never used.","'setBuildOptions' is assigned a value but never used.","'buildOptionsInit' is assigned a value but never used.","'setServiceOptions' is assigned a value but never used.","'setTemporaryBuildOptions' is assigned a value but never used.","'setupTemporaryBuildOptions' is assigned a value but never used.","'saveTemporaryBuildOptions' is assigned a value but never used.","'tempBuildOptions' is assigned a value but never used.","React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceName', and 'serviceTemplates'. Either include them or remove the dependency array.",["329"],"React Hook useEffect has missing dependencies: 'getTemporaryBuildOptions', 'serviceName', and 'setTemporaryServiceOptions'. Either include them or remove the dependency array.",["330"],"'serviceTemplates' is assigned a value but never used.",["331"],["332"],"'setTemporaryServiceOptions' is assigned a value but never used.","'onChange' is assigned a value but never used.","'volumeSettings' is assigned a value but never used.","'setVolumeSettings' is assigned a value but never used.","no-global-assign","no-unsafe-negation",{"desc":"333","fix":"334"},{"desc":"335","fix":"336"},{"desc":"337","fix":"338"},{"desc":"339","fix":"340"},{"desc":"341","fix":"342"},{"desc":"343","fix":"344"},"Update the dependencies array to be: [dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",{"range":"345","text":"346"},"Update the dependencies array to be: [dispatchGetBuildHistoryList]",{"range":"347","text":"348"},"Update the dependencies array to be: [getBuildOptions, serviceName, serviceTemplates]",{"range":"349","text":"350"},"Update the dependencies array to be: [getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",{"range":"351","text":"352"},"Update the dependencies array to be: [getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",{"range":"353","text":"354"},"Update the dependencies array to be: [getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",{"range":"355","text":"356"},[2011,2013],"[dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",[893,895],"[dispatchGetBuildHistoryList]",[1109,1111],"[getBuildOptions, serviceName, serviceTemplates]",[1298,1327],"[getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",[991,1015],"[getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",[1020,1042],"[getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]"] \ No newline at end of file diff --git a/.internal/wui/.gitignore b/.internal/wui/.gitignore index c0676348c..80c051b06 100644 --- a/.internal/wui/.gitignore +++ b/.internal/wui/.gitignore @@ -1,5 +1,7 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +*.eslintcache + # dependencies /node_modules /.pnp diff --git a/.internal/wui/package-lock.json b/.internal/wui/package-lock.json index 5d1f1a2e0..f8de67636 100644 --- a/.internal/wui/package-lock.json +++ b/.internal/wui/package-lock.json @@ -1,6 +1,6 @@ { - "name": "iotstack_ui", - "version": "0.1.0", + "name": "iotstack_wui", + "version": "0.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/.internal/wui/package.json b/.internal/wui/package.json index 186af0658..cafd33bad 100644 --- a/.internal/wui/package.json +++ b/.internal/wui/package.json @@ -18,7 +18,8 @@ "react-scripts": "4.0.1" }, "scripts": { - "start": "set PORT=32777 && react-scripts start", + "start2": "set PORT=32777 && react-scripts start", + "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" diff --git a/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx b/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx new file mode 100644 index 000000000..e98556d48 --- /dev/null +++ b/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx @@ -0,0 +1,95 @@ +import React, { Fragment, useState, useEffect } from 'react'; +// import Box from '@material-ui/core/Box'; +import Grid from '@material-ui/core/Grid'; +import TextField from '@material-ui/core/TextField'; +import { + getExternalVolume, + getInternalVolume + // replaceExternalVolume +} from '../../../utils/parsers'; + +const VolumesConfig = (props) => { + + const { + serviceConfigOptions, + serviceName, + setBuildOptions, + getBuildOptions, + buildOptionsInit, + setServiceOptions, + setTemporaryBuildOptions, + getTemporaryBuildOptions, + setTemporaryServiceOptions, + setupTemporaryBuildOptions, + saveTemporaryBuildOptions, + serviceTemplates, + onChange + } = props; + + const tempBuildOptions = getTemporaryBuildOptions(); + const yamlVolumeSettings = getBuildOptions()?.services?.[serviceName]?.volumes || []; + + const [volumeSettings, setVolumeSettings] = useState(yamlVolumeSettings); + useEffect(() => { + // setTemporaryServiceOptions(serviceName, { + // ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {}, + // ports: portSettings + // }); + }, [ + // portSettings + ]); + + const onChangeCb = (portKey, portLabelValue, event) => { + // const newPort = event.target.value; + // // const defaultTemplatePort = defaultValue(portKey, portKey); + // setPortSettings({ + // ...portSettings, + // [portKey]: replaceExternalVolume((portSettings[portKey] || portKey), newPort) + // }); + // if (typeof(onChange) === 'function') { + // onChange(portKey, portLabelValue, newPort); + // } + }; + + return ( + + Volumes + + {yamlVolumeSettings.map((volume) => { + console.log(1111, volume) + const internalVolume = getInternalVolume(volume); + + let temporaryVolume = ''; + (getTemporaryBuildOptions()?.services?.[serviceName]?.volumes ?? []).forEach((tempVolume) => { + if (getInternalVolume(tempVolume) === internalVolume) { + temporaryVolume = getTemporaryBuildOptions()?.services?.[serviceName]?.volumes ?? ''; + } else { + temporaryVolume = volume; + } + }); + const defaultExternalVolume = getExternalVolume(volume); + const currntExternalVolume = getExternalVolume(temporaryVolume); + + return ( + + { onChangeCb(internalVolume, event) }} + value={temporaryVolume ? currntExternalVolume : defaultExternalVolume} + /> + + ); + })} + + + ); +}; + +export default VolumesConfig; diff --git a/.internal/wui/src/features/serviceUiControls/index.js b/.internal/wui/src/features/serviceUiControls/index.js index 3949bc9f3..11ba058f3 100644 --- a/.internal/wui/src/features/serviceUiControls/index.js +++ b/.internal/wui/src/features/serviceUiControls/index.js @@ -1,9 +1,11 @@ import PortConfig from './general/portConfig'; import NetworkConfig from './general/networkConfig'; import Logging from './general/logging'; +import Volumes from './general/volumesConfig'; export default { PortConfig, NetworkConfig, - Logging + Logging, + Volumes }; diff --git a/.internal/wui/src/utils/configOptionLoader.jsx b/.internal/wui/src/utils/configOptionLoader.jsx index c464af8cb..928b2c149 100644 --- a/.internal/wui/src/utils/configOptionLoader.jsx +++ b/.internal/wui/src/utils/configOptionLoader.jsx @@ -17,14 +17,21 @@ const getConfigComponents = (configOptions) => { } else { return null; } - + case "logging": if (configOptions[configName] === true) { // Check if set to true return ServiceUiControls.Logging } else { return null; } - + + case "volumes": + if (configOptions[configName] === true) { // Check if set to true + return ServiceUiControls.Volumes + } else { + return null; + } + default: if (configOptions[configName]) { // Check if set return () => (
Unknown Option {configName}
); diff --git a/.internal/wui/src/utils/parsers.js b/.internal/wui/src/utils/parsers.js index 0acb27aba..3c1986dc8 100644 --- a/.internal/wui/src/utils/parsers.js +++ b/.internal/wui/src/utils/parsers.js @@ -44,10 +44,45 @@ const replaceExternalPort = (intExtStr, newExtPort) => { return intExtStr; }; +const getExternalVolume = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const splitted = intExtStr.split(':'); + if (splitted.length === 2) { + return splitted[0]; + } + } + + return intExtStr; +}; + +const getInternalVolume = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const splitted = intExtStr.split(':'); + if (splitted.length === 2) { + return splitted[1]; + } + } + + return intExtStr; +}; + +const replaceExternalVolume = (intExtStr, newExtVolume) => { + if (typeof(intExtStr) === 'string' && (typeof(newExtVolume) === 'string')) { + const intLoc = intExtStr.indexOf(':'); + const VolumesWithoutExt = intExtStr.substring(intLoc, intExtStr.length); + return `${newExtVolume}${VolumesWithoutExt}`; + } + + return intExtStr; +}; + module.exports = { getExternalPort, getInternalPort, replaceExternalPort, - getPortProtocol + getPortProtocol, + getExternalVolume, + getInternalVolume, + replaceExternalVolume }; \ No newline at end of file From 233afdd43cfd7a063f91fbedaed275d44aa785c9 Mon Sep 17 00:00:00 2001 From: Slyke Date: Fri, 12 Feb 2021 01:12:45 -0800 Subject: [PATCH 009/142] Added some basic compiling and issue checking. Added remaining services --- .internal/api/package.json | 2 +- .internal/api/src/controllers/build.js | 21 +- .internal/api/src/utils/commonBuildChecks.js | 37 +++ .internal/api/src/utils/commonCompileLogic.js | 156 ++++++++++++ .internal/api/src/utils/dockerParse.js | 124 +++++++++ .internal/ctrl_api.sh | 4 +- .internal/ctrl_wui.sh | 4 +- .internal/templates/services/adminer/build.js | 83 +++++- .../templates/services/adminer/config.js | 2 +- .../templates/services/blynk_server/build.js | 105 ++++++++ .../blynk_server/buildFiles/Dockerfile | 25 ++ .../templates/services/blynk_server/config.js | 47 ++++ .../services/blynk_server/directoryfix.sh | 90 +++++++ .../services/blynk_server/template.yml | 14 ++ .../templates/services/dashmachine/build.js | 52 +++- .../templates/services/dashmachine/config.js | 2 +- .internal/templates/services/deconz/build.js | 148 +++++++++++ .internal/templates/services/deconz/config.js | 63 +++++ .../templates/services/deconz/template.yml | 24 ++ .internal/templates/services/diyhue/build.js | 105 ++++++++ .internal/templates/services/diyhue/config.js | 45 ++++ .../templates/services/diyhue/template.yml | 16 ++ .../templates/services/domoticz/build.js | 52 +++- .../templates/services/domoticz/config.js | 2 +- .../templates/services/domoticz/template.yml | 2 - .internal/templates/services/dozzle/build.js | 52 +++- .internal/templates/services/dozzle/config.js | 2 +- .../templates/services/espruinohub/build.js | 52 +++- .../templates/services/espruinohub/config.js | 2 +- .internal/templates/services/gitea/build.js | 82 ++++-- .internal/templates/services/gitea/config.js | 2 +- .internal/templates/services/grafana/build.js | 52 +++- .../templates/services/grafana/config.js | 2 +- .../templates/services/heimdall/build.js | 52 +++- .../templates/services/heimdall/config.js | 6 +- .../services/home_assistant/build.js | 82 ++++-- .../services/home_assistant/config.js | 4 +- .../templates/services/homebridge/build.js | 105 ++++++++ .../templates/services/homebridge/config.js | 45 ++++ .../services/homebridge/template.yml | 15 ++ .internal/templates/services/homer/build.js | 82 ++++-- .internal/templates/services/homer/config.js | 2 +- .../templates/services/influxdb/build.js | 52 +++- .../templates/services/influxdb/config.js | 2 +- .internal/templates/services/mariadb/build.js | 82 ++++-- .../templates/services/mariadb/config.js | 2 +- .../templates/services/mosquitto/build.js | 78 ++++-- .../templates/services/mosquitto/config.js | 6 +- .../templates/services/motioneye/build.js | 68 ++++- .../templates/services/motioneye/config.js | 7 +- .../templates/services/motioneye/template.yml | 8 +- .../templates/services/nextcloud/build.js | 105 ++++++++ .../templates/services/nextcloud/config.js | 45 ++++ .../templates/services/nextcloud/template.yml | 35 +++ .internal/templates/services/nodered/build.js | 112 ++++++--- .../templates/services/nodered/config.js | 3 +- .internal/templates/services/openhab/build.js | 52 +++- .../templates/services/openhab/config.js | 2 +- .internal/templates/services/pihole/build.js | 82 ++++-- .internal/templates/services/pihole/config.js | 2 +- .internal/templates/services/plex/build.js | 82 ++++-- .internal/templates/services/plex/config.js | 4 +- .../templates/services/portainer/build.js | 52 +++- .../templates/services/portainer/config.js | 2 +- .../services/portainer_agent/build.js | 52 +++- .../services/portainer_agent/config.js | 2 +- .../templates/services/portainer_ce/build.js | 82 ++++-- .../templates/services/portainer_ce/config.js | 2 +- .../templates/services/postgres/build.js | 82 ++++-- .../templates/services/postgres/config.js | 2 +- .../templates/services/prometheus/build.js | 105 ++++++++ .../services/prometheus/buildFiles/build.sh | 36 +++ .../buildFiles/service_cadvisor-arm.yml | 13 + .../buildFiles/service_node-exporter.yml | 6 + .../templates/services/prometheus/config.js | 45 ++++ .../prometheus/serviceFiles/config.yml | 10 + .../services/prometheus/template.yml | 13 + .../templates/services/qbittorrent/build.js | 82 ++++-- .../templates/services/qbittorrent/config.js | 2 +- .internal/templates/services/rtl_433/build.js | 105 ++++++++ .../services/rtl_433/buildFiles/Dockerfile | 18 ++ .../templates/services/rtl_433/config.js | 42 ++++ .../templates/services/rtl_433/template.yml | 13 + .../templates/services/tasmoadmin/build.js | 82 ++++-- .../templates/services/tasmoadmin/config.js | 2 +- .../templates/services/telegraf/build.js | 105 ++++++++ .../templates/services/telegraf/config.js | 42 ++++ .../telegraf/serviceFiles/telegraf.conf | 237 ++++++++++++++++++ .../templates/services/telegraf/template.yml | 11 + .../templates/services/timescaledb/build.js | 82 ++++-- .../templates/services/timescaledb/config.js | 2 +- .../templates/services/transmission/build.js | 82 ++++-- .../templates/services/transmission/config.js | 2 +- .../templates/services/web_things/build.js | 105 ++++++++ .../templates/services/web_things/config.js | 46 ++++ .../services/web_things/template.yml | 9 + .../templates/services/wireguard/build.js | 105 ++++++++ .../templates/services/wireguard/config.js | 45 ++++ .../services/wireguard/serviceFiles/wg0.conf | 0 .../templates/services/wireguard/template.yml | 23 ++ .../templates/services/wireguard/tmp/build.sh | 11 + .../templates/services/zigbee2mqtt/build.js | 82 ++++-- .../templates/services/zigbee2mqtt/config.js | 2 +- .internal/wui/.eslintcache | 2 +- .../wui/src/features/BuildSidebar/index.jsx | 19 +- .../src/features/serviceConfigModal/index.jsx | 3 +- .../general/devicesConfig.jsx | 99 ++++++++ .../general/environmentConfig.jsx | 121 +++++++++ .../serviceUiControls/general/logging.jsx | 18 +- .../general/networkConfig.jsx | 88 +++++-- .../serviceUiControls/general/portConfig.jsx | 12 +- .../general/volumesConfig.jsx | 99 ++++---- .../src/features/serviceUiControls/index.js | 6 +- .../src/features/servicesGridItem/index.jsx | 19 +- .../services-grid-item.module.css | 10 + .../wui/src/utils/configOptionLoader.jsx | 14 ++ .internal/wui/src/utils/parsers.js | 40 ++- 117 files changed, 4434 insertions(+), 650 deletions(-) create mode 100644 .internal/api/src/utils/commonBuildChecks.js create mode 100644 .internal/api/src/utils/commonCompileLogic.js create mode 100644 .internal/api/src/utils/dockerParse.js create mode 100644 .internal/templates/services/blynk_server/build.js create mode 100644 .internal/templates/services/blynk_server/buildFiles/Dockerfile create mode 100644 .internal/templates/services/blynk_server/config.js create mode 100644 .internal/templates/services/blynk_server/directoryfix.sh create mode 100644 .internal/templates/services/blynk_server/template.yml create mode 100644 .internal/templates/services/deconz/build.js create mode 100644 .internal/templates/services/deconz/config.js create mode 100644 .internal/templates/services/deconz/template.yml create mode 100644 .internal/templates/services/diyhue/build.js create mode 100644 .internal/templates/services/diyhue/config.js create mode 100644 .internal/templates/services/diyhue/template.yml create mode 100644 .internal/templates/services/homebridge/build.js create mode 100644 .internal/templates/services/homebridge/config.js create mode 100644 .internal/templates/services/homebridge/template.yml create mode 100644 .internal/templates/services/nextcloud/build.js create mode 100644 .internal/templates/services/nextcloud/config.js create mode 100644 .internal/templates/services/nextcloud/template.yml create mode 100644 .internal/templates/services/prometheus/build.js create mode 100644 .internal/templates/services/prometheus/buildFiles/build.sh create mode 100644 .internal/templates/services/prometheus/buildFiles/service_cadvisor-arm.yml create mode 100644 .internal/templates/services/prometheus/buildFiles/service_node-exporter.yml create mode 100644 .internal/templates/services/prometheus/config.js create mode 100644 .internal/templates/services/prometheus/serviceFiles/config.yml create mode 100644 .internal/templates/services/prometheus/template.yml create mode 100644 .internal/templates/services/rtl_433/build.js create mode 100644 .internal/templates/services/rtl_433/buildFiles/Dockerfile create mode 100644 .internal/templates/services/rtl_433/config.js create mode 100644 .internal/templates/services/rtl_433/template.yml create mode 100644 .internal/templates/services/telegraf/build.js create mode 100644 .internal/templates/services/telegraf/config.js create mode 100644 .internal/templates/services/telegraf/serviceFiles/telegraf.conf create mode 100644 .internal/templates/services/telegraf/template.yml create mode 100644 .internal/templates/services/web_things/build.js create mode 100644 .internal/templates/services/web_things/config.js create mode 100644 .internal/templates/services/web_things/template.yml create mode 100644 .internal/templates/services/wireguard/build.js create mode 100644 .internal/templates/services/wireguard/config.js create mode 100644 .internal/templates/services/wireguard/serviceFiles/wg0.conf create mode 100644 .internal/templates/services/wireguard/template.yml create mode 100644 .internal/templates/services/wireguard/tmp/build.sh create mode 100644 .internal/wui/src/features/serviceUiControls/general/devicesConfig.jsx create mode 100644 .internal/wui/src/features/serviceUiControls/general/environmentConfig.jsx diff --git a/.internal/api/package.json b/.internal/api/package.json index 3ca47c7fb..91846371a 100644 --- a/.internal/api/package.json +++ b/.internal/api/package.json @@ -5,7 +5,7 @@ "repository": "https://github.com/SensorsIot/IOTstack", "main": "index.js", "scripts": { - "start": "NODE_ENV=production node index.js", + "start": "NODE_ENV=production nodemon index.js", "dev": "NODE_ENV=dev nodemon index.js" }, "author": "", diff --git a/.internal/api/src/controllers/build.js b/.internal/api/src/controllers/build.js index 339dd09fc..7d2dfb770 100644 --- a/.internal/api/src/controllers/build.js +++ b/.internal/api/src/controllers/build.js @@ -82,7 +82,6 @@ const BuildController = ({ server, settings, version, logger }) => { console.warn('Failed to compile some templates: ', failedStack); } - // All templates gathered and ready for processing by each service. const templatesBuildLogic = []; const { @@ -338,6 +337,26 @@ const BuildController = ({ server, settings, version, logger }) => { other: [] }; + // Compile service options to JSON output + for (let i = 0; i < templatesBuildLogic.length; i++) { + await templatesBuildLogic[i].compile({ + outputTemplateJson: outputStack, + buildOptions, + }); + } + + await Promise.allSettled(networkTemplatePromises).then((networkTemplateResults) => { + networkTemplateResults.forEach((networkPromiseResult) => { + if (networkPromiseResult.status === 'fulfilled' && networkPromiseResult.value) { + const networkName = Object.keys(networkPromiseResult.value)[0]; + outputStack.networks[networkName] = networkPromiseResult.value[networkName]; + } else { + failedStack.networks.push(networkPromiseResult); + } + }); + return outputStack; + }); + return templatesBuildLogic.reduce((prom, buildLogic) => { return prom.then(() => { if (typeof buildLogic.issues === 'function') { diff --git a/.internal/api/src/utils/commonBuildChecks.js b/.internal/api/src/utils/commonBuildChecks.js new file mode 100644 index 000000000..ae4283ced --- /dev/null +++ b/.internal/api/src/utils/commonBuildChecks.js @@ -0,0 +1,37 @@ +const { + getExternalPort +} = require('./dockerParse'); + +const checkPortConflicts = ({ buildTemplate, buildOptions, serviceName }) => { + const portConflicts = []; + const currentServiceExternalPorts = buildTemplate?.services?.[serviceName]?.ports?.map((port) => { + return getExternalPort(port); + }) ?? []; + + Object.keys(buildTemplate?.services ?? {}).forEach((service) => { + if (service === serviceName) { + return null; // Skip self + } + + const checkingServiceExternalPorts = buildTemplate?.services?.[service]?.ports?.map((port) => { + return getExternalPort(port); + }) ?? []; + + checkingServiceExternalPorts.forEach((port) => { + if (currentServiceExternalPorts.includes(port)) { + portConflicts.push({ + type: 'service', + name: serviceName, + issueType: 'portConflict', + message: `Port '${port}' is also used by '${service}'` + }); + } + }); + }); + + return portConflicts; +}; + +module.exports = { + checkPortConflicts +}; diff --git a/.internal/api/src/utils/commonCompileLogic.js b/.internal/api/src/utils/commonCompileLogic.js new file mode 100644 index 000000000..2efa1e10a --- /dev/null +++ b/.internal/api/src/utils/commonCompileLogic.js @@ -0,0 +1,156 @@ +const { + getExternalVolume, + getInternalVolume, + replaceExternalVolume, + getEnvironmentKey, + getEnvironmentValue, + replaceEnvironmentValue, +} = require('./dockerParse'); + + +const setModifiedPorts = ({ buildTemplate, buildOptions, serviceName }) => { + const serviceTemplate = buildTemplate?.services?.[serviceName]; + const serviceConfig = buildOptions?.serviceConfigurations?.services?.[serviceName]; + + const modifiedPortList = Object.keys(serviceConfig?.ports ?? {}); + let updated = false; + + for (let i = 0; i < modifiedPortList.length; i++) { + (serviceTemplate?.ports ?? []).forEach((port, index) => { + if (port === modifiedPortList[i]) { + if (serviceTemplate.ports[index] !== serviceConfig.ports[modifiedPortList[i]]) { + updated = true; + } + serviceTemplate.ports[index] = serviceConfig.ports[modifiedPortList[i]]; + } + }); + } + + return updated; +}; + +const setLoggingState = ({ buildTemplate, buildOptions, serviceName }) => { + const serviceTemplate = buildTemplate?.services?.[serviceName]; + const serviceConfig = buildOptions?.serviceConfigurations?.services?.[serviceName]; + + if (serviceConfig?.loggingEnabled === false) { + if (serviceTemplate.logging) { + delete serviceTemplate?.logging; + return true; + } + return false; + } + + return true; +}; + +const setNetworkMode = ({ buildTemplate, buildOptions, serviceName }) => { + const serviceTemplate = buildTemplate?.services?.[serviceName]; + const serviceConfig = buildOptions?.serviceConfigurations?.services?.[serviceName]; + + if (serviceConfig?.networkMode) { + if ( + serviceTemplate['network_mode'] !== serviceConfig.networkMode + && serviceConfig.networkMode !== 'Unchanged' + && serviceConfig.networkMode !== '' + ) { + serviceTemplate['network_mode'] = serviceConfig.networkMode; + return true; + } + } + + return false; +}; + +const setNetworks = ({ buildTemplate, buildOptions, serviceName }) => { + const serviceTemplate = buildTemplate?.services?.[serviceName]; + const serviceConfig = buildOptions?.serviceConfigurations?.services?.[serviceName]; + let updated = false; + + Object.keys(serviceConfig?.networks ?? {}).forEach((network) => { + serviceTemplate.networks = []; + if (serviceConfig.networks[network] === true) { + serviceTemplate.networks.push(network); + } + updated = true; + }); + + return updated; +}; + +const setVolumes = ({ buildTemplate, buildOptions, serviceName }) => { + const serviceTemplate = buildTemplate?.services?.[serviceName]; + const serviceConfig = buildOptions?.serviceConfigurations?.services?.[serviceName]; + let updated = false; + + if (Array.isArray(serviceConfig?.volumes ?? false)) { + serviceConfig.volumes.forEach((configVolume, volumeIndex) => { + const configInternalVolume = getInternalVolume(configVolume); + let found = false; + for (let i = 0; i < (serviceTemplate?.volumes ?? []).length; i++) { + const templateInternalVolume = getInternalVolume(serviceTemplate.volumes[i]); + + if (templateInternalVolume === configInternalVolume) { + const configExternalVolume = getExternalVolume(configVolume); + if (configExternalVolume === '') { + serviceTemplate.volumes.splice(i, 1); + } else { + serviceTemplate.volumes[i] = replaceExternalVolume(configVolume, configExternalVolume); + } + updated = true; + found = true; + break; + } + } + + if (!found) { + serviceTemplate.volumes[i].push(configVolume); + } + }); + } + + return updated; +}; + +const setEnvironmentVariables = ({ buildTemplate, buildOptions, serviceName }) => { + const serviceTemplate = buildTemplate?.services?.[serviceName]; + const serviceConfig = buildOptions?.serviceConfigurations?.services?.[serviceName]; + let updated = false; + + if (Array.isArray(serviceConfig?.environment ?? false)) { + serviceConfig.environment.forEach((configEnvironment, environmenteIndex) => { + const configEnvironmentKey = getEnvironmentKey(configEnvironment); + let found = false; + for (let i = 0; i < (serviceTemplate?.environment ?? []).length; i++) { + const templateEnvironmentKey = getEnvironmentKey(serviceTemplate.environment[i]); + + if (templateEnvironmentKey === configEnvironmentKey) { + const newEnvironmentValue = getEnvironmentValue(configEnvironment); + if (newEnvironmentValue === '') { + serviceTemplate.environment.splice(i, 1); + } else { + serviceTemplate.environment[i] = replaceEnvironmentValue(configEnvironment, newEnvironmentValue); + } + updated = true; + found = true; + break; + } + } + + if (!found) { + serviceTemplate.environment[i].push(configEnvironment); + } + }); + } + + return updated; +}; + +module.exports = { + setModifiedPorts, + setLoggingState, + setNetworkMode, + setNetworks, + setVolumes, + setEnvironmentVariables +}; diff --git a/.internal/api/src/utils/dockerParse.js b/.internal/api/src/utils/dockerParse.js new file mode 100644 index 000000000..d3ab4c5b3 --- /dev/null +++ b/.internal/api/src/utils/dockerParse.js @@ -0,0 +1,124 @@ +const getExternalPort = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const splitted = intExtStr.split(':'); + if (splitted.length === 2) { + return splitted[0]; + } + } + + return intExtStr; +}; + +const getInternalPort = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const portSection = intExtStr.split('/'); // So that /TCP or /UDP is not returned. + const splitted = portSection[0].split(':'); + if (splitted.length === 2) { + return splitted[1]; + } + } + + return intExtStr; +}; + +const getPortProtocol = (intExtProtStr) => { + if (typeof(intExtProtStr) === 'string') { + const splitted = intExtProtStr.split('/'); + if (splitted.length === 2) { + return splitted[1]; + } + } + + return intExtProtStr; +}; + +const replaceExternalPort = (intExtStr, newExtPort) => { + if (typeof(intExtStr) === 'string' && (typeof(newExtPort) === 'string' || typeof(newExtPort) === 'number')) { + const intAndProtLoc = intExtStr.indexOf(':'); + if (intAndProtLoc > 0 && intAndProtLoc < 6) { + const portsWithoutExt = intExtStr.substring(intAndProtLoc, intExtStr.length); + return `${newExtPort}${portsWithoutExt}`; + } + } + + return intExtStr; +}; + +const getExternalVolume = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const splitted = intExtStr.split(':'); + if (splitted.length === 2) { + return splitted[0]; + } + } + + return intExtStr; +}; + +const getInternalVolume = (intExtStr) => { + if (typeof(intExtStr) === 'string') { + const splitted = intExtStr.split(':'); + if (splitted.length === 2) { + return splitted[1]; + } + } + + return intExtStr; +}; + +const replaceExternalVolume = (intExtStr, newExtVolume) => { + if (typeof(intExtStr) === 'string' && (typeof(newExtVolume) === 'string')) { + const intLoc = intExtStr.indexOf(':'); + const volumesWithoutExt = intExtStr.substring(intLoc, intExtStr.length); + return `${newExtVolume}${volumesWithoutExt}`; + } + + return intExtStr; +}; + +const getEnvironmentKey = (EnvKVStr) => { + if (typeof(EnvKVStr) === 'string') { + const splitted = EnvKVStr.split('='); + if (splitted.length === 2) { + return splitted[0]; + } + } + + return EnvKVStr; +}; + +const getEnvironmentValue = (EnvKVStr) => { + if (typeof(EnvKVStr) === 'string') { + const splitted = EnvKVStr.split('='); + if (splitted.length === 2) { + return splitted[1]; + } + } + + return EnvKVStr; +}; + +const replaceEnvironmentValue = (EnvKVStr, newEnvValue) => { + if (typeof(EnvKVStr) === 'string' && (typeof(newEnvValue) === 'string')) { + const intLoc = EnvKVStr.indexOf('='); + const EnvWithoutValue = EnvKVStr.substring(intLoc, EnvKVStr.length); + return `${EnvWithoutValue}${newEnvValue}`; + } + + return EnvKVStr; +}; + + + +module.exports = { + getExternalPort, + getInternalPort, + replaceExternalPort, + getPortProtocol, + getExternalVolume, + getInternalVolume, + replaceExternalVolume, + getEnvironmentKey, + getEnvironmentValue, + replaceEnvironmentValue +}; \ No newline at end of file diff --git a/.internal/ctrl_api.sh b/.internal/ctrl_api.sh index dfb1e9e69..cafb2b1d1 100644 --- a/.internal/ctrl_api.sh +++ b/.internal/ctrl_api.sh @@ -9,12 +9,12 @@ if [ "$1" = "stop" ]; then else if [[ $IOTENV == "development" ]]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME) 2> /dev/null || docker rmi $FULL_NAME --force 2> /dev/null - docker node:14 # Docker occasionally fails to pull image when building when it is not cached. + docker pull node:14 # Docker occasionally fails to pull image when building when it is not cached. docker build --no-cache -t $FULL_NAME -f ./.internal/api.Dockerfile . else if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then echo "Building '$FULL_NAME'" - docker node:14 # Docker occasionally fails to pull image when building when it is not cached. + docker pull node:14 # Docker occasionally fails to pull image when building when it is not cached. docker build --quiet -t $FULL_NAME -f ./.internal/api.Dockerfile . else echo "Build for '$FULL_NAME' already exists. Skipping..." diff --git a/.internal/ctrl_wui.sh b/.internal/ctrl_wui.sh index e04222825..cff0cdc59 100644 --- a/.internal/ctrl_wui.sh +++ b/.internal/ctrl_wui.sh @@ -9,12 +9,12 @@ if [ "$1" = "stop" ]; then else if [[ $IOTENV == "development" ]]; then docker stop $(docker ps -q --filter ancestor=$FULL_NAME) 2> /dev/null || docker rmi $FULL_NAME --force 2> /dev/null - docker node:alpine # Docker occasionally fails to pull image when building when it is not cached. + docker pull node:alpine # Docker occasionally fails to pull image when building when it is not cached. docker build --no-cache -t $FULL_NAME -f ./.internal/wui.Dockerfile . else if [[ "$(docker images -q $FULL_NAME 2> /dev/null)" == "" ]]; then echo "Building '$FULL_NAME'" - docker node:alpine # Docker occasionally fails to pull image when building when it is not cached. + docker pull node:alpine # Docker occasionally fails to pull image when building when it is not cached. docker build --quiet -t $FULL_NAME -f ./.internal/wui.Dockerfile . else echo "Build for '$FULL_NAME' already exists. Skipping..." diff --git a/.internal/templates/services/adminer/build.js b/.internal/templates/services/adminer/build.js index 0f67b61da..f58b3f20a 100644 --- a/.internal/templates/services/adminer/build.js +++ b/.internal/templates/services/adminer/build.js @@ -6,33 +6,54 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'adminer'; + const { + setModifiedPorts, + setLoggingState, + setNetworkMode, + setNetworks + } = require('../../../src/utils/commonCompileLogic'); + + const { + checkPortConflicts + } = require('../../../src/utils/commonBuildChecks'); + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + + const compileResults = { + modifiedPorts: setModifiedPorts({ buildTemplate: outputTemplateJson, buildOptions, serviceName }), + modifiedLogging: setLoggingState({ buildTemplate: outputTemplateJson, buildOptions, serviceName }), + modifiedNetworkMode: setNetworkMode({ buildTemplate: outputTemplateJson, buildOptions, serviceName }), + modifiedNetworks: setNetworks({ buildTemplate: outputTemplateJson, buildOptions, serviceName }) + }; + console.info(`ServiceBuilder:compile() - '${serviceName}' Results:`, compileResults); + + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -48,9 +69,15 @@ const ServiceBuilder = ({ return new Promise((resolve, reject) => { try { console.info(`ServiceBuilder:issues() - '${serviceName}' started`); - // Code here + let issues = []; + + const portConflicts = checkPortConflicts({ buildTemplate: outputTemplateJson, buildOptions, serviceName }); + issues = [...issues, ...portConflicts]; + + console.info(`ServiceBuilder:issues() - '${serviceName}' Issues found: ${issues.length}`); + checkPortConflicts({ buildTemplate: outputTemplateJson, serviceConfigurations: buildOptions }) console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); - return resolve([]); + return resolve(issues); } catch (err) { console.error(err); console.trace(); @@ -67,6 +94,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/adminer/config.js b/.internal/templates/services/adminer/config.js index 74310bb8a..eb7620c9b 100644 --- a/.internal/templates/services/adminer/config.js +++ b/.internal/templates/services/adminer/config.js @@ -34,7 +34,7 @@ const adminer = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Adminer', + displayName: 'Adminer (untested)', serviceTypeTags: ['wui', 'database manager'] }; }; diff --git a/.internal/templates/services/blynk_server/build.js b/.internal/templates/services/blynk_server/build.js new file mode 100644 index 000000000..c01349485 --- /dev/null +++ b/.internal/templates/services/blynk_server/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'blynk_server'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here TODO: Finish blynk_server + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/blynk_server/buildFiles/Dockerfile b/.internal/templates/services/blynk_server/buildFiles/Dockerfile new file mode 100644 index 000000000..da0ef4a0a --- /dev/null +++ b/.internal/templates/services/blynk_server/buildFiles/Dockerfile @@ -0,0 +1,25 @@ +FROM adoptopenjdk/openjdk14 +MAINTAINER 877dev <877dev@gmail.com> + +#RUN apt-get update +#RUN apt-get install -y apt-utils +#RUN apt-get install -y default-jdk curl + +ENV BLYNK_SERVER_VERSION 0.41.14 +RUN mkdir /blynk +RUN curl -L https://github.com/blynkkk/blynk-server/releases/download/v${BLYNK_SERVER_VERSION}/server-${BLYNK_SERVER_VERSION}.jar > /blynk/server.jar + +# Create data folder. To persist data, map a volume to /data +RUN mkdir /data + +# Create configuration folder. To persist data, map a file to /config/server.properties +RUN mkdir /config && touch /config/server.properties +VOLUME ["/config", "/data/backup"] + +# IP port listing: +# 8080: Hardware without ssl/tls support +# 9443: Blynk app, https, web sockets, admin port +EXPOSE 8080 9443 + +WORKDIR /data +ENTRYPOINT ["java", "-jar", "/blynk/server.jar", "-dataFolder", "/data", "-serverConfig", "/config/server.properties", "-mailConfig", "/config/mail.properties"] diff --git a/.internal/templates/services/blynk_server/config.js b/.internal/templates/services/blynk_server/config.js new file mode 100644 index 000000000..fdbc2bdab --- /dev/null +++ b/.internal/templates/services/blynk_server/config.js @@ -0,0 +1,47 @@ +const blynk_server = () => { + const retr = {}; + + const serviceName = 'blynk_server'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8180:8080": 'http', + "8441:8441": 'other', + "9443:9443": 'ssl' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: 'https://github.com/blynkkk/blynk-server', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Blynk Server (untested)', + serviceTypeTags: ['wui', 'iot'] + }; + }; + + return retr; +}; + +module.exports = blynk_server; diff --git a/.internal/templates/services/blynk_server/directoryfix.sh b/.internal/templates/services/blynk_server/directoryfix.sh new file mode 100644 index 000000000..ff3d40b19 --- /dev/null +++ b/.internal/templates/services/blynk_server/directoryfix.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Create config files for Blynk custom server + +#current user +u=$(whoami) + +#Check if the config directory already exists: +if [ ! -d ./volumes/blynk_server/data/config ]; then + #Create the config directory + sudo mkdir -p ./volumes/blynk_server/data/config + + #Create the properties files: + #cd ~/IOTstack/volumes/blynk_server/data/config + sudo touch ./volumes/blynk_server/data/config/server.properties + sudo touch ./volumes/blynk_server/data/config/mail.properties + + #Give permissions: + sudo chown -R $u:$u ./volumes/blynk_server/data/config + + #Populate the server.properties file: + sudo echo "hardware.mqtt.port=8440 + http.port=8080 + force.port.80.for.csv=false + force.port.80.for.redirect=true + https.port=9443 + data.folder=./data + logs.folder=./logs + log.level=info + user.devices.limit=10 + user.tags.limit=100 + user.dashboard.max.limit=100 + user.widget.max.size.limit=20 + user.message.quota.limit=100 + notifications.queue.limit=2000 + blocking.processor.thread.pool.limit=6 + notifications.frequency.user.quota.limit=5 + webhooks.frequency.user.quota.limit=1000 + webhooks.response.size.limit=96 + user.profile.max.size=128 + terminal.strings.pool.size=25 + map.strings.pool.size=25 + lcd.strings.pool.size=6 + table.rows.pool.size=100 + profile.save.worker.period=60000 + stats.print.worker.period=60000 + web.request.max.size=524288 + csv.export.data.points.max=43200 + hard.socket.idle.timeout=10 + enable.db=false + enable.raw.db.data.store=false + async.logger.ring.buffer.size=2048 + allow.reading.widget.without.active.app=false + allow.store.ip=true + initial.energy=1000000 + admin.rootPath=/admin + restore.host=blynk-cloud.com + product.name=Blynk + admin.email=admin@blynk.cc + admin.pass=admin + " > ./volumes/blynk_server/data/config/server.properties + + #Populate the mail.properties file: + sudo echo "mail.smtp.auth=true + mail.smtp.starttls.enable=true + mail.smtp.host=smtp.gmail.com + mail.smtp.port=587 + mail.smtp.username=YOUR_GMAIL@gmail.com + mail.smtp.password=YOUR_GMAIL_APP_PASSWORD + mail.smtp.connectiontimeout=30000 + mail.smtp.timeout=120000 + " > ./volumes/blynk_server/data/config/mail.properties + + #Information messages: + echo "Sample properties files created in ~/IOTstack/volumes/blynk_server/data/config" + echo "Make sure you edit the files with your details, and restart the container to take effect." + + + +fi + + + + + + + + + + diff --git a/.internal/templates/services/blynk_server/template.yml b/.internal/templates/services/blynk_server/template.yml new file mode 100644 index 000000000..cbe446958 --- /dev/null +++ b/.internal/templates/services/blynk_server/template.yml @@ -0,0 +1,14 @@ +blynk_server: + build: ./services/blynk_server/. + container_name: blynk_server + restart: unless-stopped + ports: + - "8180:8080" + - "8441:8441" + - "9443:9443" + volumes: + - ./volumes/blynk_server/data:/data + - ./volumes/blynk_server/config:/config + networks: + - iotstack_nw + diff --git a/.internal/templates/services/dashmachine/build.js b/.internal/templates/services/dashmachine/build.js index e32e55905..e5e9412f6 100644 --- a/.internal/templates/services/dashmachine/build.js +++ b/.internal/templates/services/dashmachine/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'dashmachine'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/dashmachine/config.js b/.internal/templates/services/dashmachine/config.js index 35227a91a..1738b1640 100644 --- a/.internal/templates/services/dashmachine/config.js +++ b/.internal/templates/services/dashmachine/config.js @@ -34,7 +34,7 @@ const dashmachine = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'DashMachine', + displayName: 'DashMachine (untested)', serviceTypeTags: ['wui', 'dashboard'] }; }; diff --git a/.internal/templates/services/deconz/build.js b/.internal/templates/services/deconz/build.js new file mode 100644 index 000000000..f9ee0d140 --- /dev/null +++ b/.internal/templates/services/deconz/build.js @@ -0,0 +1,148 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'deconz'; + + const { + setModifiedPorts, + setLoggingState, + setNetworkMode, + setNetworks, + setVolumes + } = require('../../../src/utils/commonCompileLogic'); + + const { + checkPortConflicts + } = require('../../../src/utils/commonBuildChecks'); + + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + const checkDeconzDevice = (devicePath) => { + return ` +if [[ ! -f ${devicePath} ]]; then + echo "Ensure that Deconz has the correct device set in environment and devices list: ${devicePath}" + sleep 2 +fi +`; + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + + const compileResults = { + modifiedPorts: setModifiedPorts({ buildTemplate: outputTemplateJson, buildOptions, serviceName }), + modifiedLogging: setLoggingState({ buildTemplate: outputTemplateJson, buildOptions, serviceName }), + modifiedNetworkMode: setNetworkMode({ buildTemplate: outputTemplateJson, buildOptions, serviceName }), + modifiedNetworks: setNetworks({ buildTemplate: outputTemplateJson, buildOptions, serviceName }), + modifiedVolumes: setVolumes({ buildTemplate: outputTemplateJson, buildOptions, serviceName }) + }; + console.info(`ServiceBuilder:compile() - '${serviceName}' Results:`, compileResults); + + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + let issues = []; + + const portConflicts = checkPortConflicts({ buildTemplate: outputTemplateJson, buildOptions, serviceName }); + issues = [...issues, ...portConflicts]; + + console.info(`ServiceBuilder:issues() - '${serviceName}' Issues found: ${issues.length}`); + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve(issues); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + postbuildScripts.push({ + serviceName, + comment: 'Check deconz set env device', + multilineComment: null, + code: checkDeconzDevice('/dev/ttyS0') // TODO: Finish this logic + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/deconz/config.js b/.internal/templates/services/deconz/config.js new file mode 100644 index 000000000..bb6c3462d --- /dev/null +++ b/.internal/templates/services/deconz/config.js @@ -0,0 +1,63 @@ +const deconz = () => { + const retr = {}; + + const serviceName = 'deconz'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "8090:80": 'http', + "433:433": 'ssl', + "5900:5900": 'other' + }, + modifyableEnvironment: [ + { + key: 'DECONZ_VNC_MODE', + value: '1' + }, + { + key: 'DECONZ_VNC_PASSWORD', + value: '{$randomPassword}' + }, + { + key: 'DECONZ_DEVICE', + value: '{$selectedDevice}' + } + ], + devices: true, + volumes: true, + networks: true, + deconzSelectedDevice: true, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Deconz (untested)', + serviceTypeTags: ['iot'] + }; + }; + + return retr; +}; + +module.exports = deconz; diff --git a/.internal/templates/services/deconz/template.yml b/.internal/templates/services/deconz/template.yml new file mode 100644 index 000000000..c3fb471d2 --- /dev/null +++ b/.internal/templates/services/deconz/template.yml @@ -0,0 +1,24 @@ +deconz: + image: marthoc/deconz + container_name: deconz + restart: unless-stopped + ports: + - "8090:80" + - "443:443" + - "5901:5900" + volumes: + - ./volumes/deconz/:/root/.local/share/dresden-elektronik/deCONZ + devices: # This list is replaced during the build process. Modify the list in "config.js" to change it. + - /dev/null + environment: + - DECONZ_VNC_MODE=1 + - DECONZ_VNC_PASSWORD=%randomPassword% + - DEBUG_INFO=1 + - DEBUG_APS=0 + - DEBUG_ZCL=0 + - DEBUG_ZDP=0 + - DEBUG_OTAU=0 + - DECONZ_DEVICE=/dev/null # This is updated during the build process. + networks: + - iotstack_nw + diff --git a/.internal/templates/services/diyhue/build.js b/.internal/templates/services/diyhue/build.js new file mode 100644 index 000000000..6f4f8db8f --- /dev/null +++ b/.internal/templates/services/diyhue/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'diyhue'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/diyhue/config.js b/.internal/templates/services/diyhue/config.js new file mode 100644 index 000000000..3dc840491 --- /dev/null +++ b/.internal/templates/services/diyhue/config.js @@ -0,0 +1,45 @@ +const diyhue = () => { + const retr = {}; + + const serviceName = 'diyhue'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9080:8080": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'diyhue (untested)', + serviceTypeTags: ['wui', 'iot'] + }; + }; + + return retr; +}; + +module.exports = diyhue; diff --git a/.internal/templates/services/diyhue/template.yml b/.internal/templates/services/diyhue/template.yml new file mode 100644 index 000000000..d986d8c06 --- /dev/null +++ b/.internal/templates/services/diyhue/template.yml @@ -0,0 +1,16 @@ +diyhue: + container_name: diyhue + image: diyhue/core:latest + ports: + - "8070:80/tcp" + - "1900:1900/udp" + - "1982:1982/udp" + - "2100:2100/udp" + environment: + - IP=%LAN_IP_Address% + - MAC=%LAN_MAC_Address% + volumes: + - ./volumes/diyhue/:/opt/hue-emulator/export/ + restart: unless-stopped + networks: + - iotstack_nw diff --git a/.internal/templates/services/domoticz/build.js b/.internal/templates/services/domoticz/build.js index ee67fd9a7..921f50257 100644 --- a/.internal/templates/services/domoticz/build.js +++ b/.internal/templates/services/domoticz/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'domoticz'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/domoticz/config.js b/.internal/templates/services/domoticz/config.js index e3257d1ee..19e4af412 100644 --- a/.internal/templates/services/domoticz/config.js +++ b/.internal/templates/services/domoticz/config.js @@ -34,7 +34,7 @@ const domoticz = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Domoticz', + displayName: 'Domoticz (untested)', serviceTypeTags: ['wui', 'dashboard', 'home automation', 'iot', 'z-wave'] }; }; diff --git a/.internal/templates/services/domoticz/template.yml b/.internal/templates/services/domoticz/template.yml index 1ec55e016..45be6779a 100644 --- a/.internal/templates/services/domoticz/template.yml +++ b/.internal/templates/services/domoticz/template.yml @@ -7,8 +7,6 @@ domoticz: - "1443:1443" volumes: - ./volumes/domoticz/data:/config - env_file: - - ./services/domoticz/domoticz.env restart: unless-stopped network_mode: bridge environment: diff --git a/.internal/templates/services/dozzle/build.js b/.internal/templates/services/dozzle/build.js index 61e6bab5d..8e3b295b9 100644 --- a/.internal/templates/services/dozzle/build.js +++ b/.internal/templates/services/dozzle/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'dozzle'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/dozzle/config.js b/.internal/templates/services/dozzle/config.js index eab3f2e1d..af6c68bfd 100644 --- a/.internal/templates/services/dozzle/config.js +++ b/.internal/templates/services/dozzle/config.js @@ -34,7 +34,7 @@ const dozzle = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Dozzle', + displayName: 'Dozzle (untested)', serviceTypeTags: ['logs', 'docker', 'container manager', 'wui'] }; }; diff --git a/.internal/templates/services/espruinohub/build.js b/.internal/templates/services/espruinohub/build.js index b9501e6a0..d08001c35 100644 --- a/.internal/templates/services/espruinohub/build.js +++ b/.internal/templates/services/espruinohub/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'espruinohub'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/espruinohub/config.js b/.internal/templates/services/espruinohub/config.js index 25df42fe5..51eebb55f 100644 --- a/.internal/templates/services/espruinohub/config.js +++ b/.internal/templates/services/espruinohub/config.js @@ -31,7 +31,7 @@ const espruinohub = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'EspruinoHub', + displayName: 'EspruinoHub (untested)', serviceTypeTags: ['mqtt', 'ble', 'rpi only'] }; }; diff --git a/.internal/templates/services/gitea/build.js b/.internal/templates/services/gitea/build.js index 56ad28e47..42bf0f2ee 100644 --- a/.internal/templates/services/gitea/build.js +++ b/.internal/templates/services/gitea/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'gitea'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/gitea/config.js b/.internal/templates/services/gitea/config.js index b32b4b73a..019c49a4b 100644 --- a/.internal/templates/services/gitea/config.js +++ b/.internal/templates/services/gitea/config.js @@ -34,7 +34,7 @@ const gitea = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Gitea', + displayName: 'Gitea (untested)', serviceTypeTags: ['wui', 'git'] }; }; diff --git a/.internal/templates/services/grafana/build.js b/.internal/templates/services/grafana/build.js index 5b915e6f7..7c46fcf91 100644 --- a/.internal/templates/services/grafana/build.js +++ b/.internal/templates/services/grafana/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'grafana'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/grafana/config.js b/.internal/templates/services/grafana/config.js index 205343fe0..595b9c7b0 100644 --- a/.internal/templates/services/grafana/config.js +++ b/.internal/templates/services/grafana/config.js @@ -44,7 +44,7 @@ const grafana = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Grafana', + displayName: 'Grafana (untested)', serviceTypeTags: ['aggregator', 'wui', 'graphs', 'dashboard'], iconUri: 'https://grafana.com/static/img/logos/grafana_logo_swirl-events.svg' }; diff --git a/.internal/templates/services/heimdall/build.js b/.internal/templates/services/heimdall/build.js index 2f2e4edea..ea4b11849 100644 --- a/.internal/templates/services/heimdall/build.js +++ b/.internal/templates/services/heimdall/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'heimdall'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/heimdall/config.js b/.internal/templates/services/heimdall/config.js index d0e7c36ae..209b6d7c4 100644 --- a/.internal/templates/services/heimdall/config.js +++ b/.internal/templates/services/heimdall/config.js @@ -8,8 +8,8 @@ const heimdall = () => { serviceName, // Required modifyableEnvironment: [ { - key: 'INFLUXDB_UDP_BIND_ADDRESS', - value: '0.0.0.0:8086' + key: 'TZ', + value: 'Etc/UTC2' } ], volumes: true, @@ -37,7 +37,7 @@ const heimdall = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Heimdall', + displayName: 'Heimdall (untested)', serviceTypeTags: ['wui', 'database manager'] }; }; diff --git a/.internal/templates/services/home_assistant/build.js b/.internal/templates/services/home_assistant/build.js index 039338d02..ac2d5d4f9 100644 --- a/.internal/templates/services/home_assistant/build.js +++ b/.internal/templates/services/home_assistant/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'home_assistant'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/home_assistant/config.js b/.internal/templates/services/home_assistant/config.js index cf816d880..0476e2981 100644 --- a/.internal/templates/services/home_assistant/config.js +++ b/.internal/templates/services/home_assistant/config.js @@ -10,7 +10,7 @@ const home_assistant = () => { "8123:8123": 'http' }, volumes: true, - networks: false, + networks: true, logging: true } }; @@ -34,7 +34,7 @@ const home_assistant = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Home Assistant', + displayName: 'Home Assistant (untested)', serviceTypeTags: ['wui', 'dashboard', 'home automation', 'iot'] }; }; diff --git a/.internal/templates/services/homebridge/build.js b/.internal/templates/services/homebridge/build.js new file mode 100644 index 000000000..44f307747 --- /dev/null +++ b/.internal/templates/services/homebridge/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'homebridge'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/homebridge/config.js b/.internal/templates/services/homebridge/config.js new file mode 100644 index 000000000..361f931d5 --- /dev/null +++ b/.internal/templates/services/homebridge/config.js @@ -0,0 +1,45 @@ +const homebridge = () => { + const retr = {}; + + const serviceName = 'homebridge'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "4040:4040": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: 'https://homebridge.io/', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Home Bridge (untested)', + serviceTypeTags: ['wui', 'iot'] + }; + }; + + return retr; +}; + +module.exports = homebridge; diff --git a/.internal/templates/services/homebridge/template.yml b/.internal/templates/services/homebridge/template.yml new file mode 100644 index 000000000..f0b9a7ab5 --- /dev/null +++ b/.internal/templates/services/homebridge/template.yml @@ -0,0 +1,15 @@ +homebridge: + container_name: homebridge + image: oznu/homebridge:no-avahi-arm32v6 + restart: unless-stopped + environment: + - TZ=Etc/UTC + - PGID=1000 + - PUID=1000 + - HOMEBRIDGE_CONFIG_UI=1 + - HOMEBRIDGE_CONFIG_UI_PORT=%WUIPort% + volumes: + - ./volumes/homebridge:/homebridge + ports: + - "4040:4040" + network_mode: host diff --git a/.internal/templates/services/homer/build.js b/.internal/templates/services/homer/build.js index 28050d425..fb8f386af 100644 --- a/.internal/templates/services/homer/build.js +++ b/.internal/templates/services/homer/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'homer'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/homer/config.js b/.internal/templates/services/homer/config.js index d975ce488..77dde8514 100644 --- a/.internal/templates/services/homer/config.js +++ b/.internal/templates/services/homer/config.js @@ -34,7 +34,7 @@ const homer = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Homer', + displayName: 'Homer (untested)', serviceTypeTags: ['wui', 'dashboard'] }; }; diff --git a/.internal/templates/services/influxdb/build.js b/.internal/templates/services/influxdb/build.js index 0c42af767..f32031bbc 100644 --- a/.internal/templates/services/influxdb/build.js +++ b/.internal/templates/services/influxdb/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'influxdb'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/influxdb/config.js b/.internal/templates/services/influxdb/config.js index 3dda4e2d6..55ce82cdf 100644 --- a/.internal/templates/services/influxdb/config.js +++ b/.internal/templates/services/influxdb/config.js @@ -40,7 +40,7 @@ const influxDb = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'InfluxDB', + displayName: 'InfluxDB (untested)', serviceTypeTags: ['database', 'timeseries', 'sql'] }; }; diff --git a/.internal/templates/services/mariadb/build.js b/.internal/templates/services/mariadb/build.js index 81dff46a4..0a43198f1 100644 --- a/.internal/templates/services/mariadb/build.js +++ b/.internal/templates/services/mariadb/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'mariadb'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/mariadb/config.js b/.internal/templates/services/mariadb/config.js index 98e4b1289..63a934aff 100644 --- a/.internal/templates/services/mariadb/config.js +++ b/.internal/templates/services/mariadb/config.js @@ -53,7 +53,7 @@ const mariadb = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'MariaDB', + displayName: 'MariaDB (untested)', serviceTypeTags: ['database', 'sql'] }; }; diff --git a/.internal/templates/services/mosquitto/build.js b/.internal/templates/services/mosquitto/build.js index 5c88c5c01..94d21a227 100644 --- a/.internal/templates/services/mosquitto/build.js +++ b/.internal/templates/services/mosquitto/build.js @@ -7,6 +7,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'mosquitto'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -20,41 +27,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - const mosquittoConfFilePath = path.join(__dirname, settings.paths.serviceFiles, 'mosquitto.conf'); - zipList.push({ - fullPath: mosquittoConfFilePath, - zipName: '/services/mosquitto/mosquitto.conf' - }); - console.debug(`ServiceBuilder:build() - '${serviceName}' Added '${mosquittoConfFilePath}' to zip`); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service files exist for launch', - multilineComment: null, - code: checkServiceFilesCopied() - }); - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -89,6 +79,48 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + const mosquittoConfFilePath = path.join(__dirname, settings.paths.serviceFiles, 'mosquitto.conf'); + zipList.push({ + fullPath: mosquittoConfFilePath, + zipName: '/services/mosquitto/mosquitto.conf' + }); + console.debug(`ServiceBuilder:build() - '${serviceName}' Added '${mosquittoConfFilePath}' to zip`); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service files exist for launch', + multilineComment: null, + code: checkServiceFilesCopied() + }); + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/mosquitto/config.js b/.internal/templates/services/mosquitto/config.js index c5c52e48e..de0304444 100644 --- a/.internal/templates/services/mosquitto/config.js +++ b/.internal/templates/services/mosquitto/config.js @@ -6,7 +6,9 @@ const mosquitto = () => { retr.getConfigOptions = () => { return { serviceName, // Required - labeledPorts: {}, + labeledPorts: { + "1883:1883": 'mosquitto' + }, volumes: true, networks: true, logging: true @@ -32,7 +34,7 @@ const mosquitto = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Mosquitto', + displayName: 'Mosquitto (untested)', serviceTypeTags: ['mqtt', 'server'] }; }; diff --git a/.internal/templates/services/motioneye/build.js b/.internal/templates/services/motioneye/build.js index 30b108610..9cf645c52 100644 --- a/.internal/templates/services/motioneye/build.js +++ b/.internal/templates/services/motioneye/build.js @@ -6,33 +6,44 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'motioneye'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + const checkVideoDevice = () => { + return ` +if [[ ! -f /dev/video0 ]]; then + echo "MotionEye /dev/video0 doesn't exist. May cause errors on startup." + sleep 2 +fi +`; + }; + + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +78,43 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure MotionEye can see video device', + multilineComment: null, + code: checkVideoDevice() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/motioneye/config.js b/.internal/templates/services/motioneye/config.js index 3c9f4ab8f..c85269b7f 100644 --- a/.internal/templates/services/motioneye/config.js +++ b/.internal/templates/services/motioneye/config.js @@ -8,9 +8,12 @@ const motioneye = () => { serviceName, // Required labeledPorts: { "8765:8765": 'http', - "8081:8081": 'streaming' + "8081:60081": 'streaming1', + "8082:60082": 'streaming2', + "8083:60083": 'streaming3' }, volumes: true, + devices: true, networks: true, logging: true } @@ -35,7 +38,7 @@ const motioneye = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Motion Eye', + displayName: 'Motion Eye (untested)', serviceTypeTags: ['wui', 'physical security', 'video'] }; }; diff --git a/.internal/templates/services/motioneye/template.yml b/.internal/templates/services/motioneye/template.yml index 5d0f80637..e36ae289e 100644 --- a/.internal/templates/services/motioneye/template.yml +++ b/.internal/templates/services/motioneye/template.yml @@ -4,13 +4,15 @@ motioneye: restart: unless-stopped ports: - "8765:8765" - - "8081:8081" + - "8081:60081" + - "8082:60082" + - "8083:60083" volumes: - /etc/localtime:/etc/localtime:ro - ./volumes/motioneye/etc_motioneye:/etc/motioneye - ./volumes/motioneye/var_lib_motioneye:/var/lib/motioneye - #devices: - # - "/dev/video0:/dev/video0" + devices: + - "/dev/video0:/dev/video0" networks: - iotstack_nw logging: diff --git a/.internal/templates/services/nextcloud/build.js b/.internal/templates/services/nextcloud/build.js new file mode 100644 index 000000000..dfa7a685c --- /dev/null +++ b/.internal/templates/services/nextcloud/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'nextcloud'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here TODO: Finish NextCloud + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/nextcloud/config.js b/.internal/templates/services/nextcloud/config.js new file mode 100644 index 000000000..7a30556be --- /dev/null +++ b/.internal/templates/services/nextcloud/config.js @@ -0,0 +1,45 @@ +const nextcloud = () => { + const retr = {}; + + const serviceName = 'nextcloud'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9321:9321": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'NextCloud (untested)', + serviceTypeTags: ['wui'] + }; + }; + + return retr; +}; + +module.exports = nextcloud; diff --git a/.internal/templates/services/nextcloud/template.yml b/.internal/templates/services/nextcloud/template.yml new file mode 100644 index 000000000..87fcfae07 --- /dev/null +++ b/.internal/templates/services/nextcloud/template.yml @@ -0,0 +1,35 @@ +nextcloud: + image: nextcloud + container_name: nextcloud + ports: + - "9321:80" + volumes: + - ./volumes/nextcloud/html:/var/www/html:rw + restart: unless-stopped + depends_on: + - nextcloud_db + links: + - nextcloud_db + networks: + - iotstack_nw + - nextcloud_internal + environment: + - MYSQL_HOST=nextcloud_db + - MYSQL_PASSWORD=%randomMySqlPassword% + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + +nextcloud_db: + image: linuxserver/mariadb + container_name: nextcloud_db + volumes: + - ./volumes/nextcloud/db:/var/lib/mysql + environment: + - MYSQL_ROOT_PASSWORD=%randomPassword% + - MYSQL_PASSWORD=%randomMySqlPassword% + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + restart: unless-stopped + networks: + - nextcloud_internal + diff --git a/.internal/templates/services/nodered/build.js b/.internal/templates/services/nodered/build.js index cefcd2618..8bd5da851 100644 --- a/.internal/templates/services/nodered/build.js +++ b/.internal/templates/services/nodered/build.js @@ -10,62 +10,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'nodered'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, - fileTimePrefix, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - const addonsList = buildOptions?.services?.nodered?.addons ?? []; - const noderedDockerfileTemplate = path.join(__dirname, settings.paths.buildFiles, 'Dockerfile.template'); - const noderedDockerfileCommandTemplate = require(path.join(__dirname, settings.paths.buildFiles, 'addons.json')); - const tempDockerfileName = `${fileTimePrefix}_Dockerfile.template`; - - const templateData = fs.readFileSync(noderedDockerfileTemplate, { encoding: 'utf8', flag: 'r' }); - let addonDockerCommandOutput = noderedDockerfileCommandTemplate.data.dockerFileInstallCommand; - - if (addonsList.length > 0) { - addonsList.forEach((addon) => { - addonDockerCommandOutput += `${addon} ` - }); - } else { - addonDockerCommandOutput = ''; - } - - const outputDockerFile = byName(templateData, { - 'npmInstallModulesList': addonDockerCommandOutput - }); - - const tempBuildFile = path.join(tmpPath, tempDockerfileName); - - fs.writeFileSync(tempBuildFile, outputDockerFile); - - zipList.push({ - fullPath: tempBuildFile, - zipName: '/services/nodered/Dockerfile' - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -112,6 +85,65 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + fileTimePrefix, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + const addonsList = buildOptions?.services?.nodered?.addons ?? []; + const noderedDockerfileTemplate = path.join(__dirname, settings.paths.buildFiles, 'Dockerfile.template'); + const noderedDockerfileCommandTemplate = require(path.join(__dirname, settings.paths.buildFiles, 'addons.json')); + const tempDockerfileName = `${fileTimePrefix}_Dockerfile.template`; + + const templateData = fs.readFileSync(noderedDockerfileTemplate, { encoding: 'utf8', flag: 'r' }); + let addonDockerCommandOutput = noderedDockerfileCommandTemplate.data.dockerFileInstallCommand; + + if (addonsList.length > 0) { + addonsList.forEach((addon) => { + addonDockerCommandOutput += `${addon} ` + }); + } else { + addonDockerCommandOutput = ''; + } + + const outputDockerFile = byName(templateData, { + 'npmInstallModulesList': addonDockerCommandOutput + }); + + const tempBuildFile = path.join(tmpPath, tempDockerfileName); + + fs.writeFileSync(tempBuildFile, outputDockerFile); + + zipList.push({ + fullPath: tempBuildFile, + zipName: '/services/nodered/Dockerfile' + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/nodered/config.js b/.internal/templates/services/nodered/config.js index 982072153..4df0c1d2a 100644 --- a/.internal/templates/services/nodered/config.js +++ b/.internal/templates/services/nodered/config.js @@ -11,6 +11,7 @@ const nodered = () => { }, volumes: true, networks: true, + nodered_npmSelection: true, logging: true } }; @@ -34,7 +35,7 @@ const nodered = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'NodeRed', + displayName: 'NodeRed (untested)', serviceTypeTags: ['wui', 'dashboard', 'low code', 'graphs', 'aggregator', 'iot', 'server'] }; }; diff --git a/.internal/templates/services/openhab/build.js b/.internal/templates/services/openhab/build.js index 0f67b61da..afc41036e 100644 --- a/.internal/templates/services/openhab/build.js +++ b/.internal/templates/services/openhab/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'adminer'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/openhab/config.js b/.internal/templates/services/openhab/config.js index 6b56fe605..8ec785b7b 100644 --- a/.internal/templates/services/openhab/config.js +++ b/.internal/templates/services/openhab/config.js @@ -48,7 +48,7 @@ const adminer = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Adminer', + displayName: 'Open Hab (untested)', serviceTypeTags: ['wui', 'dashboard', 'home automation'] }; }; diff --git a/.internal/templates/services/pihole/build.js b/.internal/templates/services/pihole/build.js index 75eebb93c..13370663e 100644 --- a/.internal/templates/services/pihole/build.js +++ b/.internal/templates/services/pihole/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'pihole'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/pihole/config.js b/.internal/templates/services/pihole/config.js index 4fbaaf89c..42c1c2eb7 100644 --- a/.internal/templates/services/pihole/config.js +++ b/.internal/templates/services/pihole/config.js @@ -56,7 +56,7 @@ const pihole = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'PiHole', + displayName: 'PiHole (untested)', serviceTypeTags: ['wui', 'dns', 'dashboard'] }; }; diff --git a/.internal/templates/services/plex/build.js b/.internal/templates/services/plex/build.js index 5a74cea9d..2a0caca66 100644 --- a/.internal/templates/services/plex/build.js +++ b/.internal/templates/services/plex/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'plex'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -30,43 +37,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -101,6 +89,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/plex/config.js b/.internal/templates/services/plex/config.js index 75f037929..6c11b823b 100644 --- a/.internal/templates/services/plex/config.js +++ b/.internal/templates/services/plex/config.js @@ -40,8 +40,8 @@ const plex = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Plex', - serviceTypeTags: ['wui', 'database manager'] + displayName: 'Plex (untested)', + serviceTypeTags: ['wui', 'video', 'media'] }; }; diff --git a/.internal/templates/services/portainer/build.js b/.internal/templates/services/portainer/build.js index dee901df6..bfb837b1a 100644 --- a/.internal/templates/services/portainer/build.js +++ b/.internal/templates/services/portainer/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'portainer'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -72,6 +74,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/portainer/config.js b/.internal/templates/services/portainer/config.js index ee1d48cc5..033c3fb2e 100644 --- a/.internal/templates/services/portainer/config.js +++ b/.internal/templates/services/portainer/config.js @@ -34,7 +34,7 @@ const portainer = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Portainer', + displayName: 'Portainer (untested)', serviceTypeTags: ['container manager', 'wui', 'deprecated', 'dashboard'] }; }; diff --git a/.internal/templates/services/portainer_agent/build.js b/.internal/templates/services/portainer_agent/build.js index 2faf2b6f0..97b269c65 100644 --- a/.internal/templates/services/portainer_agent/build.js +++ b/.internal/templates/services/portainer_agent/build.js @@ -6,33 +6,35 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'portainer_agent'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); // Code here - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -67,6 +69,36 @@ const ServiceBuilder = ({ }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/portainer_agent/config.js b/.internal/templates/services/portainer_agent/config.js index 2b1b33354..3997e06b1 100644 --- a/.internal/templates/services/portainer_agent/config.js +++ b/.internal/templates/services/portainer_agent/config.js @@ -32,7 +32,7 @@ const portainer_agent = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Portainer Agent', + displayName: 'Portainer Agent (untested)', serviceTypeTags: ['container manager', 'docker'] }; }; diff --git a/.internal/templates/services/portainer_ce/build.js b/.internal/templates/services/portainer_ce/build.js index ad71c817c..7c8306295 100644 --- a/.internal/templates/services/portainer_ce/build.js +++ b/.internal/templates/services/portainer_ce/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'portainer_ce'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/portainer_ce/config.js b/.internal/templates/services/portainer_ce/config.js index 063d1e182..7adc34107 100644 --- a/.internal/templates/services/portainer_ce/config.js +++ b/.internal/templates/services/portainer_ce/config.js @@ -34,7 +34,7 @@ const portainer_ce = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Portainer-CE', + displayName: 'Portainer-CE (untested)', serviceTypeTags: ['wui', 'container manager', 'docker'] }; }; diff --git a/.internal/templates/services/postgres/build.js b/.internal/templates/services/postgres/build.js index 005744634..aa3aeba48 100644 --- a/.internal/templates/services/postgres/build.js +++ b/.internal/templates/services/postgres/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'postgres'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/postgres/config.js b/.internal/templates/services/postgres/config.js index 098a86289..2355c6e05 100644 --- a/.internal/templates/services/postgres/config.js +++ b/.internal/templates/services/postgres/config.js @@ -45,7 +45,7 @@ const postgres = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Postgres', + displayName: 'Postgres (untested)', serviceTypeTags: ['database'] }; }; diff --git a/.internal/templates/services/prometheus/build.js b/.internal/templates/services/prometheus/build.js new file mode 100644 index 000000000..ca7ec455b --- /dev/null +++ b/.internal/templates/services/prometheus/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'prometheus'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/prometheus/buildFiles/build.sh b/.internal/templates/services/prometheus/buildFiles/build.sh new file mode 100644 index 000000000..44841aee2 --- /dev/null +++ b/.internal/templates/services/prometheus/buildFiles/build.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +DOCKER_COMPOSE_PATH=./.tmp/docker-compose.tmp.yml +TEMPLATE_PATH=./.templates/prometheus + +# TODO: Prometheus needs to have a build.py file created before this bash script is executed. + +if [[ ! -f $DOCKER_COMPOSE_PATH ]]; then + echo "[Prometheus] Warning: $DOCKER_COMPOSE_PATH does not exist." +fi + +# Configure Prometheus Add-ons + +option_selection=$(whiptail --title "Select Prometheus Options" --checklist --separate-output \ + "Use the [SPACEBAR] to select add-on containers from the list below." 20 78 12 -- \ + "node-exporter" "monitor this computer " "ON" \ + "cadvisor-arm" "monitor full container stack " "ON" \ + 3>&1 1>&2 2>&3) + +mapfile -t selected_options <<< "$option_selection" + +# (cat $TEMPLATE_PATH/service.yml; echo) >> $DOCKER_COMPOSE_PATH + +for option in "${selected_options[@]}"; do + # insert add-on service + (cat $TEMPLATE_PATH/service_${option}.yml; echo) >> $DOCKER_COMPOSE_PATH + + # include add-on in depends_on + sed -i.bak -e "/depends_on:/a\\ + \\ \\ \\ \\ \\ \\ - ${option}" $DOCKER_COMPOSE_PATH +done + +# clean up +rm ${DOCKER_COMPOSE_PATH}.bak + +# TODO: need build.py \ No newline at end of file diff --git a/.internal/templates/services/prometheus/buildFiles/service_cadvisor-arm.yml b/.internal/templates/services/prometheus/buildFiles/service_cadvisor-arm.yml new file mode 100644 index 000000000..a2ecefdaf --- /dev/null +++ b/.internal/templates/services/prometheus/buildFiles/service_cadvisor-arm.yml @@ -0,0 +1,13 @@ + cadvisor-arm: + container_name: cadvisor + image: budry/cadvisor-arm:latest + restart: unless-stopped + user: "0" + privileged: true + ports: + - 8080:8080 + volumes: + - /:/rootfs:ro + - /var/run:/var/run:rw + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro diff --git a/.internal/templates/services/prometheus/buildFiles/service_node-exporter.yml b/.internal/templates/services/prometheus/buildFiles/service_node-exporter.yml new file mode 100644 index 000000000..8c007ebed --- /dev/null +++ b/.internal/templates/services/prometheus/buildFiles/service_node-exporter.yml @@ -0,0 +1,6 @@ + node-exporter: + image: prom/node-exporter:latest + container_name: node_exporter + restart: unless-stopped + expose: + - 9100 diff --git a/.internal/templates/services/prometheus/config.js b/.internal/templates/services/prometheus/config.js new file mode 100644 index 000000000..4d73f4275 --- /dev/null +++ b/.internal/templates/services/prometheus/config.js @@ -0,0 +1,45 @@ +const prometheus = () => { + const retr = {}; + + const serviceName = 'prometheus'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "9080:8080": 'http' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Prometheus (untested)', + serviceTypeTags: ['wui', 'database manager'] + }; + }; + + return retr; +}; + +module.exports = prometheus; diff --git a/.internal/templates/services/prometheus/serviceFiles/config.yml b/.internal/templates/services/prometheus/serviceFiles/config.yml new file mode 100644 index 000000000..c82004b60 --- /dev/null +++ b/.internal/templates/services/prometheus/serviceFiles/config.yml @@ -0,0 +1,10 @@ +global: + scrape_interval: 10s + evaluation_interval: 10s + +# scrape_configs: +# - job_name: iotstack +# static_configs: +# - targets: +# - cadvisor:8080 +# - node-exporter:9100 diff --git a/.internal/templates/services/prometheus/template.yml b/.internal/templates/services/prometheus/template.yml new file mode 100644 index 000000000..fc8e65789 --- /dev/null +++ b/.internal/templates/services/prometheus/template.yml @@ -0,0 +1,13 @@ +prometheus: + container_name: prometheus + image: prom/prometheus:latest + restart: unless-stopped + user: "0" + ports: + - "9090:9090" + volumes: + - ./services/prometheus/config.yml:/etc/prometheus/config.yml + - ./volumes/prometheus/data:/data + command: + - '--config.file=/etc/prometheus/config.yml' + - '--storage.tsdb.path=/data' diff --git a/.internal/templates/services/qbittorrent/build.js b/.internal/templates/services/qbittorrent/build.js index 0030cecd5..859dbbb0d 100644 --- a/.internal/templates/services/qbittorrent/build.js +++ b/.internal/templates/services/qbittorrent/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'qbittorrent'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -30,43 +37,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -101,6 +89,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/qbittorrent/config.js b/.internal/templates/services/qbittorrent/config.js index 27f811dee..dbbef5f7d 100644 --- a/.internal/templates/services/qbittorrent/config.js +++ b/.internal/templates/services/qbittorrent/config.js @@ -40,7 +40,7 @@ const qbittorrent = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Q Bittorrent', + displayName: 'Q Bittorrent (untested)', serviceTypeTags: ['bittorrent'] }; }; diff --git a/.internal/templates/services/rtl_433/build.js b/.internal/templates/services/rtl_433/build.js new file mode 100644 index 000000000..e10e94548 --- /dev/null +++ b/.internal/templates/services/rtl_433/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'rtl_433'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/rtl_433/buildFiles/Dockerfile b/.internal/templates/services/rtl_433/buildFiles/Dockerfile new file mode 100644 index 000000000..8feebfec0 --- /dev/null +++ b/.internal/templates/services/rtl_433/buildFiles/Dockerfile @@ -0,0 +1,18 @@ +FROM debian:buster-slim + +ENV MQTT_ADDRESS mosquitto +ENV MQTT_PORT 1883 +ENV MQTT_USER "" +ENV MQTT_PASSWORD "" +ENV MQTT_TOPIC RTL_433 + +RUN apt-get update && apt-get install -y git libtool libusb-1.0.0-dev librtlsdr-dev rtl-sdr cmake automake && \ + git clone https://github.com/merbanan/rtl_433.git /tmp/rtl_433 && \ + cd /tmp/rtl_433/ && \ + mkdir build && \ + cd build && \ + cmake ../ && \ + make && \ + make install + +CMD ["sh", "-c", "rtl_433 -F mqtt://${MQTT_ADDRESS}:${MQTT_PORT},events=${MQTT_TOPIC},user=${MQTT_USER},pass=${MQTT_PASSWORD}"] diff --git a/.internal/templates/services/rtl_433/config.js b/.internal/templates/services/rtl_433/config.js new file mode 100644 index 000000000..34e1fe2e9 --- /dev/null +++ b/.internal/templates/services/rtl_433/config.js @@ -0,0 +1,42 @@ +const rtl_433 = () => { + const retr = {}; + + const serviceName = 'rtl_433'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'RTL 433 (untested)', + serviceTypeTags: ['wui', 'database manager'] + }; + }; + + return retr; +}; + +module.exports = rtl_433; diff --git a/.internal/templates/services/rtl_433/template.yml b/.internal/templates/services/rtl_433/template.yml new file mode 100644 index 000000000..ef53d146e --- /dev/null +++ b/.internal/templates/services/rtl_433/template.yml @@ -0,0 +1,13 @@ +rtl_433: + container_name: rtl_433 + build: ./services/rtl_433/. + depends_on: + - mosquitto + environment: + - TZ=Etc/UTC + - MQTT_ADDRESS=mosquitto + - MQTT_PORT=1883 + - MQTT_TOPIC=RTL_433 + devices: + - /dev/bus/usb + restart: unless-stopped diff --git a/.internal/templates/services/tasmoadmin/build.js b/.internal/templates/services/tasmoadmin/build.js index 4653bf72f..1fa9a9887 100644 --- a/.internal/templates/services/tasmoadmin/build.js +++ b/.internal/templates/services/tasmoadmin/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'tasmoadmin'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/tasmoadmin/config.js b/.internal/templates/services/tasmoadmin/config.js index 00fcc219e..b1d641173 100644 --- a/.internal/templates/services/tasmoadmin/config.js +++ b/.internal/templates/services/tasmoadmin/config.js @@ -34,7 +34,7 @@ const tasmoadmin = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'TasmoAdmin', + displayName: 'TasmoAdmin (untested)', serviceTypeTags: ['wui', 'iot'] }; }; diff --git a/.internal/templates/services/telegraf/build.js b/.internal/templates/services/telegraf/build.js new file mode 100644 index 000000000..364f27b0d --- /dev/null +++ b/.internal/templates/services/telegraf/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'telegraf'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/telegraf/config.js b/.internal/templates/services/telegraf/config.js new file mode 100644 index 000000000..24f1bee4b --- /dev/null +++ b/.internal/templates/services/telegraf/config.js @@ -0,0 +1,42 @@ +const telegraf = () => { + const retr = {}; + + const serviceName = 'telegraf'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + volumes: true, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Telegraf (untested)', + serviceTypeTags: ['iot'] + }; + }; + + return retr; +}; + +module.exports = telegraf; diff --git a/.internal/templates/services/telegraf/serviceFiles/telegraf.conf b/.internal/templates/services/telegraf/serviceFiles/telegraf.conf new file mode 100644 index 000000000..f377c5a3f --- /dev/null +++ b/.internal/templates/services/telegraf/serviceFiles/telegraf.conf @@ -0,0 +1,237 @@ +# Telegraf Configuration +# +# Telegraf is entirely plugin driven. All metrics are gathered from the +# declared inputs, and sent to the declared outputs. +# +# Plugins must be declared in here to be active. +# To deactivate a plugin, comment out the name and any variables. +# +# Use 'telegraf -config telegraf.conf -test' to see what metrics a config +# file would generate. +# +# Environment variables can be used anywhere in this config file, simply surround +# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"), +# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR}) + + +# Global tags can be specified here in key="value" format. +[global_tags] + # dc = "us-east-1" # will tag all metrics with dc=us-east-1 + # rack = "1a" + ## Environment variables can be used as tags, and throughout the config file + # user = "$USER" + + +# Configuration for telegraf agent +[agent] + ## Default data collection interval for all inputs + interval = "10s" + ## Rounds collection interval to 'interval' + ## ie, if interval="10s" then always collect on :00, :10, :20, etc. + round_interval = true + + ## Telegraf will send metrics to outputs in batches of at most + ## metric_batch_size metrics. + ## This controls the size of writes that Telegraf sends to output plugins. + metric_batch_size = 1000 + + ## Maximum number of unwritten metrics per output. + metric_buffer_limit = 10000 + + ## Collection jitter is used to jitter the collection by a random amount. + ## Each plugin will sleep for a random time within jitter before collecting. + ## This can be used to avoid many plugins querying things like sysfs at the + ## same time, which can have a measurable effect on the system. + collection_jitter = "0s" + + ## Default flushing interval for all outputs. Maximum flush_interval will be + ## flush_interval + flush_jitter + flush_interval = "10s" + ## Jitter the flush interval by a random amount. This is primarily to avoid + ## large write spikes for users running a large number of telegraf instances. + ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s + flush_jitter = "0s" + + ## By default or when set to "0s", precision will be set to the same + ## timestamp order as the collection interval, with the maximum being 1s. + ## ie, when interval = "10s", precision will be "1s" + ## when interval = "250ms", precision will be "1ms" + ## Precision will NOT be used for service inputs. It is up to each individual + ## service input to set the timestamp at the appropriate precision. + ## Valid time units are "ns", "us" (or "µs"), "ms", "s". + precision = "" + + ## Log at debug level. + # debug = false + ## Log only error level messages. + # quiet = false + + ## Log file name, the empty string means to log to stderr. + # logfile = "" + + ## The logfile will be rotated after the time interval specified. When set + ## to 0 no time based rotation is performed. Logs are rotated only when + ## written to, if there is no log activity rotation may be delayed. + # logfile_rotation_interval = "0d" + + ## The logfile will be rotated when it becomes larger than the specified + ## size. When set to 0 no size based rotation is performed. + # logfile_rotation_max_size = "0MB" + + ## Maximum number of rotated archives to keep, any older logs are deleted. + ## If set to -1, no archives are removed. + # logfile_rotation_max_archives = 5 + + ## Override default hostname, if empty use os.Hostname() + hostname = "" + ## If set to true, do no set the "host" tag in the telegraf agent. + omit_hostname = false + + +############################################################################### +# OUTPUT PLUGINS # +############################################################################### + + +# Configuration for sending metrics to InfluxDB +[[outputs.influxdb]] + # The full HTTP or UDP URL for your InfluxDB instance. + # + # Multiple URLs can be specified for a single cluster, only ONE of the + # urls will be written to each interval. + # urls = ["unix:///var/run/influxdb.sock"] + # urls = ["udp://influxdb:8089"] + urls = ["http://influxdb:8086"] + + # The target database for metrics; will be created as needed. + # For UDP url endpoint database needs to be configured on server side. + database = "telegraf" + + # The value of this tag will be used to determine the database. If this + # tag is not set the 'database' option is used as the default. + database_tag = "" + + # If true, the database tag will not be added to the metric. + exclude_database_tag = false + + # If true, no CREATE DATABASE queries will be sent. Set to true when using + # Telegraf with a user without permissions to create databases or when the + # database already exists. + skip_database_creation = false + + # Name of existing retention policy to write to. Empty string writes to + # the default retention policy. Only takes effect when using HTTP. + retention_policy = "" + + # Write consistency (clusters only), can be: "any", "one", "quorum", "all". + # Only takes effect when using HTTP. + write_consistency = "any" + + # Timeout for HTTP messages. + timeout = "5s" + + # HTTP Basic Auth + username = "telegraf" + password = "metricsmetricsmetricsmetrics" + + # HTTP User-Agent + user_agent = "telegraf" + + # UDP payload size is the maximum packet size to send. + udp_payload = "512B" + + ## Optional TLS Config for use on HTTP connections. + # tls_ca = "/etc/telegraf/ca.pem" + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" + ## Use TLS but skip chain & host verification + # insecure_skip_verify = false + # + ## HTTP Proxy override, if unset values the standard proxy environment + ## variables are consulted to determine which proxy, if any, should be used. + # http_proxy = "http://corporate.proxy:3128" + + ## Additional HTTP headers + # http_headers = {"X-Special-Header" = "Special-Value"} + + ## HTTP Content-Encoding for write request body, can be set to "gzip" to + ## compress body or "identity" to apply no encoding. + # content_encoding = "identity" + + ## When true, Telegraf will output unsigned integers as unsigned values, + ## i.e.: "42u". You will need a version of InfluxDB supporting unsigned + ## integer values. Enabling this option will result in field type errors if + ## existing data has been written. + # influx_uint_support = false + + # Read metrics from MQTT topic(s) + [[inputs.mqtt_consumer]] + ## MQTT broker URLs to be used. The format should be scheme://host:port, + ## schema can be tcp, ssl, or ws. + servers = ["tcp://mosquitto:1883"] + + ## Topics that will be subscribed to. + topics = [ + "telegraf/host01/cpu", + "telegraf/+/mem", + "sensors/#", + ] + + ## The message topic will be stored in a tag specified by this value. If set + ## to the empty string no topic tag will be created. + # topic_tag = "topic" + + ## QoS policy for messages + ## 0 = at most once + ## 1 = at least once + ## 2 = exactly once + ## + ## When using a QoS of 1 or 2, you should enable persistent_session to allow + ## resuming unacknowledged messages. + # qos = 0 + + ## Connection timeout for initial connection in seconds + # connection_timeout = "30s" + + ## Maximum messages to read from the broker that have not been written by an + ## output. For best throughput set based on the number of metrics within + ## each message and the size of the output's metric_batch_size. + ## + ## For example, if each message from the queue contains 10 metrics and the + ## output metric_batch_size is 1000, setting this to 100 will ensure that a + ## full batch is collected and the write is triggered immediately without + ## waiting until the next flush_interval. + max_undelivered_messages = 1000 + + ## Persistent session disables clearing of the client session on connection. + ## In order for this option to work you must also set client_id to identity + ## the client. To receive messages that arrived while the client is offline, + ## also set the qos option to 1 or 2 and don't forget to also set the QoS when + ## publishing. + # persistent_session = false + + ## If unset, a random client ID will be generated. + # client_id = "" + + ## Username and password to connect MQTT server. + # username = "telegraf" + # password = "metricsmetricsmetricsmetrics" + + ## Optional TLS Config + # tls_ca = "/etc/telegraf/ca.pem" + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" + ## Use TLS but skip chain & host verification + # insecure_skip_verify = false + + ## Data format to consume. + ## Each data format has its own unique set of configuration options, read + ## more about them here: + ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md + + #data_format = "influx" + data_format = "json" + #tag_keys = [ + # "temperature", + # "humidity" + #] \ No newline at end of file diff --git a/.internal/templates/services/telegraf/template.yml b/.internal/templates/services/telegraf/template.yml new file mode 100644 index 000000000..f16f8e52a --- /dev/null +++ b/.internal/templates/services/telegraf/template.yml @@ -0,0 +1,11 @@ +telegraf: + container_name: telegraf + image: telegraf + restart: unless-stopped + volumes: + - ./services/telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro + depends_on: + - influxdb + - mosquitto + networks: + - iotstack_nw diff --git a/.internal/templates/services/timescaledb/build.js b/.internal/templates/services/timescaledb/build.js index 7d39824a8..4a7b88256 100644 --- a/.internal/templates/services/timescaledb/build.js +++ b/.internal/templates/services/timescaledb/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'timescaledb'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/timescaledb/config.js b/.internal/templates/services/timescaledb/config.js index d195cc8ed..acec65579 100644 --- a/.internal/templates/services/timescaledb/config.js +++ b/.internal/templates/services/timescaledb/config.js @@ -45,7 +45,7 @@ const timescaledb = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Timescale DB', + displayName: 'Timescale DB (untested)', serviceTypeTags: ['timeseries', 'database'] }; }; diff --git a/.internal/templates/services/transmission/build.js b/.internal/templates/services/transmission/build.js index 09504313f..808e8abbd 100644 --- a/.internal/templates/services/transmission/build.js +++ b/.internal/templates/services/transmission/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'transmission'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -35,43 +42,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -106,6 +94,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/transmission/config.js b/.internal/templates/services/transmission/config.js index 699551166..8b2b72349 100644 --- a/.internal/templates/services/transmission/config.js +++ b/.internal/templates/services/transmission/config.js @@ -40,7 +40,7 @@ const transmission = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'Transmission', + displayName: 'Transmission (untested)', serviceTypeTags: ['bittorrent'] }; }; diff --git a/.internal/templates/services/web_things/build.js b/.internal/templates/services/web_things/build.js new file mode 100644 index 000000000..142d34c5e --- /dev/null +++ b/.internal/templates/services/web_things/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'web_things'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/web_things/config.js b/.internal/templates/services/web_things/config.js new file mode 100644 index 000000000..694f4f608 --- /dev/null +++ b/.internal/templates/services/web_things/config.js @@ -0,0 +1,46 @@ +const web_things = () => { + const retr = {}; + + const serviceName = 'web_things'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "4060:4060": 'http', + "4061:4061": 'other' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Web Things (untested)', + serviceTypeTags: ['wui', 'iot'] + }; + }; + + return retr; +}; + +module.exports = web_things; diff --git a/.internal/templates/services/web_things/template.yml b/.internal/templates/services/web_things/template.yml new file mode 100644 index 000000000..c33ce5e50 --- /dev/null +++ b/.internal/templates/services/web_things/template.yml @@ -0,0 +1,9 @@ +webthingsio_gateway: + image: webthingsio/gateway:latest + container_name: webthingsio_gateway + network_mode: host + ports: + - "4060:4060" + - "4061:4061" + volumes: + - ./volumes/webthingsio_gateway/share:/home/node/.mozilla-iot diff --git a/.internal/templates/services/wireguard/build.js b/.internal/templates/services/wireguard/build.js new file mode 100644 index 000000000..7ad035dcf --- /dev/null +++ b/.internal/templates/services/wireguard/build.js @@ -0,0 +1,105 @@ +const ServiceBuilder = ({ + settings, + version, + logger +}) => { + const retr = {}; + const serviceName = 'wireguard'; + + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + + retr.init = () => { + logger.debug(`ServiceBuilder:init() - '${serviceName}'`); + }; + + retr.compile = ({ + outputTemplateJson, + buildOptions, + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + return reject({ + component: `ServiceBuilder::compile() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.issues = ({ + outputTemplateJson, + buildOptions, + tmpPath + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:issues() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:issues() - '${serviceName}' completed`); + return resolve([]); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::issues() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + + return retr; +} + +module.exports = ServiceBuilder; diff --git a/.internal/templates/services/wireguard/config.js b/.internal/templates/services/wireguard/config.js new file mode 100644 index 000000000..d465d6ba2 --- /dev/null +++ b/.internal/templates/services/wireguard/config.js @@ -0,0 +1,45 @@ +const wireguard = () => { + const retr = {}; + + const serviceName = 'wireguard'; + + retr.getConfigOptions = () => { + return { + serviceName, // Required + labeledPorts: { + "51820:51820": 'vpn' + }, + volumes: false, + networks: false, + logging: true + } + }; + + retr.getHelp = () => { + return { + serviceName, // Required + website: '', // Website of service + rawMarkdownRemote: '', // Usually links to github raw help pages. + rawMarkdownLocal: '', // Relative path to docs locally + onlineRendered: '' // Usually links to the github page for this service. + }; + }; + + retr.getCommands = () => { + return { + commands: {} // Key/value pair of helper commands user can run locally + }; + }; + + retr.getMeta = () => { + return { + serviceName, // Required + displayName: 'Wire Guard (untested)', + serviceTypeTags: ['vpn'] + }; + }; + + return retr; +}; + +module.exports = wireguard; diff --git a/.internal/templates/services/wireguard/serviceFiles/wg0.conf b/.internal/templates/services/wireguard/serviceFiles/wg0.conf new file mode 100644 index 000000000..e69de29bb diff --git a/.internal/templates/services/wireguard/template.yml b/.internal/templates/services/wireguard/template.yml new file mode 100644 index 000000000..3e1d13397 --- /dev/null +++ b/.internal/templates/services/wireguard/template.yml @@ -0,0 +1,23 @@ +wireguard: + image: linuxserver/wireguard + container_name: wireguard + cap_add: + - NET_ADMIN + - SYS_MODULE + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - SERVERURL=.duckdns.org + - SERVERPORT=51820 + - PEERS=1 + - PEERDNS=auto + - INTERNAL_SUBNET=100.64.0.0/24 + volumes: + - ./services/wireguard/config:/config + - /lib/modules:/lib/modules + ports: + - "51820:51820/udp" + sysctls: + - net.ipv4.conf.all.src_valid_mark=1 + restart: unless-stopped diff --git a/.internal/templates/services/wireguard/tmp/build.sh b/.internal/templates/services/wireguard/tmp/build.sh new file mode 100644 index 000000000..83b63600d --- /dev/null +++ b/.internal/templates/services/wireguard/tmp/build.sh @@ -0,0 +1,11 @@ +#1/bin/bash + +WG_CONF_TEMPLATE_PATH=./.templates/wireguard/wg0.conf +WG_CONF_DEST_PATH=./services/wireguard/config + +if [[ ! -f $WG_CONF_TEMPLATE_PATH ]]; then + echo "[Wireguard] Warning: $WG_CONF_TEMPLATE_PATH does not exist." + else + [ -d $WG_CONF_DEST_PATH ] || mkdir -p $WG_CONF_DEST_PATH + cp -r $WG_CONF_TEMPLATE_PATH $WG_CONF_DEST_PATH +fi \ No newline at end of file diff --git a/.internal/templates/services/zigbee2mqtt/build.js b/.internal/templates/services/zigbee2mqtt/build.js index 754a570aa..7c927a31f 100644 --- a/.internal/templates/services/zigbee2mqtt/build.js +++ b/.internal/templates/services/zigbee2mqtt/build.js @@ -6,6 +6,13 @@ const ServiceBuilder = ({ const retr = {}; const serviceName = 'zigbee2mqtt'; + /* + Order: + 1. compile() - merges build options into the final JSON output. + 2. issues() - runs checks on the compile()'ed JSON, and can also test for errors. + 3. build() - sets up scripts and files. + */ + retr.init = () => { logger.debug(`ServiceBuilder:init() - '${serviceName}'`); }; @@ -25,43 +32,24 @@ fi `; }; - retr.build = ({ + retr.compile = ({ outputTemplateJson, buildOptions, - tmpPath, - zipList, - prebuildScripts, - postbuildScripts }) => { return new Promise((resolve, reject) => { try { - console.info(`ServiceBuilder:build() - '${serviceName}' started`); - - prebuildScripts.push({ - serviceName, - comment: 'Create required service directory exists for first launch', - multilineComment: null, - code: createVolumesDirectory() - }); - - postbuildScripts.push({ - serviceName, - comment: 'Ensure required service directory exists for launch', - multilineComment: null, - code: checkVolumesDirectory() - }); - - console.info(`ServiceBuilder:build() - '${serviceName}' completed`); - return resolve(); + console.info(`ServiceBuilder:compile() - '${serviceName}' started`); + // Code here + console.info(`ServiceBuilder:compile() - '${serviceName}' completed`); + return resolve({ type: 'service' }); } catch (err) { console.error(err); console.trace(); console.debug("\nParams:"); console.debug({ outputTemplateJson }); console.debug({ buildOptions }); - console.debug({ tmpPath }); return reject({ - component: `ServiceBuilder::build() - '${serviceName}'`, + component: `ServiceBuilder::compile() - '${serviceName}'`, message: 'Unhandled error occured', error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) }); @@ -96,6 +84,50 @@ fi }); }; + retr.build = ({ + outputTemplateJson, + buildOptions, + tmpPath, + zipList, + prebuildScripts, + postbuildScripts + }) => { + return new Promise((resolve, reject) => { + try { + console.info(`ServiceBuilder:build() - '${serviceName}' started`); + + prebuildScripts.push({ + serviceName, + comment: 'Create required service directory exists for first launch', + multilineComment: null, + code: createVolumesDirectory() + }); + + postbuildScripts.push({ + serviceName, + comment: 'Ensure required service directory exists for launch', + multilineComment: null, + code: checkVolumesDirectory() + }); + + console.info(`ServiceBuilder:build() - '${serviceName}' completed`); + return resolve({ type: 'service' }); + } catch (err) { + console.error(err); + console.trace(); + console.debug("\nParams:"); + console.debug({ outputTemplateJson }); + console.debug({ buildOptions }); + console.debug({ tmpPath }); + return reject({ + component: `ServiceBuilder::build() - '${serviceName}'`, + message: 'Unhandled error occured', + error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) + }); + } + }); + }; + return retr; } diff --git a/.internal/templates/services/zigbee2mqtt/config.js b/.internal/templates/services/zigbee2mqtt/config.js index 6fdc1a536..bf0593041 100644 --- a/.internal/templates/services/zigbee2mqtt/config.js +++ b/.internal/templates/services/zigbee2mqtt/config.js @@ -35,7 +35,7 @@ const zigbee2mqtt = () => { retr.getMeta = () => { return { serviceName, // Required - displayName: 'zigbee2mqtt', + displayName: 'zigbee2mqtt (untested)', serviceTypeTags: ['zigbee', 'mqtt'] }; }; diff --git a/.internal/wui/.eslintcache b/.internal/wui/.eslintcache index 23e525070..e558af4eb 100644 --- a/.internal/wui/.eslintcache +++ b/.internal/wui/.eslintcache @@ -1 +1 @@ -[{"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/index.js":"1","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/App.js":"2","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/index.js":"3","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/router.jsx":"4","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/counter.js":"5","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js":"6","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js":"7","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js":"8","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js":"9","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js":"10","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js":"11","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js":"12","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js":"13","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js":"14","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js":"15","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js":"16","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js":"17","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js":"18","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/constants.js":"19","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js":"20","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js":"21","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js":"22","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js":"23","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js":"24","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js":"25","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js":"26","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getScript.action.js":"27","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js":"28","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js":"29","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js":"30","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/notFound/index.js":"31","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js":"32","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx":"33","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx":"34","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx":"35","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/help/index.jsx":"36","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/builds.js":"37","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/templates.js":"38","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/configs.js":"39","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js":"40","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/config.js":"41","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx":"42","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx":"43","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx":"44","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js":"45","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx":"46","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx":"47","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx":"48","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js":"49","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx":"50","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx":"51","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx":"52","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx":"53","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/parsers.js":"54"},{"size":353,"mtime":1606908594887,"results":"55","hashOfConfig":"56"},{"size":789,"mtime":1607430281547,"results":"57","hashOfConfig":"56"},{"size":1612,"mtime":1610356071552,"results":"58","hashOfConfig":"56"},{"size":1231,"mtime":1610350276543,"results":"59","hashOfConfig":"56"},{"size":1551,"mtime":1606908622214,"results":"60","hashOfConfig":"56"},{"size":962,"mtime":1610356100446,"results":"61","hashOfConfig":"56"},{"size":972,"mtime":1610350671817,"results":"62","hashOfConfig":"56"},{"size":972,"mtime":1610352205750,"results":"63","hashOfConfig":"56"},{"size":1105,"mtime":1607294167538,"results":"64","hashOfConfig":"56"},{"size":1878,"mtime":1607294201436,"results":"65","hashOfConfig":"56"},{"size":894,"mtime":1607816383799,"results":"66","hashOfConfig":"56"},{"size":1922,"mtime":1609913154250,"results":"67","hashOfConfig":"56"},{"size":947,"mtime":1607430599186,"results":"68","hashOfConfig":"56"},{"size":1079,"mtime":1607529487594,"results":"69","hashOfConfig":"56"},{"size":1714,"mtime":1608802587649,"results":"70","hashOfConfig":"56"},{"size":902,"mtime":1608450868778,"results":"71","hashOfConfig":"56"},{"size":607,"mtime":1607109560543,"results":"72","hashOfConfig":"56"},{"size":711,"mtime":1607260096944,"results":"73","hashOfConfig":"56"},{"size":160,"mtime":1607109631094,"results":"74","hashOfConfig":"56"},{"size":340,"mtime":1610354130554,"results":"75","hashOfConfig":"56"},{"size":369,"mtime":1610350419464,"results":"76","hashOfConfig":"56"},{"size":369,"mtime":1610351960667,"results":"77","hashOfConfig":"56"},{"size":534,"mtime":1607292532075,"results":"78","hashOfConfig":"56"},{"size":340,"mtime":1607430711272,"results":"79","hashOfConfig":"56"},{"size":358,"mtime":1607816378529,"results":"80","hashOfConfig":"56"},{"size":375,"mtime":1607260125923,"results":"81","hashOfConfig":"56"},{"size":390,"mtime":1608850637136,"results":"82","hashOfConfig":"56"},{"size":419,"mtime":1609913346831,"results":"83","hashOfConfig":"56"},{"size":540,"mtime":1607529608604,"results":"84","hashOfConfig":"56"},{"size":394,"mtime":1608448546580,"results":"85","hashOfConfig":"56"},{"size":206,"mtime":1607342162060,"results":"86","hashOfConfig":"56"},{"size":4770,"mtime":1607430353516,"results":"87","hashOfConfig":"56"},{"size":3836,"mtime":1610356472899,"results":"88","hashOfConfig":"56"},{"size":1626,"mtime":1610349813009,"results":"89","hashOfConfig":"56"},{"size":213,"mtime":1607342531957,"results":"90","hashOfConfig":"56"},{"size":204,"mtime":1607342542038,"results":"91","hashOfConfig":"56"},{"size":5471,"mtime":1608852677675,"results":"92","hashOfConfig":"56"},{"size":5035,"mtime":1610354111429,"results":"93","hashOfConfig":"56"},{"size":2528,"mtime":1609913218191,"results":"94","hashOfConfig":"56"},{"size":2379,"mtime":1610267137497,"results":"95","hashOfConfig":"56"},{"size":98,"mtime":1610733891137,"results":"96","hashOfConfig":"56"},{"size":3558,"mtime":1610347837498,"results":"97","hashOfConfig":"56"},{"size":11600,"mtime":1610356264839,"results":"98","hashOfConfig":"56"},{"size":10365,"mtime":1610350599948,"results":"99","hashOfConfig":"56"},{"size":318,"mtime":1608852934388,"results":"100","hashOfConfig":"56"},{"size":3624,"mtime":1610275595190,"results":"101","hashOfConfig":"56"},{"size":3907,"mtime":1610440735107,"results":"102","hashOfConfig":"56"},{"size":1438,"mtime":1611364238145,"results":"103","hashOfConfig":"56"},{"size":261,"mtime":1611364236143,"results":"104","hashOfConfig":"56"},{"size":2716,"mtime":1610613869470,"results":"105","hashOfConfig":"56"},{"size":1630,"mtime":1610614530760,"results":"106","hashOfConfig":"56"},{"size":2975,"mtime":1610540007725,"results":"107","hashOfConfig":"56"},{"size":2915,"mtime":1611426491458,"results":"108","hashOfConfig":"56"},{"size":2145,"mtime":1611366674505,"results":"109","hashOfConfig":"56"},{"filePath":"110","messages":"111","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},"fw5a4t",{"filePath":"113","messages":"114","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"115","messages":"116","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"117","messages":"118","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"119","messages":"120","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"121","messages":"122","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"123","messages":"124","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"125","messages":"126","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"127","messages":"128","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"129","messages":"130","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"131","messages":"132","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"133","messages":"134","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"135","messages":"136","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"137","messages":"138","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"139","messages":"140","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"141","messages":"142","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"143","messages":"144","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"145","messages":"146","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"147","messages":"148","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"149","messages":"150","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"151","messages":"152","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"153","messages":"154","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"155","messages":"156","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"157","messages":"158","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"159","messages":"160","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"161","messages":"162","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"163","messages":"164","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"165","messages":"166","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"167","messages":"168","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"169","messages":"170","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"171","messages":"172","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"173","messages":"174","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"175","messages":"176","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"177","usedDeprecatedRules":"112"},{"filePath":"178","messages":"179","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"180","usedDeprecatedRules":"112"},{"filePath":"181","messages":"182","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"183","messages":"184","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"185","messages":"186","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"187","messages":"188","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"189","messages":"190","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"191","messages":"192","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"193","messages":"194","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"195","messages":"196","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"197","messages":"198","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"199","usedDeprecatedRules":"112"},{"filePath":"200","messages":"201","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"202","usedDeprecatedRules":"112"},{"filePath":"203","messages":"204","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"205","messages":"206","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"207","messages":"208","errorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"209","usedDeprecatedRules":"112"},{"filePath":"210","messages":"211","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},{"filePath":"212","messages":"213","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"214","usedDeprecatedRules":"112"},{"filePath":"215","messages":"216","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":"217","usedDeprecatedRules":"112"},{"filePath":"218","messages":"219","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":"220","usedDeprecatedRules":"112"},{"filePath":"221","messages":"222","errorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":"223","usedDeprecatedRules":"112"},{"filePath":"224","messages":"225","errorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"226","messages":"227","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"112"},"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/index.js",[],["228","229"],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/App.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/router.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/counter.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/constants.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getScript.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/notFound/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx",["230"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport Box from '@material-ui/core/Box';\nimport ServiceGridItem from '../../features/servicesGridItem';\nimport BuildSidebar from '../../features/BuildSidebar';\nimport { getServiceTemplateListAction } from '../../actions/getServiceTemplateList.action';\nimport { getServiceTemplatesAction } from '../../actions/getServiceTemplates.action';\nimport { getNetworkTemplateListAction } from '../../actions/getNetworkTemplateList.action';\nimport {\n getBuildOptions,\n setBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceTemplatesList: () => dispatch(getServiceTemplateListAction()),\n dispatchGetNetworkTemplatesList: () => dispatch(getNetworkTemplateListAction()),\n dispatchGetServiceTemplates: () => dispatch(getServiceTemplatesAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n serviceTemplateList: selector(state => state.serviceTemplateList),\n networkTemplateList: selector(state => state.networkTemplateList),\n serviceTemplates: selector(state => state.serviceTemplates)\n };\n};\n\nconst Main = (props) => {\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n dispatchGetServiceTemplatesList,\n dispatchGetNetworkTemplatesList,\n dispatchGetServiceTemplates,\n serviceTemplateList,\n networkTemplateList,\n serviceTemplates\n } = props;\n const buildOptions = getBuildOptions();\n\n useEffect(() => {\n dispatchGetServiceTemplatesList();\n dispatchGetNetworkTemplatesList();\n dispatchGetServiceTemplates();\n }, []);\n\n return (\n \n
\n \n \n \n {Array.isArray(serviceTemplateList.payload) && serviceTemplateList.payload.map((templateName) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n\n
\n
\n );\n};\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx",["231"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport BuildHistoryGridItem from '../../features/buildHistoryGridItem'\nimport {\n getBuildHistoryListAction\n} from '../../actions/getBuildHistoryList.action';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetBuildHistoryList: () => dispatch(getBuildHistoryListAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n buildHistory: selector(state => state.buildHistory)\n };\n};\n\nconst Main = (props) => {\n\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const { dispatchGetBuildHistoryList, buildHistory } = props;\n\n useEffect(() => {\n dispatchGetBuildHistoryList();\n }, []);\n\n return (\n \n
\n \n {typeof buildHistory.payload !== 'undefined' && Object.keys(buildHistory.payload.buildsList).map((buildDetailsTime) => {\n return (\n \n \n \n );\n })}\n \n
\n
\n );\n}\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/help/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/builds.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/templates.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/configs.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/config.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx",["232"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Skeleton from '@material-ui/lab/Skeleton';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Button from '@material-ui/core/Button';\nimport Link from '@material-ui/core/Link';\nimport ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ServiceConfigModal from '../serviceConfigModal';\nimport { useTheme } from '@material-ui/core/styles';\nimport {\n getBuildIssuesAction\n} from '../../actions/checkBuildIssues.action';\nimport {\n getServiceMetadataAction\n} from '../../actions/getServiceMetadata.action';\nimport {\n getServiceConfigOptionsAction\n} from '../../actions/getServiceConfigOptions.action';\nimport {\n addSelectedService,\n removeSelectedService\n} from '../../actions/updateSelectedServices.action';\nimport styles from './services-grid-item.module.css';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceMetadata: (serviceName) => dispatch(getServiceMetadataAction(serviceName)),\n dispatchGetServiceConfigOptions: (serviceName) => dispatch(getServiceConfigOptionsAction(serviceName)),\n dispatchGetBuildIssues: (selectedServices, serviceConfigurations) => dispatch(getBuildIssuesAction(selectedServices, serviceConfigurations)),\n dispatchAddSelectedService: (serviceName) => dispatch(addSelectedService(serviceName)),\n dispatchRemoveSelectedService: (serviceName) => dispatch(removeSelectedService(serviceName))\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n templateList: selector(state => state.templateList),\n configServiceMetadata: selector(state => state.configServiceMetadata),\n configServiceConfigOptions: selector(state => state.configServiceConfigOptions),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues)\n };\n};\n\nconst useStyles = makeStyles({\n serviceCard: {\n \"&:hover\": {\n borderColor: ({ theme }) => theme.palette.text.primary\n }\n }\n});\n\nconst ServiceItem = (props) => {\n const theme = useTheme();\n const classes = useStyles({ props, theme });\n // console.log('theme.palette', theme.palette)\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n serviceName,\n networkTemplateList,\n serviceTemplates,\n dispatchGetServiceMetadata,\n dispatchGetServiceConfigOptions,\n dispatchAddSelectedService,\n dispatchRemoveSelectedService,\n dispatchGetBuildIssues,\n configServiceMetadata,\n configServiceConfigOptions,\n selectedServices,\n hideServiceTags,\n buildIssues,\n buildOptions,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const [isLoading, setIsLoading] = useState(false);\n const [serviceMetadata, setServiceMetadata] = useState({});\n const [serviceMetadataError, setServiceMetadataError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceMetadata.services.completed[serviceName] === 'undefined'\n && typeof configServiceMetadata.services.failed[serviceName] === 'undefined'\n && !configServiceMetadata.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceMetadata(serviceName);\n }\n\n setIsLoading(false);\n\n if (typeof configServiceMetadata.services.completed[serviceName] === 'object') {\n setServiceMetadata(configServiceMetadata.services.completed[serviceName].payload);\n } else if (!configServiceMetadata.services.pending.includes(serviceName)) {\n setServiceMetadataError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceMetadata,\n configServiceMetadata.services.completed,\n configServiceMetadata.services.pending,\n configServiceMetadata.services.failed\n ]);\n\n const [serviceConfigOptions, setServiceConfigOptions] = useState({});\n const [serviceConfigOptionsError, setServiceConfigOptionsError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceConfigOptions.services.completed[serviceName] === 'undefined'\n && typeof configServiceConfigOptions.services.failed[serviceName] === 'undefined'\n && !configServiceConfigOptions.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceConfigOptions(serviceName);\n }\n\n // setIsLoading(false);\n\n if (typeof configServiceConfigOptions.services.completed[serviceName] === 'object') {\n setServiceConfigOptions(configServiceConfigOptions.services.completed[serviceName].payload);\n } else if (!configServiceConfigOptions.services.pending.includes(serviceName)) {\n setServiceConfigOptionsError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceConfigOptions,\n configServiceConfigOptions.services.completed,\n configServiceConfigOptions.services.pending,\n configServiceConfigOptions.services.failed\n ]);\n\n const [updated, setIsUpdated] = useState(false);\n useEffect(() => {\n if (updated) {\n dispatchGetBuildIssues(selectedServices.selectedServices, {});\n }\n setIsUpdated(false);\n }, [\n updated,\n serviceName,\n selectedServices.selectedServices,\n dispatchGetBuildIssues\n ]);\n\n const [hasIssue, setHasIssue] = useState(false);\n useEffect(() => {\n if (!selectedServices.selectedServices.includes(serviceName)) {\n return void setHasIssue(false);\n }\n const issueList = buildIssues?.payload?.issueList ?? {};\n if (Array.isArray(issueList.services)) {\n issueList.services.forEach((service) => {\n if (service.name === serviceName) {\n return void setHasIssue(true);\n }\n });\n }\n }, [buildIssues, selectedServices.selectedServices, serviceName]);\n\n const handleBuildSelectChange = (evt) => {\n setIsUpdated(true);\n if (evt.target.checked) {\n return dispatchAddSelectedService(serviceName);\n }\n return dispatchRemoveSelectedService(serviceName);\n }\n\n const [modalOpen, setModalOpen] = useState(false);\n\n const serviceComponent = () => {\n return (\n \n setModalOpen(false)}\n serviceMetadata={serviceMetadata}\n serviceConfigOptions={serviceConfigOptions}\n serviceName={serviceName}\n buildOptions={buildOptions}\n setBuildOptions={setBuildOptions}\n setServiceOptions={setServiceOptions}\n getBuildOptions={getBuildOptions}\n buildOptionsInit={buildOptionsInit}\n setTemporaryBuildOptions={setTemporaryBuildOptions}\n getTemporaryBuildOptions={getTemporaryBuildOptions}\n setTemporaryServiceOptions={setTemporaryServiceOptions}\n setupTemporaryBuildOptions={setupTemporaryBuildOptions}\n saveTemporaryBuildOptions={saveTemporaryBuildOptions}\n networkTemplateList={networkTemplateList}\n serviceTemplates={serviceTemplates}\n />\n {serviceMetadata.displayName}\n \n {!serviceMetadata.iconUri\n && (\n \n \n \n )}\n {serviceMetadata.iconUri\n && (\n \n
\n {`${serviceMetadata.displayName}\n
\n
\n )}\n
\n \n \n \n \n \n }\n label={`Add ${serviceMetadata.displayName} to build`}\n />\n \n \n \n {serviceMetadata.displayName} Help and Docs\n \n \n \n )\n };\n\n const errorComponent = () => {\n return (\n \n
Error loading: {serviceName}
\n
Try refreshing, and ensuring the API server is running correctly.
\n
\n )\n };\n\n const loadingComponent = () => {\n return (\n \n Loading '{serviceName}' metadata...\n \n \n \n \n \n \n \n \n \n \n \n \n \n )\n };\n\n const highlightClass = () => {\n if (selectedServices.selectedServices.includes(serviceName)) {\n if (hasIssue) {\n return styles.serviceError;\n } else {\n return styles.selectedForBuild;\n }\n }\n\n return '';\n };\n\n const tagIsHidden = (hiddenTags, serviceTags) => {\n let hide = false;\n\n hiddenTags.forEach((hiddenTag) => {\n serviceTags.forEach((serviceTag) => {\n if (hiddenTag === serviceTag) {\n hide = true;\n }\n });\n });\n\n return hide;\n }\n\n if (!isLoading && tagIsHidden(hideServiceTags.hideServiceTags, serviceMetadata.serviceTypeTags)) {\n return null;\n }\n\n return (\n \n \n {isLoading\n && (loadingComponent())}\n {!isLoading\n && serviceMetadata.displayName\n && (\n serviceComponent()\n )}\n {!isLoading\n && serviceMetadataError.hasError === true\n && (\n errorComponent()\n )}\n \n \n );\n};\n\nexport default ServiceItem;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx",["233","234"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\n// import Tooltip from '@material-ui/core/Tooltip';\nimport Button from '@material-ui/core/Button';\n// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport Divider from '@material-ui/core/Divider';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n// import { makeStyles, useTheme } from '@material-ui/core/styles';\nimport styles from './build-sidebar.module.css';\nimport {\n addTagToHideListAction,\n removeTagFromHideListAction\n} from '../../actions/updateFilterTags.action';\nimport {\n createAndBuildStackAction\n} from '../../actions/buildStack.action';\nimport {\n getScriptFromTemplateAction\n} from '../../actions/getScript.action';\nimport {\n downloadBuildFile\n} from '../../actions/downloadBuild.action';\nimport BuildCompletedModal from '../buildCompletedModal';\nimport { API_STATUS } from '../../constants'\n\n// const useStyles = makeStyles({\n// serviceCard: {\n// \"&:hover\": {\n// borderColor: ({ theme }) => theme.palette.text.primary\n// }\n// }\n// });\n\nconst getUniqueTagsFromTemplates = ({ serviceTemplateListPayload, metadataList }) => {\n const tagList = [];\n if (Array.isArray(serviceTemplateListPayload)) {\n serviceTemplateListPayload.forEach((service) => {\n if (metadataList[service] && metadataList[service].payload && Array.isArray(metadataList[service].payload.serviceTypeTags)) {\n metadataList[service].payload.serviceTypeTags.forEach((tag) => {\n if (!tagList.includes(tag)) {\n tagList.push(tag);\n }\n });\n }\n });\n }\n tagList.sort();\n return tagList;\n};\n\nconst buildIssueListItem = (name, issueType, issueText) => {\n return (\n {name} [{issueType}] - {issueText}\n );\n};\n\nconst buildIssuesRender = (issues) => {\n const unknownError = !(\n issues.payload\n && issues.payload.issueList\n && Array.isArray(issues.payload.issueList.services)\n && Array.isArray(issues.payload.issueList.networks)\n && Array.isArray(issues.payload.issueList.other)\n );\n\n const noIssues = (\n !unknownError\n && issues.payload.issueList.services.length === 0\n && issues.payload.issueList.networks.length === 0\n && issues.payload.issueList.other.length === 0\n );\n\n return (\n \n Build Issues:\n \n {issues.status === API_STATUS.SUCCESS\n && (\n \n {Array.isArray(issues.payload.issueList.services)\n && issues.payload.issueList.services.length > 0\n && (\n \n \n Services:\n \n
    \n {issues.payload.issueList.services.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.networks)\n && issues.payload.issueList.networks.length > 0\n && (\n \n \n Networks:\n \n
    \n {issues.payload.issueList.networks.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.other)\n && issues.payload.issueList.other.length > 0\n && (\n \n \n Other Issues:\n \n
    \n {issues.payload.issueList.other.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {noIssues\n && (\n \n \n No build issues\n \n \n )}\n {!noIssues\n && (\n \n \n You can still attempt to build when issues are reported.\n \n \n )}\n {unknownError\n && (\n \n \n An unknown error occured retrieving build issues\n \n \n )}\n
\n )}\n {issues.status === API_STATUS.PENDING\n && (\n Loading...\n )}\n {issues.status === API_STATUS.FAILURE\n && (\n Failed to get build issues from API\n )}\n {issues.status === API_STATUS.UNINIT\n && (\n No changes detected\n )}\n
\n
\n );\n};\n\nconst buildList = (selectedServices) => {\n return (\n \n Building Services:\n \n {selectedServices.join(', ')}\n \n \n );\n};\n\nconst buildServices = (dispatchBuildStack) => {\n return (\n \n Build:\n \n \n \n \n );\n};\n\nconst Sidebar = (props) => {\n // const theme = useTheme();\n // const classes = useStyles({ props, theme });\n\n const mapStateToProps = (selector) => {\n return {\n configServiceMetadata: selector(state => state.configServiceMetadata),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues),\n buildStack: selector(state => state.buildStack),\n scriptTemplates: selector(state => state.scriptTemplates)\n };\n };\n const mapDispatchToProps = (dispatch) => {\n return {\n dispatchAddTagToHideList: (tag) => dispatch(addTagToHideListAction(tag)),\n dispatchRemoveTagFromHideList: (tag) => dispatch(removeTagFromHideListAction(tag)),\n dispatchBuildStack: (selectedServices, serviceConfigurations) => dispatch(createAndBuildStackAction(selectedServices, serviceConfigurations)),\n dispatchGetScriptTemplates: ({ scriptName, options, linkRef }) => dispatch(getScriptFromTemplateAction({ scriptName, options, linkRef })),\n dispatchDownloadBuildFile: ({ build, type, linkRef }) => dispatch(downloadBuildFile({ build, type, linkRef }))\n };\n };\n \n props = {\n ...props,\n ...mapStateToProps(useSelector),\n ...mapDispatchToProps(useDispatch()),\n };\n\n const [modalOpen, setModalOpen] = useState(false);\n useEffect(() => {\n if (props.buildStack.status === API_STATUS.SUCCESS) {\n setModalOpen(true);\n }\n }, [\n props.buildStack\n ]);\n\n const {\n serviceTemplateList,\n configServiceMetadata,\n selectedServices,\n buildIssues,\n hideServiceTags,\n dispatchRemoveTagFromHideList,\n dispatchAddTagToHideList,\n dispatchBuildStack,\n dispatchGetScriptTemplates,\n dispatchDownloadBuildFile,\n buildStack,\n scriptTemplates\n } = props;\n\n const downloadLinkRef = React.useRef(null);\n\n const handleBuildSelectChange = (evt, tagName) => {\n if (evt.target.checked) {\n return dispatchAddTagToHideList(tagName);\n }\n return dispatchRemoveTagFromHideList(tagName);\n };\n\n const serviceFilter = (serviceTemplateListPayload, servicesMetadata) => {\n return (\n \n Hide by tag:\n \n {\n getUniqueTagsFromTemplates({ serviceTemplateListPayload, metadataList: servicesMetadata }).map((tag) => {\n return (\n -1}\n onChange={(evt) => handleBuildSelectChange(evt, tag)}\n name=\"checkedB\"\n color=\"primary\"\n />\n }\n label={tag}\n />\n );\n })\n }\n \n \n );\n };\n \n return (\n \n
\n setModalOpen(false)}\n buildStack={buildStack}\n scriptTemplates={scriptTemplates}\n dispatchGetScriptTemplates={dispatchGetScriptTemplates}\n dispatchDownloadBuildFile={dispatchDownloadBuildFile}\n downloadLinkRef={downloadLinkRef}\n />\n \n {serviceFilter(serviceTemplateList.payload, configServiceMetadata.services.completed)}\n \n {buildIssuesRender(buildIssues)}\n \n {buildList(selectedServices.selectedServices)}\n \n {buildServices(() => {\n if (Array.isArray(selectedServices.selectedServices) && selectedServices.selectedServices.length > 0) {\n dispatchBuildStack(selectedServices.selectedServices);\n }\n })}\n \n \n );\n};\n\nexport default Sidebar;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx",["235","236","237","238"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Modal from '@material-ui/core/Modal';\nimport Grid from '@material-ui/core/Grid';\nimport Button from \"@material-ui/core/Button\";\nimport Box from '@material-ui/core/Box';\nimport getConfigComponents from '../../utils/configOptionLoader';\nimport {\n deleteTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst getModalStyle = () => {\n const top = 10;\n const left = 50;\n\n return {\n top: `${top}%`,\n left: `${left}%`,\n maxHeight: '75%',\n overflow: 'hidden',\n overflowY: 'scroll',\n transform: `translate(-50%, 0%)`,\n };\n};\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n position: 'absolute',\n width: '50%',\n backgroundColor: theme.palette.background.paper,\n border: '2px solid #000',\n boxShadow: theme.shadows[5],\n padding: theme.spacing(2, 4, 3),\n },\n}));\n\nconst ServiceConfigModal = (props) => {\n const {\n isOpen,\n handleClose,\n serviceName,\n networkTemplateList,\n serviceMetadata,\n serviceConfigOptions,\n buildOptions,\n serviceTemplates,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const closeModal = (event) => {\n deleteTemporaryBuildOptions();\n if (typeof handleClose === 'function') {\n handleClose(event);\n }\n }\n\n const classes = useStyles();\n const [modalStyle] = React.useState(getModalStyle);\n const body = (\n
\n

{serviceMetadata ? serviceMetadata.displayName : ''} ({serviceName}) Configuration

\n \n {getConfigComponents(serviceConfigOptions ?? []).map((ConfigComponent, index) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n \n \n \n \n \n \n
\n );\n\n return (\n \n {body}\n \n );\n};\n\nexport default ServiceConfigModal;","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js",["239"],"import PortConfig from './general/portConfig';\nimport NetworkConfig from './general/networkConfig';\nimport Logging from './general/logging';\nimport Volumes from './general/volumesConfig';\n\nexport default {\n PortConfig,\n NetworkConfig,\n Logging,\n Volumes\n};\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx",["240","241","242","243","244","245","246","247","248","249"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n\nconst NetworkConfig = (props) => {\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n networkTemplateList,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [modifiedNetworkList, setModifiedNetworkList] = useState({});\n useEffect(() => {\n const defaultOnNetworks = { ...getBuildOptions()?.services?.[serviceName]?.networks ?? {} };\n serviceTemplates[serviceName]?.networks?.forEach((networkName) => {\n defaultOnNetworks[networkName] = true;\n });\n setModifiedNetworkList({\n ...defaultOnNetworks\n });\n }, []);\n\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n networks: modifiedNetworkList\n });\n }, [\n modifiedNetworkList\n ]);\n\n const onChangeCb = (networkName, event) => {\n const networkSelected = event.target.checked;\n setModifiedNetworkList({\n ...modifiedNetworkList,\n [networkName]: networkSelected\n });\n if (typeof(onChange) === 'function') {\n onChange(networkName, networkName);\n }\n };\n\n const defaultValue = (networkName) => {\n return (serviceTemplates[serviceName]?.networks ?? []).includes(networkName);\n };\n\n return (\n \n IOTstack Networks:\n \n {(networkTemplateList?.payload ?? []).map((networkName) => {\n return (\n \n onChangeCb(networkName, evt) }\n name={networkName}\n color=\"primary\"\n />\n }\n label={networkName}\n />\n \n );\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default NetworkConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx",["250","251","252","253","254","255","256","257","258","259"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Box from '@material-ui/core/Box';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [loggingEnabled, setLoggingEnabled] = useState(getBuildOptions()?.services?.[serviceName]?.loggingEnabled ?? true);\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n loggingEnabled\n });\n }, [\n loggingEnabled\n ]);\n\n const onChangeCb = (event) => {\n const newSetting = event.target.checked;\n setLoggingEnabled(newSetting);\n if (typeof(onChange) === 'function') {\n onChange(newSetting);\n }\n };\n\n return (\n \n \n onChangeCb(evt) }\n name={\"logging\"}\n color=\"primary\"\n />\n }\n label={`Enable Logging for ${serviceName}`}\n />\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx",["260","261","262","263","264","265","266"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getExternalPort,\n replaceExternalPort,\n getInternalPort\n} from '../../../utils/parsers';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [portSettings, setPortSettings] = useState(getBuildOptions()?.services?.[serviceName]?.ports || {});\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n ports: portSettings\n });\n }, [\n portSettings\n ]);\n\n const onChangeCb = (portKey, portLabelValue, event) => {\n const newPort = event.target.value;\n // const defaultTemplatePort = defaultValue(portKey, portKey);\n setPortSettings({\n ...portSettings,\n [portKey]: replaceExternalPort((portSettings[portKey] || portKey), newPort)\n });\n if (typeof(onChange) === 'function') {\n onChange(portKey, portLabelValue, newPort);\n }\n };\n\n const defaultValue = (portValueKey, defaultValue) => {\n const servicePorts = tempBuildOptions?.services?.[serviceName] ?? {};\n return servicePorts?.ports?.[portValueKey] ?? defaultValue;\n };\n\n return (\n \n \n {serviceConfigOptions && Object.keys(serviceConfigOptions.labeledPorts).map((portValueKey) => {\n const currentPortSetting = portSettings[portValueKey] || defaultValue(portValueKey, portValueKey);\n if ((serviceTemplates[serviceName]?.ports?.[portValueKey] ?? []).indexOf(portValueKey)) { // Only show ports that exist in the YAML template\n return (\n \n { onChangeCb(portValueKey, serviceConfigOptions.labeledPorts[portValueKey], event) }}\n value={getExternalPort(currentPortSetting)}\n />\n \n );\n }\n\n return null;\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx",["267","268","269","270","271","272","273","274","275","276","277","278","279"],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/parsers.js",[],{"ruleId":"280","replacedBy":"281"},{"ruleId":"282","replacedBy":"283"},{"ruleId":"284","severity":1,"message":"285","line":60,"column":6,"nodeType":"286","endLine":60,"endColumn":8,"suggestions":"287"},{"ruleId":"284","severity":1,"message":"288","line":34,"column":6,"nodeType":"286","endLine":34,"endColumn":8,"suggestions":"289"},{"ruleId":"290","severity":1,"message":"291","line":127,"column":10,"nodeType":"292","messageId":"293","endLine":127,"endColumn":35},{"ruleId":"294","severity":1,"message":"295","line":300,"column":7,"nodeType":"296","endLine":300,"endColumn":34},{"ruleId":"297","severity":1,"message":"298","line":300,"column":7,"nodeType":"296","endLine":300,"endColumn":34},{"ruleId":"290","severity":1,"message":"299","line":1,"column":27,"nodeType":"292","messageId":"293","endLine":1,"endColumn":35},{"ruleId":"290","severity":1,"message":"300","line":1,"column":37,"nodeType":"292","messageId":"293","endLine":1,"endColumn":46},{"ruleId":"290","severity":1,"message":"301","line":10,"column":3,"nodeType":"292","messageId":"293","endLine":10,"endColumn":28},{"ruleId":"290","severity":1,"message":"302","line":46,"column":5,"nodeType":"292","messageId":"293","endLine":46,"endColumn":17},{"ruleId":"303","severity":1,"message":"304","line":6,"column":1,"nodeType":"305","endLine":11,"endColumn":3},{"ruleId":"290","severity":1,"message":"306","line":9,"column":5,"nodeType":"292","messageId":"293","endLine":9,"endColumn":25},{"ruleId":"290","severity":1,"message":"307","line":11,"column":5,"nodeType":"292","messageId":"293","endLine":11,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":13,"column":5,"nodeType":"292","messageId":"293","endLine":13,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":14,"column":5,"nodeType":"292","messageId":"293","endLine":14,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":29},{"ruleId":"290","severity":1,"message":"311","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":30},{"ruleId":"290","severity":1,"message":"313","line":25,"column":9,"nodeType":"292","messageId":"293","endLine":25,"endColumn":25},{"ruleId":"284","severity":1,"message":"314","line":36,"column":6,"nodeType":"286","endLine":36,"endColumn":8,"suggestions":"315"},{"ruleId":"284","severity":1,"message":"316","line":43,"column":6,"nodeType":"286","endLine":45,"endColumn":4,"suggestions":"317"},{"ruleId":"290","severity":1,"message":"306","line":10,"column":5,"nodeType":"292","messageId":"293","endLine":10,"endColumn":25},{"ruleId":"290","severity":1,"message":"307","line":12,"column":5,"nodeType":"292","messageId":"293","endLine":12,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":14,"column":5,"nodeType":"292","messageId":"293","endLine":14,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":15,"column":5,"nodeType":"292","messageId":"293","endLine":15,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":29},{"ruleId":"290","severity":1,"message":"311","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":30},{"ruleId":"290","severity":1,"message":"318","line":21,"column":5,"nodeType":"292","messageId":"293","endLine":21,"endColumn":21},{"ruleId":"290","severity":1,"message":"313","line":25,"column":9,"nodeType":"292","messageId":"293","endLine":25,"endColumn":25},{"ruleId":"284","severity":1,"message":"316","line":33,"column":6,"nodeType":"286","endLine":35,"endColumn":4,"suggestions":"319"},{"ruleId":"290","severity":1,"message":"307","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":18,"column":5,"nodeType":"292","messageId":"293","endLine":18,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":29},{"ruleId":"290","severity":1,"message":"311","line":23,"column":5,"nodeType":"292","messageId":"293","endLine":23,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":24,"column":5,"nodeType":"292","messageId":"293","endLine":24,"endColumn":30},{"ruleId":"284","severity":1,"message":"316","line":37,"column":6,"nodeType":"286","endLine":39,"endColumn":4,"suggestions":"320"},{"ruleId":"290","severity":1,"message":"306","line":14,"column":5,"nodeType":"292","messageId":"293","endLine":14,"endColumn":25},{"ruleId":"290","severity":1,"message":"307","line":16,"column":5,"nodeType":"292","messageId":"293","endLine":16,"endColumn":20},{"ruleId":"290","severity":1,"message":"308","line":18,"column":5,"nodeType":"292","messageId":"293","endLine":18,"endColumn":21},{"ruleId":"290","severity":1,"message":"309","line":19,"column":5,"nodeType":"292","messageId":"293","endLine":19,"endColumn":22},{"ruleId":"290","severity":1,"message":"310","line":20,"column":5,"nodeType":"292","messageId":"293","endLine":20,"endColumn":29},{"ruleId":"290","severity":1,"message":"321","line":22,"column":5,"nodeType":"292","messageId":"293","endLine":22,"endColumn":31},{"ruleId":"290","severity":1,"message":"311","line":23,"column":5,"nodeType":"292","messageId":"293","endLine":23,"endColumn":31},{"ruleId":"290","severity":1,"message":"312","line":24,"column":5,"nodeType":"292","messageId":"293","endLine":24,"endColumn":30},{"ruleId":"290","severity":1,"message":"318","line":25,"column":5,"nodeType":"292","messageId":"293","endLine":25,"endColumn":21},{"ruleId":"290","severity":1,"message":"322","line":26,"column":5,"nodeType":"292","messageId":"293","endLine":26,"endColumn":13},{"ruleId":"290","severity":1,"message":"313","line":29,"column":9,"nodeType":"292","messageId":"293","endLine":29,"endColumn":25},{"ruleId":"290","severity":1,"message":"323","line":32,"column":10,"nodeType":"292","messageId":"293","endLine":32,"endColumn":24},{"ruleId":"290","severity":1,"message":"324","line":32,"column":26,"nodeType":"292","messageId":"293","endLine":32,"endColumn":43},"no-native-reassign",["325"],"no-negated-in-lhs",["326"],"react-hooks/exhaustive-deps","React Hook useEffect has missing dependencies: 'dispatchGetNetworkTemplatesList', 'dispatchGetServiceTemplates', and 'dispatchGetServiceTemplatesList'. Either include them or remove the dependency array.","ArrayExpression",["327"],"React Hook useEffect has a missing dependency: 'dispatchGetBuildHistoryList'. Either include it or remove the dependency array.",["328"],"no-unused-vars","'serviceConfigOptionsError' is assigned a value but never used.","Identifier","unusedVar","jsx-a11y/anchor-has-content","Anchors must have content and the content must be accessible by a screen reader.","JSXOpeningElement","jsx-a11y/anchor-is-valid","The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md","'useState' is defined but never used.","'useEffect' is defined but never used.","'saveTemporaryBuildOptions' is defined but never used.","'buildOptions' is assigned a value but never used.","import/no-anonymous-default-export","Assign object to a variable before exporting as module default","ExportDefaultDeclaration","'serviceConfigOptions' is assigned a value but never used.","'setBuildOptions' is assigned a value but never used.","'buildOptionsInit' is assigned a value but never used.","'setServiceOptions' is assigned a value but never used.","'setTemporaryBuildOptions' is assigned a value but never used.","'setupTemporaryBuildOptions' is assigned a value but never used.","'saveTemporaryBuildOptions' is assigned a value but never used.","'tempBuildOptions' is assigned a value but never used.","React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceName', and 'serviceTemplates'. Either include them or remove the dependency array.",["329"],"React Hook useEffect has missing dependencies: 'getTemporaryBuildOptions', 'serviceName', and 'setTemporaryServiceOptions'. Either include them or remove the dependency array.",["330"],"'serviceTemplates' is assigned a value but never used.",["331"],["332"],"'setTemporaryServiceOptions' is assigned a value but never used.","'onChange' is assigned a value but never used.","'volumeSettings' is assigned a value but never used.","'setVolumeSettings' is assigned a value but never used.","no-global-assign","no-unsafe-negation",{"desc":"333","fix":"334"},{"desc":"335","fix":"336"},{"desc":"337","fix":"338"},{"desc":"339","fix":"340"},{"desc":"341","fix":"342"},{"desc":"343","fix":"344"},"Update the dependencies array to be: [dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",{"range":"345","text":"346"},"Update the dependencies array to be: [dispatchGetBuildHistoryList]",{"range":"347","text":"348"},"Update the dependencies array to be: [getBuildOptions, serviceName, serviceTemplates]",{"range":"349","text":"350"},"Update the dependencies array to be: [getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",{"range":"351","text":"352"},"Update the dependencies array to be: [getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",{"range":"353","text":"354"},"Update the dependencies array to be: [getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",{"range":"355","text":"356"},[2011,2013],"[dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",[893,895],"[dispatchGetBuildHistoryList]",[1109,1111],"[getBuildOptions, serviceName, serviceTemplates]",[1298,1327],"[getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",[991,1015],"[getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",[1020,1042],"[getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]"] \ No newline at end of file +[{"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/index.js":"1","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/App.js":"2","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/index.js":"3","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/router.jsx":"4","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/counter.js":"5","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js":"6","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js":"7","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js":"8","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js":"9","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js":"10","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js":"11","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js":"12","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js":"13","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js":"14","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js":"15","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js":"16","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js":"17","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js":"18","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/constants.js":"19","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js":"20","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js":"21","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js":"22","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js":"23","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js":"24","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js":"25","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js":"26","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getScript.action.js":"27","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js":"28","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js":"29","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js":"30","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/notFound/index.js":"31","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js":"32","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx":"33","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx":"34","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx":"35","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/help/index.jsx":"36","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/builds.js":"37","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/templates.js":"38","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/configs.js":"39","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js":"40","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/config.js":"41","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx":"42","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx":"43","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx":"44","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js":"45","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx":"46","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx":"47","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx":"48","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js":"49","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx":"50","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx":"51","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx":"52","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx":"53","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/parsers.js":"54","/home/slyke/repos/IOTstack/.internal/wui/src/index.js":"55","/home/slyke/repos/IOTstack/.internal/wui/src/App.js":"56","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/index.js":"57","/home/slyke/repos/IOTstack/.internal/wui/src/router.jsx":"58","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/counter.js":"59","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js":"60","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js":"61","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js":"62","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js":"63","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js":"64","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js":"65","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js":"66","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js":"67","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js":"68","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js":"69","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js":"70","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js":"71","/home/slyke/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js":"72","/home/slyke/repos/IOTstack/.internal/wui/src/constants.js":"73","/home/slyke/repos/IOTstack/.internal/wui/src/pages/notFound/index.js":"74","/home/slyke/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js":"75","/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js":"76","/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js":"77","/home/slyke/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js":"78","/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js":"79","/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js":"80","/home/slyke/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js":"81","/home/slyke/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js":"82","/home/slyke/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js":"83","/home/slyke/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js":"84","/home/slyke/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js":"85","/home/slyke/repos/IOTstack/.internal/wui/src/actions/getScript.action.js":"86","/home/slyke/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx":"87","/home/slyke/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx":"88","/home/slyke/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx":"89","/home/slyke/repos/IOTstack/.internal/wui/src/pages/help/index.jsx":"90","/home/slyke/repos/IOTstack/.internal/wui/src/services/templates.js":"91","/home/slyke/repos/IOTstack/.internal/wui/src/services/configs.js":"92","/home/slyke/repos/IOTstack/.internal/wui/src/services/builds.js":"93","/home/slyke/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js":"94","/home/slyke/repos/IOTstack/.internal/wui/src/config.js":"95","/home/slyke/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx":"96","/home/slyke/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx":"97","/home/slyke/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx":"98","/home/slyke/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js":"99","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx":"100","/home/slyke/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx":"101","/home/slyke/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx":"102","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js":"103","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx":"104","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx":"105","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx":"106","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx":"107","/home/slyke/repos/IOTstack/.internal/wui/src/utils/parsers.js":"108","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/environmentConfig.jsx":"109","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/devicesConfig.jsx":"110"},{"size":353,"mtime":1606908594887,"results":"111","hashOfConfig":"112"},{"size":789,"mtime":1607430281547,"results":"113","hashOfConfig":"112"},{"size":1612,"mtime":1610356071552,"results":"114","hashOfConfig":"112"},{"size":1231,"mtime":1610350276543,"results":"115","hashOfConfig":"112"},{"size":1551,"mtime":1606908622214,"results":"116","hashOfConfig":"112"},{"size":962,"mtime":1610356100446,"results":"117","hashOfConfig":"112"},{"size":972,"mtime":1610350671817,"results":"118","hashOfConfig":"112"},{"size":972,"mtime":1610352205750,"results":"119","hashOfConfig":"112"},{"size":1105,"mtime":1607294167538,"results":"120","hashOfConfig":"112"},{"size":1878,"mtime":1607294201436,"results":"121","hashOfConfig":"112"},{"size":894,"mtime":1607816383799,"results":"122","hashOfConfig":"112"},{"size":1922,"mtime":1609913154250,"results":"123","hashOfConfig":"112"},{"size":947,"mtime":1607430599186,"results":"124","hashOfConfig":"112"},{"size":1079,"mtime":1607529487594,"results":"125","hashOfConfig":"112"},{"size":1714,"mtime":1608802587649,"results":"126","hashOfConfig":"112"},{"size":902,"mtime":1608450868778,"results":"127","hashOfConfig":"112"},{"size":607,"mtime":1607109560543,"results":"128","hashOfConfig":"112"},{"size":711,"mtime":1607260096944,"results":"129","hashOfConfig":"112"},{"size":160,"mtime":1607109631094,"results":"130","hashOfConfig":"112"},{"size":340,"mtime":1610354130554,"results":"131","hashOfConfig":"112"},{"size":369,"mtime":1610350419464,"results":"132","hashOfConfig":"112"},{"size":369,"mtime":1610351960667,"results":"133","hashOfConfig":"112"},{"size":534,"mtime":1607292532075,"results":"134","hashOfConfig":"112"},{"size":340,"mtime":1607430711272,"results":"135","hashOfConfig":"112"},{"size":358,"mtime":1607816378529,"results":"136","hashOfConfig":"112"},{"size":375,"mtime":1607260125923,"results":"137","hashOfConfig":"112"},{"size":390,"mtime":1608850637136,"results":"138","hashOfConfig":"112"},{"size":419,"mtime":1609913346831,"results":"139","hashOfConfig":"112"},{"size":540,"mtime":1607529608604,"results":"140","hashOfConfig":"112"},{"size":394,"mtime":1608448546580,"results":"141","hashOfConfig":"112"},{"size":206,"mtime":1607342162060,"results":"142","hashOfConfig":"112"},{"size":4770,"mtime":1607430353516,"results":"143","hashOfConfig":"112"},{"size":3836,"mtime":1610356472899,"results":"144","hashOfConfig":"112"},{"size":1626,"mtime":1610349813009,"results":"145","hashOfConfig":"112"},{"size":213,"mtime":1607342531957,"results":"146","hashOfConfig":"112"},{"size":204,"mtime":1607342542038,"results":"147","hashOfConfig":"112"},{"size":5471,"mtime":1608852677675,"results":"148","hashOfConfig":"112"},{"size":5035,"mtime":1610354111429,"results":"149","hashOfConfig":"112"},{"size":2528,"mtime":1609913218191,"results":"150","hashOfConfig":"112"},{"size":2379,"mtime":1610267137497,"results":"151","hashOfConfig":"112"},{"size":98,"mtime":1610733891137,"results":"152","hashOfConfig":"112"},{"size":3558,"mtime":1610347837498,"results":"153","hashOfConfig":"112"},{"size":11600,"mtime":1610356264839,"results":"154","hashOfConfig":"112"},{"size":10365,"mtime":1610350599948,"results":"155","hashOfConfig":"112"},{"size":318,"mtime":1608852934388,"results":"156","hashOfConfig":"112"},{"size":3624,"mtime":1610275595190,"results":"157","hashOfConfig":"112"},{"size":3907,"mtime":1610440735107,"results":"158","hashOfConfig":"112"},{"size":1438,"mtime":1611364238145,"results":"159","hashOfConfig":"112"},{"size":261,"mtime":1611364236143,"results":"160","hashOfConfig":"112"},{"size":2716,"mtime":1610613869470,"results":"161","hashOfConfig":"112"},{"size":1630,"mtime":1610614530760,"results":"162","hashOfConfig":"112"},{"size":2975,"mtime":1610540007725,"results":"163","hashOfConfig":"112"},{"size":2915,"mtime":1611426491458,"results":"164","hashOfConfig":"112"},{"size":2145,"mtime":1611366674505,"results":"165","hashOfConfig":"112"},{"size":353,"mtime":1611426633820,"results":"166","hashOfConfig":"167"},{"size":789,"mtime":1611426633820,"results":"168","hashOfConfig":"167"},{"size":1612,"mtime":1611426633860,"results":"169","hashOfConfig":"167"},{"size":1231,"mtime":1611426633830,"results":"170","hashOfConfig":"167"},{"size":1551,"mtime":1611426633860,"results":"171","hashOfConfig":"167"},{"size":972,"mtime":1611426633850,"results":"172","hashOfConfig":"167"},{"size":962,"mtime":1611426633850,"results":"173","hashOfConfig":"167"},{"size":972,"mtime":1611426633840,"results":"174","hashOfConfig":"167"},{"size":1878,"mtime":1611426633870,"results":"175","hashOfConfig":"167"},{"size":1922,"mtime":1611426633840,"results":"176","hashOfConfig":"167"},{"size":1105,"mtime":1611426633860,"results":"177","hashOfConfig":"167"},{"size":1079,"mtime":1611426633880,"results":"178","hashOfConfig":"167"},{"size":894,"mtime":1611426633870,"results":"179","hashOfConfig":"167"},{"size":902,"mtime":1611426633830,"results":"180","hashOfConfig":"167"},{"size":947,"mtime":1611426633840,"results":"181","hashOfConfig":"167"},{"size":1714,"mtime":1611426633870,"results":"182","hashOfConfig":"167"},{"size":711,"mtime":1611426633890,"results":"183","hashOfConfig":"167"},{"size":607,"mtime":1611426633890,"results":"184","hashOfConfig":"167"},{"size":160,"mtime":1611426633820,"results":"185","hashOfConfig":"167"},{"size":206,"mtime":1611426633770,"results":"186","hashOfConfig":"167"},{"size":4770,"mtime":1611426633670,"results":"187","hashOfConfig":"167"},{"size":369,"mtime":1611426633740,"results":"188","hashOfConfig":"167"},{"size":340,"mtime":1611426633720,"results":"189","hashOfConfig":"167"},{"size":369,"mtime":1611426633700,"results":"190","hashOfConfig":"167"},{"size":419,"mtime":1611426633720,"results":"191","hashOfConfig":"167"},{"size":375,"mtime":1611426633720,"results":"192","hashOfConfig":"167"},{"size":534,"mtime":1611426633730,"results":"193","hashOfConfig":"167"},{"size":540,"mtime":1611426633730,"results":"194","hashOfConfig":"167"},{"size":358,"mtime":1611426633710,"results":"195","hashOfConfig":"167"},{"size":340,"mtime":1611426633710,"results":"196","hashOfConfig":"167"},{"size":394,"mtime":1611426633730,"results":"197","hashOfConfig":"167"},{"size":390,"mtime":1611426633710,"results":"198","hashOfConfig":"167"},{"size":3836,"mtime":1611426633760,"results":"199","hashOfConfig":"167"},{"size":1626,"mtime":1611426633750,"results":"200","hashOfConfig":"167"},{"size":213,"mtime":1611426633780,"results":"201","hashOfConfig":"167"},{"size":204,"mtime":1611426633760,"results":"202","hashOfConfig":"167"},{"size":5035,"mtime":1611426633790,"results":"203","hashOfConfig":"167"},{"size":2528,"mtime":1611426633790,"results":"204","hashOfConfig":"167"},{"size":5471,"mtime":1611426633800,"results":"205","hashOfConfig":"167"},{"size":2379,"mtime":1611426633810,"results":"206","hashOfConfig":"167"},{"size":98,"mtime":1611426633680,"results":"207","hashOfConfig":"167"},{"size":11857,"mtime":1612418002970,"results":"208","hashOfConfig":"167"},{"size":3558,"mtime":1611426633600,"results":"209","hashOfConfig":"167"},{"size":10501,"mtime":1612335771520,"results":"210","hashOfConfig":"167"},{"size":318,"mtime":1611426633700,"results":"211","hashOfConfig":"167"},{"size":3878,"mtime":1611445663360,"results":"212","hashOfConfig":"167"},{"size":3624,"mtime":1611426633670,"results":"213","hashOfConfig":"167"},{"size":1870,"mtime":1612130327410,"results":"214","hashOfConfig":"167"},{"size":389,"mtime":1612130452410,"results":"215","hashOfConfig":"167"},{"size":2993,"mtime":1612150221810,"results":"216","hashOfConfig":"167"},{"size":4746,"mtime":1612423080560,"results":"217","hashOfConfig":"167"},{"size":1657,"mtime":1612131016720,"results":"218","hashOfConfig":"167"},{"size":3070,"mtime":1612150262840,"results":"219","hashOfConfig":"167"},{"size":2977,"mtime":1612602317250,"results":"220","hashOfConfig":"167"},{"size":3735,"mtime":1612135842030,"results":"221","hashOfConfig":"167"},{"size":2664,"mtime":1613114342660,"results":"222","hashOfConfig":"167"},{"filePath":"223","messages":"224","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},"fw5a4t",{"filePath":"226","messages":"227","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"228","messages":"229","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"230","messages":"231","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"232","messages":"233","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"234","messages":"235","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"236","messages":"237","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"238","messages":"239","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"240","messages":"241","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"242","messages":"243","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"244","messages":"245","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"246","messages":"247","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"248","messages":"249","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"250","messages":"251","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"252","messages":"253","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"254","messages":"255","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"256","messages":"257","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"258","messages":"259","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"260","messages":"261","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"262","messages":"263","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"264","messages":"265","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"266","messages":"267","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"268","messages":"269","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"270","messages":"271","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"272","messages":"273","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"274","messages":"275","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"276","messages":"277","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"278","messages":"279","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"280","messages":"281","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"282","messages":"283","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"284","messages":"285","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"286","messages":"287","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"288","messages":"289","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"290","usedDeprecatedRules":"225"},{"filePath":"291","messages":"292","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"293","usedDeprecatedRules":"225"},{"filePath":"294","messages":"295","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"296","messages":"297","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"298","messages":"299","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"300","messages":"301","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"302","messages":"303","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"304","messages":"305","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"306","messages":"307","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"308","messages":"309","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"310","messages":"311","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"312","usedDeprecatedRules":"225"},{"filePath":"313","messages":"314","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"315","usedDeprecatedRules":"225"},{"filePath":"316","messages":"317","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"318","messages":"319","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"320","messages":"321","errorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"322","usedDeprecatedRules":"225"},{"filePath":"323","messages":"324","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"325","messages":"326","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"327","usedDeprecatedRules":"225"},{"filePath":"328","messages":"329","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":"330","usedDeprecatedRules":"225"},{"filePath":"331","messages":"332","errorCount":0,"warningCount":10,"fixableErrorCount":0,"fixableWarningCount":0,"source":"333","usedDeprecatedRules":"225"},{"filePath":"334","messages":"335","errorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":"336","usedDeprecatedRules":"225"},{"filePath":"337","messages":"338","errorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"339","messages":"340","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"225"},{"filePath":"341","messages":"342","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},"1pdcxu",{"filePath":"344","messages":"345","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"346","messages":"347","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"348","messages":"349","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"350","messages":"351","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"352","messages":"353","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"354","messages":"355","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"356","messages":"357","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"358","messages":"359","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"360","messages":"361","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"362","messages":"363","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"364","messages":"365","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"366","messages":"367","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"368","messages":"369","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"370","messages":"371","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"372","messages":"373","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"374","messages":"375","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"376","messages":"377","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"378","messages":"379","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"380","messages":"381","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"382","messages":"383","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"384","messages":"385","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"386","messages":"387","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"388","messages":"389","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"390","messages":"391","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"392","messages":"393","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"394","messages":"395","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"396","messages":"397","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"398","messages":"399","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"400","messages":"401","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"402","messages":"403","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"404","messages":"405","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"406","messages":"407","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"290","usedDeprecatedRules":"343"},{"filePath":"408","messages":"409","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"293","usedDeprecatedRules":"343"},{"filePath":"410","messages":"411","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"412","messages":"413","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"414","messages":"415","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"416","messages":"417","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"418","messages":"419","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"420","messages":"421","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"422","messages":"423","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"424","messages":"425","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"426","usedDeprecatedRules":"343"},{"filePath":"427","messages":"428","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"429","messages":"430","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"431","usedDeprecatedRules":"343"},{"filePath":"432","messages":"433","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"434","messages":"435","errorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"436","usedDeprecatedRules":"343"},{"filePath":"437","messages":"438","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"439","messages":"440","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"343"},{"filePath":"441","messages":"442","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"443","usedDeprecatedRules":"343"},{"filePath":"444","messages":"445","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"446","usedDeprecatedRules":"343"},{"filePath":"447","messages":"448","errorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"449","usedDeprecatedRules":"343"},{"filePath":"450","messages":"451","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"452","usedDeprecatedRules":"343"},{"filePath":"453","messages":"454","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"455","usedDeprecatedRules":"343"},{"filePath":"456","messages":"457","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"458"},{"filePath":"459","messages":"460","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"461","usedDeprecatedRules":"343"},{"filePath":"462","messages":"463","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"464","usedDeprecatedRules":"343"},"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/index.js",[],["465","466"],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/App.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/router.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/counter.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/constants.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getScript.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/notFound/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx",["467"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport Box from '@material-ui/core/Box';\nimport ServiceGridItem from '../../features/servicesGridItem';\nimport BuildSidebar from '../../features/BuildSidebar';\nimport { getServiceTemplateListAction } from '../../actions/getServiceTemplateList.action';\nimport { getServiceTemplatesAction } from '../../actions/getServiceTemplates.action';\nimport { getNetworkTemplateListAction } from '../../actions/getNetworkTemplateList.action';\nimport {\n getBuildOptions,\n setBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceTemplatesList: () => dispatch(getServiceTemplateListAction()),\n dispatchGetNetworkTemplatesList: () => dispatch(getNetworkTemplateListAction()),\n dispatchGetServiceTemplates: () => dispatch(getServiceTemplatesAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n serviceTemplateList: selector(state => state.serviceTemplateList),\n networkTemplateList: selector(state => state.networkTemplateList),\n serviceTemplates: selector(state => state.serviceTemplates)\n };\n};\n\nconst Main = (props) => {\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n dispatchGetServiceTemplatesList,\n dispatchGetNetworkTemplatesList,\n dispatchGetServiceTemplates,\n serviceTemplateList,\n networkTemplateList,\n serviceTemplates\n } = props;\n const buildOptions = getBuildOptions();\n\n useEffect(() => {\n dispatchGetServiceTemplatesList();\n dispatchGetNetworkTemplatesList();\n dispatchGetServiceTemplates();\n }, []);\n\n return (\n \n
\n \n \n \n {Array.isArray(serviceTemplateList.payload) && serviceTemplateList.payload.map((templateName) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n\n
\n
\n );\n};\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx",["468"],"// import React, { Fragment, useState, useEffect } from 'react';\nimport React, { Fragment, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Grid from '@material-ui/core/Grid';\nimport BuildHistoryGridItem from '../../features/buildHistoryGridItem'\nimport {\n getBuildHistoryListAction\n} from '../../actions/getBuildHistoryList.action';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetBuildHistoryList: () => dispatch(getBuildHistoryListAction())\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n buildHistory: selector(state => state.buildHistory)\n };\n};\n\nconst Main = (props) => {\n\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const { dispatchGetBuildHistoryList, buildHistory } = props;\n\n useEffect(() => {\n dispatchGetBuildHistoryList();\n }, []);\n\n return (\n \n
\n \n {typeof buildHistory.payload !== 'undefined' && Object.keys(buildHistory.payload.buildsList).map((buildDetailsTime) => {\n return (\n \n \n \n );\n })}\n \n
\n
\n );\n}\n\nexport default Main;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/pages/help/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/builds.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/templates.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/services/configs.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/config.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx",["469"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Skeleton from '@material-ui/lab/Skeleton';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Button from '@material-ui/core/Button';\nimport Link from '@material-ui/core/Link';\nimport ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ServiceConfigModal from '../serviceConfigModal';\nimport { useTheme } from '@material-ui/core/styles';\nimport {\n getBuildIssuesAction\n} from '../../actions/checkBuildIssues.action';\nimport {\n getServiceMetadataAction\n} from '../../actions/getServiceMetadata.action';\nimport {\n getServiceConfigOptionsAction\n} from '../../actions/getServiceConfigOptions.action';\nimport {\n addSelectedService,\n removeSelectedService\n} from '../../actions/updateSelectedServices.action';\nimport styles from './services-grid-item.module.css';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceMetadata: (serviceName) => dispatch(getServiceMetadataAction(serviceName)),\n dispatchGetServiceConfigOptions: (serviceName) => dispatch(getServiceConfigOptionsAction(serviceName)),\n dispatchGetBuildIssues: (selectedServices, serviceConfigurations) => dispatch(getBuildIssuesAction(selectedServices, serviceConfigurations)),\n dispatchAddSelectedService: (serviceName) => dispatch(addSelectedService(serviceName)),\n dispatchRemoveSelectedService: (serviceName) => dispatch(removeSelectedService(serviceName))\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n templateList: selector(state => state.templateList),\n configServiceMetadata: selector(state => state.configServiceMetadata),\n configServiceConfigOptions: selector(state => state.configServiceConfigOptions),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues)\n };\n};\n\nconst useStyles = makeStyles({\n serviceCard: {\n \"&:hover\": {\n borderColor: ({ theme }) => theme.palette.text.primary\n }\n }\n});\n\nconst ServiceItem = (props) => {\n const theme = useTheme();\n const classes = useStyles({ props, theme });\n // console.log('theme.palette', theme.palette)\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n serviceName,\n networkTemplateList,\n serviceTemplates,\n dispatchGetServiceMetadata,\n dispatchGetServiceConfigOptions,\n dispatchAddSelectedService,\n dispatchRemoveSelectedService,\n dispatchGetBuildIssues,\n configServiceMetadata,\n configServiceConfigOptions,\n selectedServices,\n hideServiceTags,\n buildIssues,\n buildOptions,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const [isLoading, setIsLoading] = useState(false);\n const [serviceMetadata, setServiceMetadata] = useState({});\n const [serviceMetadataError, setServiceMetadataError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceMetadata.services.completed[serviceName] === 'undefined'\n && typeof configServiceMetadata.services.failed[serviceName] === 'undefined'\n && !configServiceMetadata.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceMetadata(serviceName);\n }\n\n setIsLoading(false);\n\n if (typeof configServiceMetadata.services.completed[serviceName] === 'object') {\n setServiceMetadata(configServiceMetadata.services.completed[serviceName].payload);\n } else if (!configServiceMetadata.services.pending.includes(serviceName)) {\n setServiceMetadataError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceMetadata,\n configServiceMetadata.services.completed,\n configServiceMetadata.services.pending,\n configServiceMetadata.services.failed\n ]);\n\n const [serviceConfigOptions, setServiceConfigOptions] = useState({});\n const [serviceConfigOptionsError, setServiceConfigOptionsError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceConfigOptions.services.completed[serviceName] === 'undefined'\n && typeof configServiceConfigOptions.services.failed[serviceName] === 'undefined'\n && !configServiceConfigOptions.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceConfigOptions(serviceName);\n }\n\n // setIsLoading(false);\n\n if (typeof configServiceConfigOptions.services.completed[serviceName] === 'object') {\n setServiceConfigOptions(configServiceConfigOptions.services.completed[serviceName].payload);\n } else if (!configServiceConfigOptions.services.pending.includes(serviceName)) {\n setServiceConfigOptionsError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceConfigOptions,\n configServiceConfigOptions.services.completed,\n configServiceConfigOptions.services.pending,\n configServiceConfigOptions.services.failed\n ]);\n\n const [updated, setIsUpdated] = useState(false);\n useEffect(() => {\n if (updated) {\n dispatchGetBuildIssues(selectedServices.selectedServices, {});\n }\n setIsUpdated(false);\n }, [\n updated,\n serviceName,\n selectedServices.selectedServices,\n dispatchGetBuildIssues\n ]);\n\n const [hasIssue, setHasIssue] = useState(false);\n useEffect(() => {\n if (!selectedServices.selectedServices.includes(serviceName)) {\n return void setHasIssue(false);\n }\n const issueList = buildIssues?.payload?.issueList ?? {};\n if (Array.isArray(issueList.services)) {\n issueList.services.forEach((service) => {\n if (service.name === serviceName) {\n return void setHasIssue(true);\n }\n });\n }\n }, [buildIssues, selectedServices.selectedServices, serviceName]);\n\n const handleBuildSelectChange = (evt) => {\n setIsUpdated(true);\n if (evt.target.checked) {\n return dispatchAddSelectedService(serviceName);\n }\n return dispatchRemoveSelectedService(serviceName);\n }\n\n const [modalOpen, setModalOpen] = useState(false);\n\n const serviceComponent = () => {\n return (\n \n setModalOpen(false)}\n serviceMetadata={serviceMetadata}\n serviceConfigOptions={serviceConfigOptions}\n serviceName={serviceName}\n buildOptions={buildOptions}\n setBuildOptions={setBuildOptions}\n setServiceOptions={setServiceOptions}\n getBuildOptions={getBuildOptions}\n buildOptionsInit={buildOptionsInit}\n setTemporaryBuildOptions={setTemporaryBuildOptions}\n getTemporaryBuildOptions={getTemporaryBuildOptions}\n setTemporaryServiceOptions={setTemporaryServiceOptions}\n setupTemporaryBuildOptions={setupTemporaryBuildOptions}\n saveTemporaryBuildOptions={saveTemporaryBuildOptions}\n networkTemplateList={networkTemplateList}\n serviceTemplates={serviceTemplates}\n />\n {serviceMetadata.displayName}\n \n {!serviceMetadata.iconUri\n && (\n \n \n \n )}\n {serviceMetadata.iconUri\n && (\n \n
\n {`${serviceMetadata.displayName}\n
\n
\n )}\n
\n \n \n \n \n \n }\n label={`Add ${serviceMetadata.displayName} to build`}\n />\n \n \n \n {serviceMetadata.displayName} Help and Docs\n \n \n \n )\n };\n\n const errorComponent = () => {\n return (\n \n
Error loading: {serviceName}
\n
Try refreshing, and ensuring the API server is running correctly.
\n
\n )\n };\n\n const loadingComponent = () => {\n return (\n \n Loading '{serviceName}' metadata...\n \n \n \n \n \n \n \n \n \n \n \n \n \n )\n };\n\n const highlightClass = () => {\n if (selectedServices.selectedServices.includes(serviceName)) {\n if (hasIssue) {\n return styles.serviceError;\n } else {\n return styles.selectedForBuild;\n }\n }\n\n return '';\n };\n\n const tagIsHidden = (hiddenTags, serviceTags) => {\n let hide = false;\n\n hiddenTags.forEach((hiddenTag) => {\n serviceTags.forEach((serviceTag) => {\n if (hiddenTag === serviceTag) {\n hide = true;\n }\n });\n });\n\n return hide;\n }\n\n if (!isLoading && tagIsHidden(hideServiceTags.hideServiceTags, serviceMetadata.serviceTypeTags)) {\n return null;\n }\n\n return (\n \n \n {isLoading\n && (loadingComponent())}\n {!isLoading\n && serviceMetadata.displayName\n && (\n serviceComponent()\n )}\n {!isLoading\n && serviceMetadataError.hasError === true\n && (\n errorComponent()\n )}\n \n \n );\n};\n\nexport default ServiceItem;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx",["470","471"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\n// import Tooltip from '@material-ui/core/Tooltip';\nimport Button from '@material-ui/core/Button';\n// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport Divider from '@material-ui/core/Divider';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n// import { makeStyles, useTheme } from '@material-ui/core/styles';\nimport styles from './build-sidebar.module.css';\nimport {\n addTagToHideListAction,\n removeTagFromHideListAction\n} from '../../actions/updateFilterTags.action';\nimport {\n createAndBuildStackAction\n} from '../../actions/buildStack.action';\nimport {\n getScriptFromTemplateAction\n} from '../../actions/getScript.action';\nimport {\n downloadBuildFile\n} from '../../actions/downloadBuild.action';\nimport BuildCompletedModal from '../buildCompletedModal';\nimport { API_STATUS } from '../../constants'\n\n// const useStyles = makeStyles({\n// serviceCard: {\n// \"&:hover\": {\n// borderColor: ({ theme }) => theme.palette.text.primary\n// }\n// }\n// });\n\nconst getUniqueTagsFromTemplates = ({ serviceTemplateListPayload, metadataList }) => {\n const tagList = [];\n if (Array.isArray(serviceTemplateListPayload)) {\n serviceTemplateListPayload.forEach((service) => {\n if (metadataList[service] && metadataList[service].payload && Array.isArray(metadataList[service].payload.serviceTypeTags)) {\n metadataList[service].payload.serviceTypeTags.forEach((tag) => {\n if (!tagList.includes(tag)) {\n tagList.push(tag);\n }\n });\n }\n });\n }\n tagList.sort();\n return tagList;\n};\n\nconst buildIssueListItem = (name, issueType, issueText) => {\n return (\n {name} [{issueType}] - {issueText}\n );\n};\n\nconst buildIssuesRender = (issues) => {\n const unknownError = !(\n issues.payload\n && issues.payload.issueList\n && Array.isArray(issues.payload.issueList.services)\n && Array.isArray(issues.payload.issueList.networks)\n && Array.isArray(issues.payload.issueList.other)\n );\n\n const noIssues = (\n !unknownError\n && issues.payload.issueList.services.length === 0\n && issues.payload.issueList.networks.length === 0\n && issues.payload.issueList.other.length === 0\n );\n\n return (\n \n Build Issues:\n \n {issues.status === API_STATUS.SUCCESS\n && (\n \n {Array.isArray(issues.payload.issueList.services)\n && issues.payload.issueList.services.length > 0\n && (\n \n \n Services:\n \n
    \n {issues.payload.issueList.services.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.networks)\n && issues.payload.issueList.networks.length > 0\n && (\n \n \n Networks:\n \n
    \n {issues.payload.issueList.networks.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues.payload.issueList.other)\n && issues.payload.issueList.other.length > 0\n && (\n \n \n Other Issues:\n \n
    \n {issues.payload.issueList.other.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {noIssues\n && (\n \n \n No build issues\n \n \n )}\n {!noIssues\n && (\n \n \n You can still attempt to build when issues are reported.\n \n \n )}\n {unknownError\n && (\n \n \n An unknown error occured retrieving build issues\n \n \n )}\n
\n )}\n {issues.status === API_STATUS.PENDING\n && (\n Loading...\n )}\n {issues.status === API_STATUS.FAILURE\n && (\n Failed to get build issues from API\n )}\n {issues.status === API_STATUS.UNINIT\n && (\n No changes detected\n )}\n
\n
\n );\n};\n\nconst buildList = (selectedServices) => {\n return (\n \n Building Services:\n \n {selectedServices.join(', ')}\n \n \n );\n};\n\nconst buildServices = (dispatchBuildStack) => {\n return (\n \n Build:\n \n \n \n \n );\n};\n\nconst Sidebar = (props) => {\n // const theme = useTheme();\n // const classes = useStyles({ props, theme });\n\n const mapStateToProps = (selector) => {\n return {\n configServiceMetadata: selector(state => state.configServiceMetadata),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues),\n buildStack: selector(state => state.buildStack),\n scriptTemplates: selector(state => state.scriptTemplates)\n };\n };\n const mapDispatchToProps = (dispatch) => {\n return {\n dispatchAddTagToHideList: (tag) => dispatch(addTagToHideListAction(tag)),\n dispatchRemoveTagFromHideList: (tag) => dispatch(removeTagFromHideListAction(tag)),\n dispatchBuildStack: (selectedServices, serviceConfigurations) => dispatch(createAndBuildStackAction(selectedServices, serviceConfigurations)),\n dispatchGetScriptTemplates: ({ scriptName, options, linkRef }) => dispatch(getScriptFromTemplateAction({ scriptName, options, linkRef })),\n dispatchDownloadBuildFile: ({ build, type, linkRef }) => dispatch(downloadBuildFile({ build, type, linkRef }))\n };\n };\n \n props = {\n ...props,\n ...mapStateToProps(useSelector),\n ...mapDispatchToProps(useDispatch()),\n };\n\n const [modalOpen, setModalOpen] = useState(false);\n useEffect(() => {\n if (props.buildStack.status === API_STATUS.SUCCESS) {\n setModalOpen(true);\n }\n }, [\n props.buildStack\n ]);\n\n const {\n serviceTemplateList,\n configServiceMetadata,\n selectedServices,\n buildIssues,\n hideServiceTags,\n dispatchRemoveTagFromHideList,\n dispatchAddTagToHideList,\n dispatchBuildStack,\n dispatchGetScriptTemplates,\n dispatchDownloadBuildFile,\n buildStack,\n scriptTemplates\n } = props;\n\n const downloadLinkRef = React.useRef(null);\n\n const handleBuildSelectChange = (evt, tagName) => {\n if (evt.target.checked) {\n return dispatchAddTagToHideList(tagName);\n }\n return dispatchRemoveTagFromHideList(tagName);\n };\n\n const serviceFilter = (serviceTemplateListPayload, servicesMetadata) => {\n return (\n \n Hide by tag:\n \n {\n getUniqueTagsFromTemplates({ serviceTemplateListPayload, metadataList: servicesMetadata }).map((tag) => {\n return (\n -1}\n onChange={(evt) => handleBuildSelectChange(evt, tag)}\n name=\"checkedB\"\n color=\"primary\"\n />\n }\n label={tag}\n />\n );\n })\n }\n \n \n );\n };\n \n return (\n \n
\n setModalOpen(false)}\n buildStack={buildStack}\n scriptTemplates={scriptTemplates}\n dispatchGetScriptTemplates={dispatchGetScriptTemplates}\n dispatchDownloadBuildFile={dispatchDownloadBuildFile}\n downloadLinkRef={downloadLinkRef}\n />\n \n {serviceFilter(serviceTemplateList.payload, configServiceMetadata.services.completed)}\n \n {buildIssuesRender(buildIssues)}\n \n {buildList(selectedServices.selectedServices)}\n \n {buildServices(() => {\n if (Array.isArray(selectedServices.selectedServices) && selectedServices.selectedServices.length > 0) {\n dispatchBuildStack(selectedServices.selectedServices);\n }\n })}\n \n \n );\n};\n\nexport default Sidebar;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx",["472","473","474","475"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Modal from '@material-ui/core/Modal';\nimport Grid from '@material-ui/core/Grid';\nimport Button from \"@material-ui/core/Button\";\nimport Box from '@material-ui/core/Box';\nimport getConfigComponents from '../../utils/configOptionLoader';\nimport {\n deleteTemporaryBuildOptions,\n saveTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst getModalStyle = () => {\n const top = 10;\n const left = 50;\n\n return {\n top: `${top}%`,\n left: `${left}%`,\n maxHeight: '75%',\n overflow: 'hidden',\n overflowY: 'scroll',\n transform: `translate(-50%, 0%)`,\n };\n};\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n position: 'absolute',\n width: '50%',\n backgroundColor: theme.palette.background.paper,\n border: '2px solid #000',\n boxShadow: theme.shadows[5],\n padding: theme.spacing(2, 4, 3),\n },\n}));\n\nconst ServiceConfigModal = (props) => {\n const {\n isOpen,\n handleClose,\n serviceName,\n networkTemplateList,\n serviceMetadata,\n serviceConfigOptions,\n buildOptions,\n serviceTemplates,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const closeModal = (event) => {\n deleteTemporaryBuildOptions();\n if (typeof handleClose === 'function') {\n handleClose(event);\n }\n }\n\n const classes = useStyles();\n const [modalStyle] = React.useState(getModalStyle);\n const body = (\n
\n

{serviceMetadata ? serviceMetadata.displayName : ''} ({serviceName}) Configuration

\n \n {getConfigComponents(serviceConfigOptions ?? []).map((ConfigComponent, index) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n \n \n \n \n \n \n
\n );\n\n return (\n \n {body}\n \n );\n};\n\nexport default ServiceConfigModal;","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx",[],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js",["476"],"import PortConfig from './general/portConfig';\nimport NetworkConfig from './general/networkConfig';\nimport Logging from './general/logging';\nimport Volumes from './general/volumesConfig';\n\nexport default {\n PortConfig,\n NetworkConfig,\n Logging,\n Volumes\n};\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx",["477","478","479","480","481","482","483","484","485","486"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n\nconst NetworkConfig = (props) => {\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n networkTemplateList,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [modifiedNetworkList, setModifiedNetworkList] = useState({});\n useEffect(() => {\n const defaultOnNetworks = { ...getBuildOptions()?.services?.[serviceName]?.networks ?? {} };\n serviceTemplates[serviceName]?.networks?.forEach((networkName) => {\n defaultOnNetworks[networkName] = true;\n });\n setModifiedNetworkList({\n ...defaultOnNetworks\n });\n }, []);\n\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n networks: modifiedNetworkList\n });\n }, [\n modifiedNetworkList\n ]);\n\n const onChangeCb = (networkName, event) => {\n const networkSelected = event.target.checked;\n setModifiedNetworkList({\n ...modifiedNetworkList,\n [networkName]: networkSelected\n });\n if (typeof(onChange) === 'function') {\n onChange(networkName, networkName);\n }\n };\n\n const defaultValue = (networkName) => {\n return (serviceTemplates[serviceName]?.networks ?? []).includes(networkName);\n };\n\n return (\n \n IOTstack Networks:\n \n {(networkTemplateList?.payload ?? []).map((networkName) => {\n return (\n \n onChangeCb(networkName, evt) }\n name={networkName}\n color=\"primary\"\n />\n }\n label={networkName}\n />\n \n );\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default NetworkConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx",["487","488","489","490","491","492","493","494","495","496"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Box from '@material-ui/core/Box';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [loggingEnabled, setLoggingEnabled] = useState(getBuildOptions()?.services?.[serviceName]?.loggingEnabled ?? true);\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n loggingEnabled\n });\n }, [\n loggingEnabled\n ]);\n\n const onChangeCb = (event) => {\n const newSetting = event.target.checked;\n setLoggingEnabled(newSetting);\n if (typeof(onChange) === 'function') {\n onChange(newSetting);\n }\n };\n\n return (\n \n \n onChangeCb(evt) }\n name={\"logging\"}\n color=\"primary\"\n />\n }\n label={`Enable Logging for ${serviceName}`}\n />\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx",["497","498","499","500","501","502","503"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getExternalPort,\n replaceExternalPort,\n getInternalPort\n} from '../../../utils/parsers';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [portSettings, setPortSettings] = useState(getBuildOptions()?.services?.[serviceName]?.ports || {});\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n ports: portSettings\n });\n }, [\n portSettings\n ]);\n\n const onChangeCb = (portKey, portLabelValue, event) => {\n const newPort = event.target.value;\n // const defaultTemplatePort = defaultValue(portKey, portKey);\n setPortSettings({\n ...portSettings,\n [portKey]: replaceExternalPort((portSettings[portKey] || portKey), newPort)\n });\n if (typeof(onChange) === 'function') {\n onChange(portKey, portLabelValue, newPort);\n }\n };\n\n const defaultValue = (portValueKey, defaultValue) => {\n const servicePorts = tempBuildOptions?.services?.[serviceName] ?? {};\n return servicePorts?.ports?.[portValueKey] ?? defaultValue;\n };\n\n return (\n \n \n {serviceConfigOptions && Object.keys(serviceConfigOptions.labeledPorts).map((portValueKey) => {\n const currentPortSetting = portSettings[portValueKey] || defaultValue(portValueKey, portValueKey);\n if ((serviceTemplates[serviceName]?.ports?.[portValueKey] ?? []).indexOf(portValueKey)) { // Only show ports that exist in the YAML template\n return (\n \n { onChangeCb(portValueKey, serviceConfigOptions.labeledPorts[portValueKey], event) }}\n value={getExternalPort(currentPortSetting)}\n />\n \n );\n }\n\n return null;\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default PortConfig;\n","/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx",["504","505","506","507","508","509","510","511","512","513","514","515","516"],"/c/Users/Slyke/Documents/repos/IOTstack/.internal/wui/src/utils/parsers.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/index.js",[],["517","518"],"/home/slyke/repos/IOTstack/.internal/wui/src/App.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/index.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/router.jsx",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/counter.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplateListReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceTemplatesReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getNetworkTemplateListReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceMetadataReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getServiceConfigOptionsReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/updateSelectedServicesReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/updateSelectedFilterTagsReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getBuildIssuesReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/buildStackReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getBuildHistoryListReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/getScriptTemplatesReducer.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/middlewares/promiseMiddleware.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/reducers/middlewares/asyncDispatchMiddleware.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/constants.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/pages/notFound/index.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/features/Sidebar/index.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceTemplateList.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceTemplates.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/getNetworkTemplateList.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceConfigOptions.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/getServiceMetadata.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/updateSelectedServices.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/updateFilterTags.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/checkBuildIssues.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/getBuildHistoryList.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/buildStack.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/actions/getScript.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/pages/mainBuild/index.jsx",["519"],"/home/slyke/repos/IOTstack/.internal/wui/src/pages/buildHistory/index.jsx",["520"],"/home/slyke/repos/IOTstack/.internal/wui/src/pages/scripts/index.jsx",[],"/home/slyke/repos/IOTstack/.internal/wui/src/pages/help/index.jsx",[],"/home/slyke/repos/IOTstack/.internal/wui/src/services/templates.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/services/configs.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/services/builds.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/utils/buildOptionSync.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/config.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/features/servicesGridItem/index.jsx",["521","522"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Skeleton from '@material-ui/lab/Skeleton';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Button from '@material-ui/core/Button';\nimport Link from '@material-ui/core/Link';\nimport ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\nimport ServiceConfigModal from '../serviceConfigModal';\nimport { useTheme } from '@material-ui/core/styles';\nimport {\n getBuildIssuesAction\n} from '../../actions/checkBuildIssues.action';\nimport {\n getServiceMetadataAction\n} from '../../actions/getServiceMetadata.action';\nimport {\n getServiceConfigOptionsAction\n} from '../../actions/getServiceConfigOptions.action';\nimport {\n addSelectedService,\n removeSelectedService\n} from '../../actions/updateSelectedServices.action';\nimport styles from './services-grid-item.module.css';\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n dispatchGetServiceMetadata: (serviceName) => dispatch(getServiceMetadataAction(serviceName)),\n dispatchGetServiceConfigOptions: (serviceName) => dispatch(getServiceConfigOptionsAction(serviceName)),\n dispatchGetBuildIssues: (selectedServices, serviceConfigurations) => dispatch(getBuildIssuesAction(selectedServices, serviceConfigurations)),\n dispatchAddSelectedService: (serviceName) => dispatch(addSelectedService(serviceName)),\n dispatchRemoveSelectedService: (serviceName) => dispatch(removeSelectedService(serviceName))\n };\n};\n\nconst mapStateToProps = (selector) => {\n return {\n templateList: selector(state => state.templateList),\n configServiceMetadata: selector(state => state.configServiceMetadata),\n configServiceConfigOptions: selector(state => state.configServiceConfigOptions),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues)\n };\n};\n\nconst useStyles = makeStyles({\n serviceCard: {\n \"&:hover\": {\n borderColor: ({ theme }) => theme.palette.text.primary\n }\n }\n});\n\nconst ServiceItem = (props) => {\n const theme = useTheme();\n const classes = useStyles({ props, theme });\n // console.log('theme.palette', theme.palette)\n props = {\n ...props,\n ...mapDispatchToProps(useDispatch()),\n ...mapStateToProps(useSelector)\n };\n\n const {\n serviceName,\n networkTemplateList,\n serviceTemplates,\n dispatchGetServiceMetadata,\n dispatchGetServiceConfigOptions,\n dispatchAddSelectedService,\n dispatchRemoveSelectedService,\n dispatchGetBuildIssues,\n configServiceMetadata,\n configServiceConfigOptions,\n selectedServices,\n hideServiceTags,\n buildIssues,\n buildOptions,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const [isLoading, setIsLoading] = useState(false);\n const [serviceMetadata, setServiceMetadata] = useState({});\n const [serviceMetadataError, setServiceMetadataError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceMetadata.services.completed[serviceName] === 'undefined'\n && typeof configServiceMetadata.services.failed[serviceName] === 'undefined'\n && !configServiceMetadata.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceMetadata(serviceName);\n }\n\n setIsLoading(false);\n\n if (typeof configServiceMetadata.services.completed[serviceName] === 'object') {\n setServiceMetadata(configServiceMetadata.services.completed[serviceName].payload);\n } else if (!configServiceMetadata.services.pending.includes(serviceName)) {\n setServiceMetadataError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceMetadata,\n configServiceMetadata.services.completed,\n configServiceMetadata.services.pending,\n configServiceMetadata.services.failed\n ]);\n\n const [serviceConfigOptions, setServiceConfigOptions] = useState({});\n const [serviceConfigOptionsError, setServiceConfigOptionsError] = useState({});\n useEffect(() => {\n if (\n typeof configServiceConfigOptions.services.completed[serviceName] === 'undefined'\n && typeof configServiceConfigOptions.services.failed[serviceName] === 'undefined'\n && !configServiceConfigOptions.services.pending.includes(serviceName)\n && !isLoading\n ) {\n setIsLoading(true);\n return void dispatchGetServiceConfigOptions(serviceName);\n }\n\n // setIsLoading(false);\n\n if (typeof configServiceConfigOptions.services.completed[serviceName] === 'object') {\n setServiceConfigOptions(configServiceConfigOptions.services.completed[serviceName].payload);\n } else if (!configServiceConfigOptions.services.pending.includes(serviceName)) {\n setServiceConfigOptionsError({\n hasError: true\n });\n }\n }, [\n isLoading,\n serviceName,\n dispatchGetServiceConfigOptions,\n configServiceConfigOptions.services.completed,\n configServiceConfigOptions.services.pending,\n configServiceConfigOptions.services.failed\n ]);\n\n const [updated, setIsUpdated] = useState(false);\n useEffect(() => {\n if (updated) {\n dispatchGetBuildIssues(selectedServices.selectedServices, getBuildOptions());\n }\n setIsUpdated(false);\n }, [\n updated,\n serviceName,\n selectedServices.selectedServices,\n dispatchGetBuildIssues\n ]);\n\n const [hasIssue, setHasIssue] = useState(false);\n useEffect(() => {\n if (!selectedServices.selectedServices.includes(serviceName)) {\n return void setHasIssue(false);\n }\n const issueList = buildIssues?.payload?.issueList ?? {};\n if (Array.isArray(issueList.services)) {\n issueList.services.forEach((service) => {\n if (service.name === serviceName) {\n return void setHasIssue(true);\n }\n });\n }\n }, [buildIssues, selectedServices.selectedServices, serviceName]);\n\n const handleBuildSelectChange = (evt) => {\n setIsUpdated(true);\n if (evt.target.checked) {\n return dispatchAddSelectedService(serviceName);\n }\n return dispatchRemoveSelectedService(serviceName);\n }\n\n const [modalOpen, setModalOpen] = useState(false);\n\n const serviceComponent = () => {\n return (\n \n setModalOpen(false)}\n serviceMetadata={serviceMetadata}\n serviceConfigOptions={serviceConfigOptions}\n serviceName={serviceName}\n buildOptions={buildOptions}\n setBuildOptions={setBuildOptions}\n setServiceOptions={setServiceOptions}\n getBuildOptions={getBuildOptions}\n buildOptionsInit={buildOptionsInit}\n setTemporaryBuildOptions={setTemporaryBuildOptions}\n getTemporaryBuildOptions={getTemporaryBuildOptions}\n setTemporaryServiceOptions={setTemporaryServiceOptions}\n setupTemporaryBuildOptions={setupTemporaryBuildOptions}\n saveTemporaryBuildOptions={saveTemporaryBuildOptions}\n networkTemplateList={networkTemplateList}\n serviceTemplates={serviceTemplates}\n />\n \n {serviceMetadata.displayName}\n \n \n {!serviceMetadata.iconUri\n && (\n \n \n \n )}\n {serviceMetadata.iconUri\n && (\n \n
\n {`${serviceMetadata.displayName}\n
\n
\n )}\n
\n \n { setTemporaryBuildOptions(buildOptions); setModalOpen(true); }}\n className={`${styles.configButton}`}\n >\n {serviceMetadata.displayName} Configuration\n \n \n \n \n }\n label={`Add ${serviceMetadata.displayName} to build`}\n />\n \n \n \n {serviceMetadata.displayName} Help and Docs\n \n \n \n )\n };\n\n const errorComponent = () => {\n return (\n \n
Error loading: {serviceName}
\n
Try refreshing, and ensuring the API server is running correctly.
\n
\n )\n };\n\n const loadingComponent = () => {\n return (\n \n Loading '{serviceName}' metadata...\n \n \n \n \n \n \n \n \n \n \n \n \n \n )\n };\n\n const highlightClass = () => {\n if (selectedServices.selectedServices.includes(serviceName)) {\n if (hasIssue) {\n return styles.serviceError;\n } else {\n return styles.selectedForBuild;\n }\n }\n\n return '';\n };\n\n const tagIsHidden = (hiddenTags, serviceTags) => {\n let hide = false;\n\n hiddenTags.forEach((hiddenTag) => {\n serviceTags.forEach((serviceTag) => {\n if (hiddenTag === serviceTag) {\n hide = true;\n }\n });\n });\n\n return hide;\n }\n\n if (!isLoading && tagIsHidden(hideServiceTags.hideServiceTags, serviceMetadata.serviceTypeTags)) {\n return null;\n }\n\n return (\n \n \n {isLoading\n && (loadingComponent())}\n {!isLoading\n && serviceMetadata.displayName\n && (\n serviceComponent()\n )}\n {!isLoading\n && serviceMetadataError.hasError === true\n && (\n errorComponent()\n )}\n \n \n );\n};\n\nexport default ServiceItem;\n","/home/slyke/repos/IOTstack/.internal/wui/src/features/buildHistoryGridItem/index.jsx",[],"/home/slyke/repos/IOTstack/.internal/wui/src/features/BuildSidebar/index.jsx",["523","524"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { useDispatch, useSelector } from \"react-redux\";\nimport Box from '@material-ui/core/Box';\n// import Tooltip from '@material-ui/core/Tooltip';\nimport Button from '@material-ui/core/Button';\n// import ErrorOutlineOutlinedIcon from '@material-ui/icons/ErrorOutlineOutlined';\nimport Divider from '@material-ui/core/Divider';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\n// import { makeStyles, useTheme } from '@material-ui/core/styles';\nimport styles from './build-sidebar.module.css';\nimport {\n addTagToHideListAction,\n removeTagFromHideListAction\n} from '../../actions/updateFilterTags.action';\nimport {\n createAndBuildStackAction\n} from '../../actions/buildStack.action';\nimport {\n getScriptFromTemplateAction\n} from '../../actions/getScript.action';\nimport {\n downloadBuildFile\n} from '../../actions/downloadBuild.action';\nimport BuildCompletedModal from '../buildCompletedModal';\nimport { API_STATUS } from '../../constants';\nimport { getBuildOptions } from '../../utils/buildOptionSync';\n\n// const useStyles = makeStyles({\n// serviceCard: {\n// \"&:hover\": {\n// borderColor: ({ theme }) => theme.palette.text.primary\n// }\n// }\n// });\n\nconst getUniqueTagsFromTemplates = ({ serviceTemplateListPayload, metadataList }) => {\n const tagList = [];\n if (Array.isArray(serviceTemplateListPayload)) {\n serviceTemplateListPayload.forEach((service) => {\n if (metadataList[service] && metadataList[service].payload && Array.isArray(metadataList[service].payload.serviceTypeTags)) {\n metadataList[service].payload.serviceTypeTags.forEach((tag) => {\n if (!tagList.includes(tag)) {\n tagList.push(tag);\n }\n });\n }\n });\n }\n tagList.sort();\n return tagList;\n};\n\nconst buildIssueListItem = (name, issueType, issueText) => {\n return (\n {name} [{issueType}] - {issueText}\n );\n};\n\nconst buildIssuesRender = (issues) => {\n const unknownError = !(\n issues.payload\n && issues.payload.issueList\n && Array.isArray(issues.payload.issueList.services)\n && Array.isArray(issues.payload.issueList.networks)\n && Array.isArray(issues.payload.issueList.other)\n );\n\n const noIssues = (\n !unknownError\n && issues.payload.issueList.services.length === 0\n && issues.payload.issueList.networks.length === 0\n && issues.payload.issueList.other.length === 0\n );\n\n return (\n \n Build Issues:\n \n {issues.status === API_STATUS.SUCCESS\n && (\n \n {Array.isArray(issues?.payload?.issueList?.services)\n && (issues?.payload?.issueList?.services?.length ?? 0) > 0\n && (\n \n \n Services:\n \n
    \n {issues.payload.issueList.services.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues?.payload?.issueList?.networks)\n && (issues?.payload?.issueList?.networks?.length ?? 0) > 0\n && (\n \n \n Networks:\n \n
    \n {(issues?.payload?.issueList?.networks ?? []).map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {Array.isArray(issues?.payload?.issueList?.other)\n && (issues?.payload?.issueList?.other?.length ?? 0) > 0\n && (\n \n \n Other Issues:\n \n
    \n {issues.payload.issueList.other.map((issue) => {\n return (\n
  • \n {buildIssueListItem(issue.name, issue.issueType, issue.message)}\n
  • \n )\n })}\n
\n
\n
\n
\n )}\n {noIssues\n && (\n \n \n No build issues\n \n \n )}\n {!noIssues\n && (\n \n \n You can still attempt to build when issues are reported.\n \n \n )}\n {unknownError\n && (\n \n \n An unknown error occured retrieving build issues\n \n \n )}\n
\n )}\n {issues.status === API_STATUS.PENDING\n && (\n Loading...\n )}\n {issues.status === API_STATUS.FAILURE\n && (\n Failed to get build issues from API\n )}\n {issues.status === API_STATUS.UNINIT\n && (\n No changes detected\n )}\n
\n
\n );\n};\n\nconst buildList = (selectedServices) => {\n return (\n \n Building Services:\n \n {selectedServices.join(', ')}\n \n \n );\n};\n\nconst buildServices = (dispatchBuildStack) => {\n return (\n \n Build:\n \n \n \n \n );\n};\n\nconst Sidebar = (props) => {\n // const theme = useTheme();\n // const classes = useStyles({ props, theme });\n\n const mapStateToProps = (selector) => {\n return {\n configServiceMetadata: selector(state => state.configServiceMetadata),\n hideServiceTags: selector(state => state.hideServiceTags),\n selectedServices: selector(state => state.selectedServices),\n buildIssues: selector(state => state.buildIssues),\n buildStack: selector(state => state.buildStack),\n scriptTemplates: selector(state => state.scriptTemplates)\n };\n };\n const mapDispatchToProps = (dispatch) => {\n return {\n dispatchAddTagToHideList: (tag) => dispatch(addTagToHideListAction(tag)),\n dispatchRemoveTagFromHideList: (tag) => dispatch(removeTagFromHideListAction(tag)),\n dispatchBuildStack: (selectedServices, serviceConfigurations) => dispatch(createAndBuildStackAction(selectedServices, serviceConfigurations)),\n dispatchGetScriptTemplates: ({ scriptName, options, linkRef }) => dispatch(getScriptFromTemplateAction({ scriptName, options, linkRef })),\n dispatchDownloadBuildFile: ({ build, type, linkRef }) => dispatch(downloadBuildFile({ build, type, linkRef }))\n };\n };\n \n props = {\n ...props,\n ...mapStateToProps(useSelector),\n ...mapDispatchToProps(useDispatch()),\n };\n\n const [modalOpen, setModalOpen] = useState(false);\n useEffect(() => {\n if (props.buildStack.status === API_STATUS.SUCCESS) {\n setModalOpen(true);\n }\n }, [\n props.buildStack\n ]);\n\n const {\n serviceTemplateList,\n configServiceMetadata,\n selectedServices,\n buildIssues,\n hideServiceTags,\n dispatchRemoveTagFromHideList,\n dispatchAddTagToHideList,\n dispatchBuildStack,\n dispatchGetScriptTemplates,\n dispatchDownloadBuildFile,\n buildStack,\n scriptTemplates\n } = props;\n\n const downloadLinkRef = React.useRef(null);\n\n const handleBuildSelectChange = (evt, tagName) => {\n if (evt.target.checked) {\n return dispatchAddTagToHideList(tagName);\n }\n return dispatchRemoveTagFromHideList(tagName);\n };\n\n const serviceFilter = (serviceTemplateListPayload, servicesMetadata) => {\n return (\n \n Hide by tag:\n \n {\n getUniqueTagsFromTemplates({ serviceTemplateListPayload, metadataList: servicesMetadata }).map((tag) => {\n return (\n -1}\n onChange={(evt) => handleBuildSelectChange(evt, tag)}\n name=\"checkedB\"\n color=\"primary\"\n />\n }\n label={tag}\n />\n );\n })\n }\n \n \n );\n };\n \n return (\n \n
\n setModalOpen(false)}\n buildStack={buildStack}\n scriptTemplates={scriptTemplates}\n dispatchGetScriptTemplates={dispatchGetScriptTemplates}\n dispatchDownloadBuildFile={dispatchDownloadBuildFile}\n downloadLinkRef={downloadLinkRef}\n />\n \n {serviceFilter(serviceTemplateList.payload, configServiceMetadata.services.completed)}\n \n {buildIssuesRender(buildIssues)}\n \n {buildList(selectedServices.selectedServices)}\n \n {buildServices(() => {\n if (Array.isArray(selectedServices.selectedServices) && selectedServices.selectedServices.length > 0) {\n dispatchBuildStack(selectedServices.selectedServices, getBuildOptions());\n }\n })}\n \n \n );\n};\n\nexport default Sidebar;\n","/home/slyke/repos/IOTstack/.internal/wui/src/actions/downloadBuild.action.js",[],"/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceConfigModal/index.jsx",["525","526","527"],"import React, { Fragment, useState, useEffect } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Modal from '@material-ui/core/Modal';\nimport Grid from '@material-ui/core/Grid';\nimport Button from \"@material-ui/core/Button\";\nimport Box from '@material-ui/core/Box';\nimport getConfigComponents from '../../utils/configOptionLoader';\nimport {\n deleteTemporaryBuildOptions\n} from '../../utils/buildOptionSync';\n\nconst getModalStyle = () => {\n const top = 10;\n const left = 50;\n\n return {\n top: `${top}%`,\n left: `${left}%`,\n maxHeight: '75%',\n overflow: 'hidden',\n overflowY: 'scroll',\n transform: `translate(-50%, 0%)`,\n };\n};\n\nconst useStyles = makeStyles((theme) => ({\n paper: {\n position: 'absolute',\n width: '50%',\n backgroundColor: theme.palette.background.paper,\n border: '2px solid #000',\n boxShadow: theme.shadows[5],\n padding: theme.spacing(2, 4, 3),\n },\n}));\n\nconst ServiceConfigModal = (props) => {\n const {\n isOpen,\n handleClose,\n serviceName,\n networkTemplateList,\n serviceMetadata,\n serviceConfigOptions,\n buildOptions,\n serviceTemplates,\n setBuildOptions,\n getBuildOptions,\n buildOptionsInit,\n setServiceOptions,\n setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n setupTemporaryBuildOptions,\n saveTemporaryBuildOptions\n } = props;\n\n const closeModal = (event) => {\n deleteTemporaryBuildOptions();\n if (typeof handleClose === 'function') {\n handleClose(event);\n }\n }\n\n const classes = useStyles();\n const [modalStyle] = React.useState(getModalStyle);\n const body = (\n
\n

{serviceMetadata ? serviceMetadata.displayName : ''} ({serviceName}) Configuration

\n \n {getConfigComponents(serviceConfigOptions ?? []).map((ConfigComponent, index) => {\n return (\n \n \n \n );\n })}\n \n \n \n \n \n \n \n \n \n \n \n \n
\n );\n\n return (\n \n {body}\n \n );\n};\n\nexport default ServiceConfigModal;","/home/slyke/repos/IOTstack/.internal/wui/src/features/buildCompletedModal/index.jsx",[],"/home/slyke/repos/IOTstack/.internal/wui/src/utils/configOptionLoader.jsx",[],"/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/index.js",["528"],"import PortConfig from './general/portConfig';\nimport NetworkConfig from './general/networkConfig';\nimport Logging from './general/logging';\nimport Volumes from './general/volumesConfig';\nimport Devices from './general/devicesConfig';\nimport Environment from './general/environmentConfig';\n\nexport default {\n PortConfig,\n NetworkConfig,\n Logging,\n Volumes,\n Devices,\n Environment\n};\n","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/portConfig.jsx",["529"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getExternalPort,\n replaceExternalPort,\n getInternalPort\n} from '../../../utils/parsers';\n\nconst PortConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n // setBuildOptions,\n getBuildOptions,\n // buildOptionsInit,\n // setServiceOptions,\n // setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n // setupTemporaryBuildOptions,\n // saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n\n const [portSettings, setPortSettings] = useState(getBuildOptions()?.services?.[serviceName]?.ports || {});\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n ports: portSettings\n });\n }, [\n portSettings\n ]);\n\n const onChangeCb = (portKey, portLabelValue, event) => {\n const newPort = event.target.value;\n // const defaultTemplatePort = defaultValue(portKey, portKey);\n setPortSettings({\n ...portSettings,\n [portKey]: replaceExternalPort((portSettings[portKey] || portKey), newPort)\n });\n if (typeof(onChange) === 'function') {\n onChange(portKey, portLabelValue, newPort);\n }\n };\n\n const defaultValue = (portValueKey, defaultValue) => {\n const servicePorts = tempBuildOptions?.services?.[serviceName] ?? {};\n return servicePorts?.ports?.[portValueKey] ?? defaultValue;\n };\n\n return (\n \n \n {serviceConfigOptions && Object.keys(serviceConfigOptions.labeledPorts).map((portValueKey) => {\n const currentPortSetting = portSettings[portValueKey] || defaultValue(portValueKey, portValueKey);\n if ((serviceTemplates[serviceName]?.ports?.[portValueKey] ?? []).indexOf(portValueKey)) { // Only show ports that exist in the YAML template\n return (\n \n { onChangeCb(portValueKey, serviceConfigOptions.labeledPorts[portValueKey], event) }}\n value={getExternalPort(currentPortSetting)}\n />\n \n );\n }\n\n return null;\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default PortConfig;\n","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/networkConfig.jsx",["530","531","532"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Box from '@material-ui/core/Box';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\n\nconst NetworkConfig = (props) => {\n const {\n // serviceConfigOptions,\n serviceName,\n // setBuildOptions,\n getBuildOptions,\n // buildOptionsInit,\n // setServiceOptions,\n networkTemplateList,\n // setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n // setupTemporaryBuildOptions,\n // saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n // const tempBuildOptions = getTemporaryBuildOptions();\n const [networkMode, setNetworkMode] = useState({});\n\n const [modifiedNetworkList, setModifiedNetworkList] = useState({});\n useEffect(() => {\n const defaultOnNetworks = { ...getBuildOptions()?.services?.[serviceName]?.networks ?? {} };\n serviceTemplates[serviceName]?.networks?.forEach((networkName) => {\n defaultOnNetworks[networkName] = true;\n });\n setModifiedNetworkList({\n ...defaultOnNetworks\n });\n\n const templateNetworkMode = serviceTemplates?.[serviceName]?.['network-mode'];\n const calculatedNetworkMode = Object.keys(defaultOnNetworks).length > 0 ? 'bridge' : 'host';\n\n const toNetworkMode = getBuildOptions()?.services?.[serviceName]?.networkMode ?? templateNetworkMode ?? calculatedNetworkMode;\n setNetworkMode(toNetworkMode);\n }, []);\n\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n networks: modifiedNetworkList\n });\n }, [\n modifiedNetworkList\n ]);\n\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n networkMode: networkMode\n });\n }, [\n networkMode\n ]);\n\n const onChangeCb = (event, changeType, networkName) => {\n if (changeType === 'mode') {\n const newMode = event.target.checked;\n setNetworkMode(newMode);\n if (typeof(onChange) === 'function') {\n onChange(event, changeType);\n }\n } else if (changeType === 'network') {\n const networkSelected = event.target.checked;\n setModifiedNetworkList({\n ...modifiedNetworkList,\n [networkName]: networkSelected\n });\n if (typeof(onChange) === 'function') {\n onChange(networkName, networkSelected, changeType);\n }\n } else {\n \n if (typeof(onChange) === 'function') {\n onChange(event, changeType, networkName);\n }\n }\n };\n\n const defaultValue = (networkName) => {\n return (serviceTemplates[serviceName]?.networks ?? []).includes(networkName);\n };\n\n return (\n \n \n \n IOTstack Networks:\n \n \n \n Mode:\n onChangeCb(evt, 'mode')}\n >\n Unchanged\n Host\n Bridge\n Overlay\n MAC-VLAN\n No Networking\n \n \n \n \n \n {(networkTemplateList?.payload ?? []).map((networkName) => {\n return (\n \n onChangeCb(evt, 'network', networkName) }\n name={networkName}\n color=\"primary\"\n />\n }\n label={networkName}\n />\n \n );\n }).filter((ele) => {\n return ele !== null;\n })}\n \n \n );\n};\n\nexport default NetworkConfig;\n","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/logging.jsx",["533"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Box from '@material-ui/core/Box';\n\nconst PortConfig = (props) => {\n\n const {\n // serviceConfigOptions,\n serviceName,\n // setBuildOptions,\n getBuildOptions,\n // buildOptionsInit,\n // setServiceOptions,\n // setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n // setupTemporaryBuildOptions,\n // saveTemporaryBuildOptions,\n // serviceTemplates,\n onChange\n } = props;\n\n // const tempBuildOptions = getTemporaryBuildOptions();\n\n const [loggingEnabled, setLoggingEnabled] = useState(getBuildOptions()?.services?.[serviceName]?.loggingEnabled ?? true);\n useEffect(() => {\n setTemporaryServiceOptions(serviceName, {\n ...getTemporaryBuildOptions()?.services?.[serviceName] ?? {},\n loggingEnabled\n });\n }, [\n loggingEnabled\n ]);\n\n const onChangeCb = (event) => {\n const newSetting = event.target.checked;\n setLoggingEnabled(newSetting);\n if (typeof(onChange) === 'function') {\n onChange(newSetting);\n }\n };\n\n return (\n \n \n onChangeCb(evt) }\n name={\"logging\"}\n color=\"primary\"\n />\n }\n label={`Enable Logging for ${serviceName}`}\n />\n \n \n );\n};\n\nexport default PortConfig;\n","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/volumesConfig.jsx",["534","535"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getExternalVolume,\n getInternalVolume,\n replaceExternalVolume\n} from '../../../utils/parsers';\n\nconst VolumesConfig = (props) => {\n\n const {\n // serviceConfigOptions,\n serviceName,\n // setBuildOptions,\n getBuildOptions,\n // buildOptionsInit,\n // setServiceOptions,\n // setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n // setupTemporaryBuildOptions,\n // saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n const yamlVolumeSettings = serviceTemplates?.[serviceName]?.volumes || [];\n\n const [volumeSettings, setVolumeSettings] = useState(yamlVolumeSettings);\n const [loaded, setLoaded] = useState(false);\n useEffect(() => {\n if ((getBuildOptions().services?.[serviceName]?.volumes?.length ?? 0) < 1 ) {\n setTemporaryServiceOptions(serviceName, {\n ...getBuildOptions().services?.[serviceName] ?? {},\n volumes: yamlVolumeSettings\n });\n } else {\n setVolumeSettings(getBuildOptions().services?.[serviceName]?.volumes);\n }\n setLoaded(true);\n }, []);\n\n useEffect(() => {\n if (loaded) {\n setTemporaryServiceOptions(serviceName, {\n ...tempBuildOptions?.services?.[serviceName] ?? {},\n volumes: volumeSettings\n });\n }\n }, [\n volumeSettings\n ]);\n\n const onChangeCb = (internalVolume, event) => {\n const newExternalVolumePath = event.target.value;\n const temporaryVolumes = [...volumeSettings];\n \n const volumeIndex = temporaryVolumes.findIndex((index) => {\n return getInternalVolume(index) === internalVolume;\n });\n \n if (volumeIndex > -1) {\n temporaryVolumes[volumeIndex] = replaceExternalVolume(temporaryVolumes[volumeIndex], newExternalVolumePath);\n }\n\n setVolumeSettings(temporaryVolumes);\n if (typeof(onChange) === 'function') {\n onChange(internalVolume, newExternalVolumePath);\n }\n };\n\n return (\n \n \n {volumeSettings.map((volume) => {\n const internalVolume = getInternalVolume(volume);\n const currentExternalVolume = getExternalVolume(volume);\n\n return (\n \n { onChangeCb(internalVolume, event) }}\n value={currentExternalVolume}\n style={{ width: '100%' }}\n />\n \n );\n })}\n \n \n );\n};\n\nexport default VolumesConfig;\n","/home/slyke/repos/IOTstack/.internal/wui/src/utils/parsers.js",[],["536","537"],"/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/environmentConfig.jsx",["538","539"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\nimport {\n getEnvironmentKey,\n getEnvironmentValue\n} from '../../../utils/parsers';\n\nconst VolumesConfig = (props) => {\n\n const {\n serviceConfigOptions,\n serviceName,\n // setBuildOptions,\n getBuildOptions,\n // buildOptionsInit,\n // setServiceOptions,\n // setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n // setupTemporaryBuildOptions,\n // saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n const yamlEnvironmentSettings = serviceTemplates?.[serviceName]?.environment || [];\n\n const [environmentSettings, setEnvironmentSettings] = useState(yamlEnvironmentSettings);\n const [loaded, setLoaded] = useState(false);\n useEffect(() => {\n // Check if there's a default value set in configs, and use it if so.\n const envBuildDefaultOptions = serviceConfigOptions?.modifyableEnvironment ?? [];\n const defaultEnvSettings = yamlEnvironmentSettings.map((envKV) => {\n const envKey = getEnvironmentKey(envKV);\n const defaultKV = envBuildDefaultOptions.find((modObj) => {\n return modObj.key === envKey;\n });\n\n if (defaultKV) {\n return `${envKey}=${defaultKV.value}`;\n }\n return envKV;\n });\n\n // Load options from persistant state\n if ((getBuildOptions().services?.[serviceName]?.environment?.length ?? 0) < 1 ) {\n setTemporaryServiceOptions(serviceName, {\n ...getBuildOptions().services?.[serviceName] ?? {},\n environment: defaultEnvSettings\n });\n setEnvironmentSettings(defaultEnvSettings);\n } else {\n setEnvironmentSettings(getBuildOptions().services?.[serviceName]?.environment);\n }\n setLoaded(true);\n }, []);\n\n useEffect(() => {\n if (loaded) {\n setTemporaryServiceOptions(serviceName, {\n ...tempBuildOptions?.services?.[serviceName] ?? {},\n environment: environmentSettings\n });\n }\n }, [\n environmentSettings\n ]);\n\n const onChangeCb = (environmentKey, event) => {\n const newEnvironmentValue = event.target.value;\n const temporaryEnvironment = [...environmentSettings];\n \n const environmentIndex = temporaryEnvironment.findIndex((index) => {\n return getEnvironmentKey(index) === environmentKey;\n });\n \n if (environmentIndex > -1) {\n temporaryEnvironment[environmentIndex] = `${environmentKey}=${newEnvironmentValue}`\n }\n\n setEnvironmentSettings(temporaryEnvironment);\n if (typeof(onChange) === 'function') {\n onChange(environmentKey, newEnvironmentValue);\n }\n };\n\n return (\n \n \n {environmentSettings.map((environmentKeyValue) => {\n const environmentKey = getEnvironmentKey(environmentKeyValue);\n const environmentValue = getEnvironmentValue(environmentKeyValue);\n\n return (\n \n { onChangeCb(environmentKey, event) }}\n value={environmentValue}\n style={{ width: '100%' }}\n />\n \n );\n })}\n \n \n );\n};\n\nexport default VolumesConfig;\n","/home/slyke/repos/IOTstack/.internal/wui/src/features/serviceUiControls/general/devicesConfig.jsx",["540","541"],"import React, { Fragment, useState, useEffect } from 'react';\n// import Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TextField from '@material-ui/core/TextField';\n\nconst DevicessConfig = (props) => {\n\n const {\n // serviceConfigOptions,\n serviceName,\n // setBuildOptions,\n getBuildOptions,\n // buildOptionsInit,\n // setServiceOptions,\n // setTemporaryBuildOptions,\n getTemporaryBuildOptions,\n setTemporaryServiceOptions,\n // setupTemporaryBuildOptions,\n // saveTemporaryBuildOptions,\n serviceTemplates,\n onChange\n } = props;\n\n const tempBuildOptions = getTemporaryBuildOptions();\n const yamlDevicesSettings = serviceTemplates?.[serviceName]?.devices || [];\n\n const [devicesSettings, setDevicesSettings] = useState(yamlDevicesSettings);\n const [loaded, setLoaded] = useState(false);\n useEffect(() => {\n if ((getBuildOptions().services?.[serviceName]?.devices?.length ?? 0) < 1 ) {\n setTemporaryServiceOptions(serviceName, {\n ...getBuildOptions().services?.[serviceName] ?? {},\n devices: yamlDevicesSettings\n });\n } else {\n setDevicesSettings(getBuildOptions().services?.[serviceName]?.devices);\n }\n setLoaded(true);\n }, []);\n\n useEffect(() => {\n if (loaded) {\n setTemporaryServiceOptions(serviceName, {\n ...tempBuildOptions?.services?.[serviceName] ?? {},\n devices: devicesSettings\n });\n }\n }, [\n devicesSettings\n ]);\n\n const onChangeCb = (oldDevice, event) => {\n const newDevice = event.target.value;\n const temporaryDevices = [...devicesSettings];\n \n const devicesIndex = temporaryDevices.findIndex((device) => {\n return oldDevice === device;\n });\n\n if (devicesIndex > -1) {\n temporaryDevices[devicesIndex] = newDevice;\n }\n\n setDevicesSettings(temporaryDevices);\n if (typeof(onChange) === 'function') {\n onChange(oldDevice, newDevice);\n }\n };\n\n return (\n \n \n {devicesSettings.map((device, index) => {\n\n return (\n \n { onChangeCb(device, event) }}\n value={device}\n style={{ width: '100%' }}\n />\n \n );\n })}\n \n \n );\n};\n\nexport default DevicessConfig;\n",{"ruleId":"542","replacedBy":"543"},{"ruleId":"544","replacedBy":"545"},{"ruleId":"546","severity":1,"message":"547","line":60,"column":6,"nodeType":"548","endLine":60,"endColumn":8,"suggestions":"549"},{"ruleId":"546","severity":1,"message":"550","line":34,"column":6,"nodeType":"548","endLine":34,"endColumn":8,"suggestions":"551"},{"ruleId":"552","severity":1,"message":"553","line":127,"column":10,"nodeType":"554","messageId":"555","endLine":127,"endColumn":35},{"ruleId":"556","severity":1,"message":"557","line":300,"column":7,"nodeType":"558","endLine":300,"endColumn":34},{"ruleId":"559","severity":1,"message":"560","line":300,"column":7,"nodeType":"558","endLine":300,"endColumn":34},{"ruleId":"552","severity":1,"message":"561","line":1,"column":27,"nodeType":"554","messageId":"555","endLine":1,"endColumn":35},{"ruleId":"552","severity":1,"message":"562","line":1,"column":37,"nodeType":"554","messageId":"555","endLine":1,"endColumn":46},{"ruleId":"552","severity":1,"message":"563","line":10,"column":3,"nodeType":"554","messageId":"555","endLine":10,"endColumn":28},{"ruleId":"552","severity":1,"message":"564","line":46,"column":5,"nodeType":"554","messageId":"555","endLine":46,"endColumn":17},{"ruleId":"565","severity":1,"message":"566","line":6,"column":1,"nodeType":"567","endLine":11,"endColumn":3},{"ruleId":"552","severity":1,"message":"568","line":9,"column":5,"nodeType":"554","messageId":"555","endLine":9,"endColumn":25},{"ruleId":"552","severity":1,"message":"569","line":11,"column":5,"nodeType":"554","messageId":"555","endLine":11,"endColumn":20},{"ruleId":"552","severity":1,"message":"570","line":13,"column":5,"nodeType":"554","messageId":"555","endLine":13,"endColumn":21},{"ruleId":"552","severity":1,"message":"571","line":14,"column":5,"nodeType":"554","messageId":"555","endLine":14,"endColumn":22},{"ruleId":"552","severity":1,"message":"572","line":16,"column":5,"nodeType":"554","messageId":"555","endLine":16,"endColumn":29},{"ruleId":"552","severity":1,"message":"573","line":19,"column":5,"nodeType":"554","messageId":"555","endLine":19,"endColumn":31},{"ruleId":"552","severity":1,"message":"574","line":20,"column":5,"nodeType":"554","messageId":"555","endLine":20,"endColumn":30},{"ruleId":"552","severity":1,"message":"575","line":25,"column":9,"nodeType":"554","messageId":"555","endLine":25,"endColumn":25},{"ruleId":"546","severity":1,"message":"576","line":36,"column":6,"nodeType":"548","endLine":36,"endColumn":8,"suggestions":"577"},{"ruleId":"546","severity":1,"message":"578","line":43,"column":6,"nodeType":"548","endLine":45,"endColumn":4,"suggestions":"579"},{"ruleId":"552","severity":1,"message":"568","line":10,"column":5,"nodeType":"554","messageId":"555","endLine":10,"endColumn":25},{"ruleId":"552","severity":1,"message":"569","line":12,"column":5,"nodeType":"554","messageId":"555","endLine":12,"endColumn":20},{"ruleId":"552","severity":1,"message":"570","line":14,"column":5,"nodeType":"554","messageId":"555","endLine":14,"endColumn":21},{"ruleId":"552","severity":1,"message":"571","line":15,"column":5,"nodeType":"554","messageId":"555","endLine":15,"endColumn":22},{"ruleId":"552","severity":1,"message":"572","line":16,"column":5,"nodeType":"554","messageId":"555","endLine":16,"endColumn":29},{"ruleId":"552","severity":1,"message":"573","line":19,"column":5,"nodeType":"554","messageId":"555","endLine":19,"endColumn":31},{"ruleId":"552","severity":1,"message":"574","line":20,"column":5,"nodeType":"554","messageId":"555","endLine":20,"endColumn":30},{"ruleId":"552","severity":1,"message":"580","line":21,"column":5,"nodeType":"554","messageId":"555","endLine":21,"endColumn":21},{"ruleId":"552","severity":1,"message":"575","line":25,"column":9,"nodeType":"554","messageId":"555","endLine":25,"endColumn":25},{"ruleId":"546","severity":1,"message":"578","line":33,"column":6,"nodeType":"548","endLine":35,"endColumn":4,"suggestions":"581"},{"ruleId":"552","severity":1,"message":"569","line":16,"column":5,"nodeType":"554","messageId":"555","endLine":16,"endColumn":20},{"ruleId":"552","severity":1,"message":"570","line":18,"column":5,"nodeType":"554","messageId":"555","endLine":18,"endColumn":21},{"ruleId":"552","severity":1,"message":"571","line":19,"column":5,"nodeType":"554","messageId":"555","endLine":19,"endColumn":22},{"ruleId":"552","severity":1,"message":"572","line":20,"column":5,"nodeType":"554","messageId":"555","endLine":20,"endColumn":29},{"ruleId":"552","severity":1,"message":"573","line":23,"column":5,"nodeType":"554","messageId":"555","endLine":23,"endColumn":31},{"ruleId":"552","severity":1,"message":"574","line":24,"column":5,"nodeType":"554","messageId":"555","endLine":24,"endColumn":30},{"ruleId":"546","severity":1,"message":"578","line":37,"column":6,"nodeType":"548","endLine":39,"endColumn":4,"suggestions":"582"},{"ruleId":"552","severity":1,"message":"568","line":14,"column":5,"nodeType":"554","messageId":"555","endLine":14,"endColumn":25},{"ruleId":"552","severity":1,"message":"569","line":16,"column":5,"nodeType":"554","messageId":"555","endLine":16,"endColumn":20},{"ruleId":"552","severity":1,"message":"570","line":18,"column":5,"nodeType":"554","messageId":"555","endLine":18,"endColumn":21},{"ruleId":"552","severity":1,"message":"571","line":19,"column":5,"nodeType":"554","messageId":"555","endLine":19,"endColumn":22},{"ruleId":"552","severity":1,"message":"572","line":20,"column":5,"nodeType":"554","messageId":"555","endLine":20,"endColumn":29},{"ruleId":"552","severity":1,"message":"583","line":22,"column":5,"nodeType":"554","messageId":"555","endLine":22,"endColumn":31},{"ruleId":"552","severity":1,"message":"573","line":23,"column":5,"nodeType":"554","messageId":"555","endLine":23,"endColumn":31},{"ruleId":"552","severity":1,"message":"574","line":24,"column":5,"nodeType":"554","messageId":"555","endLine":24,"endColumn":30},{"ruleId":"552","severity":1,"message":"580","line":25,"column":5,"nodeType":"554","messageId":"555","endLine":25,"endColumn":21},{"ruleId":"552","severity":1,"message":"584","line":26,"column":5,"nodeType":"554","messageId":"555","endLine":26,"endColumn":13},{"ruleId":"552","severity":1,"message":"575","line":29,"column":9,"nodeType":"554","messageId":"555","endLine":29,"endColumn":25},{"ruleId":"552","severity":1,"message":"585","line":32,"column":10,"nodeType":"554","messageId":"555","endLine":32,"endColumn":24},{"ruleId":"552","severity":1,"message":"586","line":32,"column":26,"nodeType":"554","messageId":"555","endLine":32,"endColumn":43},{"ruleId":"542","replacedBy":"587"},{"ruleId":"544","replacedBy":"588"},{"ruleId":"546","severity":1,"message":"547","line":60,"column":6,"nodeType":"548","endLine":60,"endColumn":8,"suggestions":"589"},{"ruleId":"546","severity":1,"message":"550","line":34,"column":6,"nodeType":"548","endLine":34,"endColumn":8,"suggestions":"590"},{"ruleId":"552","severity":1,"message":"553","line":127,"column":10,"nodeType":"554","messageId":"555","endLine":127,"endColumn":35},{"ruleId":"546","severity":1,"message":"591","line":163,"column":6,"nodeType":"548","endLine":168,"endColumn":4,"suggestions":"592"},{"ruleId":"556","severity":1,"message":"557","line":301,"column":7,"nodeType":"558","endLine":301,"endColumn":34},{"ruleId":"559","severity":1,"message":"560","line":301,"column":7,"nodeType":"558","endLine":301,"endColumn":34},{"ruleId":"552","severity":1,"message":"561","line":1,"column":27,"nodeType":"554","messageId":"555","endLine":1,"endColumn":35},{"ruleId":"552","severity":1,"message":"562","line":1,"column":37,"nodeType":"554","messageId":"555","endLine":1,"endColumn":46},{"ruleId":"552","severity":1,"message":"564","line":45,"column":5,"nodeType":"554","messageId":"555","endLine":45,"endColumn":17},{"ruleId":"565","severity":1,"message":"566","line":8,"column":1,"nodeType":"567","endLine":15,"endColumn":3},{"ruleId":"546","severity":1,"message":"578","line":37,"column":6,"nodeType":"548","endLine":39,"endColumn":4,"suggestions":"593"},{"ruleId":"546","severity":1,"message":"576","line":46,"column":6,"nodeType":"548","endLine":46,"endColumn":8,"suggestions":"594"},{"ruleId":"546","severity":1,"message":"578","line":53,"column":6,"nodeType":"548","endLine":55,"endColumn":4,"suggestions":"595"},{"ruleId":"546","severity":1,"message":"578","line":62,"column":6,"nodeType":"548","endLine":64,"endColumn":4,"suggestions":"596"},{"ruleId":"546","severity":1,"message":"578","line":33,"column":6,"nodeType":"548","endLine":35,"endColumn":4,"suggestions":"597"},{"ruleId":"546","severity":1,"message":"598","line":44,"column":6,"nodeType":"548","endLine":44,"endColumn":8,"suggestions":"599"},{"ruleId":"546","severity":1,"message":"600","line":53,"column":6,"nodeType":"548","endLine":55,"endColumn":4,"suggestions":"601"},{"ruleId":"542","replacedBy":"602"},{"ruleId":"544","replacedBy":"603"},{"ruleId":"546","severity":1,"message":"604","line":59,"column":6,"nodeType":"548","endLine":59,"endColumn":8,"suggestions":"605"},{"ruleId":"546","severity":1,"message":"600","line":68,"column":6,"nodeType":"548","endLine":70,"endColumn":4,"suggestions":"606"},{"ruleId":"546","severity":1,"message":"607","line":39,"column":6,"nodeType":"548","endLine":39,"endColumn":8,"suggestions":"608"},{"ruleId":"546","severity":1,"message":"600","line":48,"column":6,"nodeType":"548","endLine":50,"endColumn":4,"suggestions":"609"},"no-native-reassign",["610"],"no-negated-in-lhs",["611"],"react-hooks/exhaustive-deps","React Hook useEffect has missing dependencies: 'dispatchGetNetworkTemplatesList', 'dispatchGetServiceTemplates', and 'dispatchGetServiceTemplatesList'. Either include them or remove the dependency array.","ArrayExpression",["612"],"React Hook useEffect has a missing dependency: 'dispatchGetBuildHistoryList'. Either include it or remove the dependency array.",["613"],"no-unused-vars","'serviceConfigOptionsError' is assigned a value but never used.","Identifier","unusedVar","jsx-a11y/anchor-has-content","Anchors must have content and the content must be accessible by a screen reader.","JSXOpeningElement","jsx-a11y/anchor-is-valid","The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md","'useState' is defined but never used.","'useEffect' is defined but never used.","'saveTemporaryBuildOptions' is defined but never used.","'buildOptions' is assigned a value but never used.","import/no-anonymous-default-export","Assign object to a variable before exporting as module default","ExportDefaultDeclaration","'serviceConfigOptions' is assigned a value but never used.","'setBuildOptions' is assigned a value but never used.","'buildOptionsInit' is assigned a value but never used.","'setServiceOptions' is assigned a value but never used.","'setTemporaryBuildOptions' is assigned a value but never used.","'setupTemporaryBuildOptions' is assigned a value but never used.","'saveTemporaryBuildOptions' is assigned a value but never used.","'tempBuildOptions' is assigned a value but never used.","React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceName', and 'serviceTemplates'. Either include them or remove the dependency array.",["614"],"React Hook useEffect has missing dependencies: 'getTemporaryBuildOptions', 'serviceName', and 'setTemporaryServiceOptions'. Either include them or remove the dependency array.",["615"],"'serviceTemplates' is assigned a value but never used.",["616"],["617"],"'setTemporaryServiceOptions' is assigned a value but never used.","'onChange' is assigned a value but never used.","'volumeSettings' is assigned a value but never used.","'setVolumeSettings' is assigned a value but never used.",["610"],["611"],["618"],["619"],"React Hook useEffect has a missing dependency: 'getBuildOptions'. Either include it or remove the dependency array.",["620"],["621"],["622"],["623"],["624"],["625"],"React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceName', 'setTemporaryServiceOptions', and 'yamlVolumeSettings'. Either include them or remove the dependency array.",["626"],"React Hook useEffect has missing dependencies: 'loaded', 'serviceName', 'setTemporaryServiceOptions', and 'tempBuildOptions?.services'. Either include them or remove the dependency array.",["627"],["610"],["611"],"React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceConfigOptions?.modifyableEnvironment', 'serviceName', 'setTemporaryServiceOptions', and 'yamlEnvironmentSettings'. Either include them or remove the dependency array.",["628"],["629"],"React Hook useEffect has missing dependencies: 'getBuildOptions', 'serviceName', 'setTemporaryServiceOptions', and 'yamlDevicesSettings'. Either include them or remove the dependency array.",["630"],["631"],"no-global-assign","no-unsafe-negation",{"desc":"632","fix":"633"},{"desc":"634","fix":"635"},{"desc":"636","fix":"637"},{"desc":"638","fix":"639"},{"desc":"640","fix":"641"},{"desc":"642","fix":"643"},{"desc":"632","fix":"644"},{"desc":"634","fix":"645"},{"desc":"646","fix":"647"},{"desc":"642","fix":"648"},{"desc":"636","fix":"649"},{"desc":"638","fix":"650"},{"desc":"651","fix":"652"},{"desc":"640","fix":"653"},{"desc":"654","fix":"655"},{"desc":"656","fix":"657"},{"desc":"658","fix":"659"},{"desc":"660","fix":"661"},{"desc":"662","fix":"663"},{"desc":"664","fix":"665"},"Update the dependencies array to be: [dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",{"range":"666","text":"667"},"Update the dependencies array to be: [dispatchGetBuildHistoryList]",{"range":"668","text":"669"},"Update the dependencies array to be: [getBuildOptions, serviceName, serviceTemplates]",{"range":"670","text":"671"},"Update the dependencies array to be: [getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",{"range":"672","text":"673"},"Update the dependencies array to be: [getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",{"range":"674","text":"675"},"Update the dependencies array to be: [getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",{"range":"676","text":"677"},{"range":"678","text":"667"},{"range":"679","text":"669"},"Update the dependencies array to be: [updated, serviceName, selectedServices.selectedServices, dispatchGetBuildIssues, getBuildOptions]",{"range":"680","text":"681"},{"range":"682","text":"677"},{"range":"683","text":"671"},{"range":"684","text":"673"},"Update the dependencies array to be: [getTemporaryBuildOptions, networkMode, serviceName, setTemporaryServiceOptions]",{"range":"685","text":"686"},{"range":"687","text":"675"},"Update the dependencies array to be: [getBuildOptions, serviceName, setTemporaryServiceOptions, yamlVolumeSettings]",{"range":"688","text":"689"},"Update the dependencies array to be: [loaded, serviceName, setTemporaryServiceOptions, tempBuildOptions?.services, volumeSettings]",{"range":"690","text":"691"},"Update the dependencies array to be: [getBuildOptions, serviceConfigOptions?.modifyableEnvironment, serviceName, setTemporaryServiceOptions, yamlEnvironmentSettings]",{"range":"692","text":"693"},"Update the dependencies array to be: [environmentSettings, loaded, serviceName, setTemporaryServiceOptions, tempBuildOptions?.services]",{"range":"694","text":"695"},"Update the dependencies array to be: [getBuildOptions, serviceName, setTemporaryServiceOptions, yamlDevicesSettings]",{"range":"696","text":"697"},"Update the dependencies array to be: [devicesSettings, loaded, serviceName, setTemporaryServiceOptions, tempBuildOptions?.services]",{"range":"698","text":"699"},[2011,2013],"[dispatchGetNetworkTemplatesList, dispatchGetServiceTemplates, dispatchGetServiceTemplatesList]",[893,895],"[dispatchGetBuildHistoryList]",[1109,1111],"[getBuildOptions, serviceName, serviceTemplates]",[1298,1327],"[getTemporaryBuildOptions, modifiedNetworkList, serviceName, setTemporaryServiceOptions]",[991,1015],"[getTemporaryBuildOptions, loggingEnabled, serviceName, setTemporaryServiceOptions]",[1020,1042],"[getTemporaryBuildOptions, portSettings, serviceName, setTemporaryServiceOptions]",[2011,2013],[893,895],[5750,5851],"[updated, serviceName, selectedServices.selectedServices, dispatchGetBuildIssues, getBuildOptions]",[1038,1060],[1674,1676],[1863,1892],[2074,2095],"[getTemporaryBuildOptions, networkMode, serviceName, setTemporaryServiceOptions]",[1018,1042],[1346,1348],"[getBuildOptions, serviceName, setTemporaryServiceOptions, yamlVolumeSettings]",[1551,1575],"[loaded, serviceName, setTemporaryServiceOptions, tempBuildOptions?.services, volumeSettings]",[1954,1956],"[getBuildOptions, serviceConfigOptions?.modifyableEnvironment, serviceName, setTemporaryServiceOptions, yamlEnvironmentSettings]",[2168,2197],"[environmentSettings, loaded, serviceName, setTemporaryServiceOptions, tempBuildOptions?.services]",[1245,1247],"[getBuildOptions, serviceName, setTemporaryServiceOptions, yamlDevicesSettings]",[1451,1476],"[devicesSettings, loaded, serviceName, setTemporaryServiceOptions, tempBuildOptions?.services]"] \ No newline at end of file diff --git a/.internal/wui/src/features/BuildSidebar/index.jsx b/.internal/wui/src/features/BuildSidebar/index.jsx index e41634fb3..54d368b17 100644 --- a/.internal/wui/src/features/BuildSidebar/index.jsx +++ b/.internal/wui/src/features/BuildSidebar/index.jsx @@ -23,7 +23,8 @@ import { downloadBuildFile } from '../../actions/downloadBuild.action'; import BuildCompletedModal from '../buildCompletedModal'; -import { API_STATUS } from '../../constants' +import { API_STATUS } from '../../constants'; +import { getBuildOptions } from '../../utils/buildOptionSync'; // const useStyles = makeStyles({ // serviceCard: { @@ -79,8 +80,8 @@ const buildIssuesRender = (issues) => { {issues.status === API_STATUS.SUCCESS && ( - {Array.isArray(issues.payload.issueList.services) - && issues.payload.issueList.services.length > 0 + {Array.isArray(issues?.payload?.issueList?.services) + && (issues?.payload?.issueList?.services?.length ?? 0) > 0 && ( @@ -99,15 +100,15 @@ const buildIssuesRender = (issues) => { )} - {Array.isArray(issues.payload.issueList.networks) - && issues.payload.issueList.networks.length > 0 + {Array.isArray(issues?.payload?.issueList?.networks) + && (issues?.payload?.issueList?.networks?.length ?? 0) > 0 && ( Networks: