From 24f6a8a95ff36333f70240a9c38b6ee4cb96eee7 Mon Sep 17 00:00:00 2001 From: Lukas Heiligenbrunner Date: Tue, 8 Dec 2020 15:12:15 +0000 Subject: [PATCH] Deleted .idea/.gitignore, .idea/clion.iml, .idea/misc.xml, .idea/modules.xml, .idea/platformio.iml, .idea/serialmonitor_settings.xml, .idea/vcs.xml, .idea/watcherTasks.xml files --- .clang-format | 16 + .gitignore | 9 +- .gitlab-ci.yml | 19 + .idea/.gitignore | 2 - .idea/clion.iml | 2 - .idea/misc.xml | 16 - .idea/modules.xml | 9 - .idea/platformio.iml | 2 - .idea/serialmonitor_settings.xml | 4 - .idea/vcs.xml | 6 - .idea/watcherTasks.xml | 30 - .travis.yml | 19 + CMakeListsPrivate.txt | 289 + LICENSE.txt | 165 + factory_settings.ini | 48 + features.ini | 8 + interface/.env | 5 + interface/.env.development | 4 + interface/.env.production | 1 + interface/build/app/icon.png | Bin 0 -> 8940 bytes interface/build/app/manifest.json | 12 + interface/build/css/roboto.css | 22 + interface/build/favicon.ico | Bin 0 -> 1150 bytes interface/build/fonts/li.woff2 | Bin 0 -> 15440 bytes interface/build/fonts/me.woff2 | Bin 0 -> 15552 bytes interface/build/fonts/re.woff2 | Bin 0 -> 15344 bytes interface/build/js/1.b30b.js.gz | Bin 0 -> 735 bytes interface/config-overrides.js | 37 + interface/package-lock.json | 14652 ++++++++++++++++ interface/package.json | 57 + interface/progmem-generator.js | 122 + interface/public/app/icon.png | Bin 0 -> 8940 bytes interface/public/app/manifest.json | 12 + interface/public/css/roboto.css | 22 + interface/public/favicon.ico | Bin 0 -> 1150 bytes interface/public/fonts/li.woff2 | Bin 0 -> 15440 bytes interface/public/fonts/me.woff2 | Bin 0 -> 15552 bytes interface/public/fonts/re.woff2 | Bin 0 -> 15344 bytes interface/public/index.html | 16 + interface/src/App.tsx | 50 + interface/src/AppRouting.tsx | 60 + interface/src/CustomMuiTheme.tsx | 39 + interface/src/SignIn.tsx | 147 + interface/src/ap/APModes.ts | 5 + interface/src/ap/APSettingsController.tsx | 30 + interface/src/ap/APSettingsForm.tsx | 106 + interface/src/ap/APStatus.ts | 28 + interface/src/ap/APStatusController.tsx | 29 + interface/src/ap/APStatusForm.tsx | 78 + interface/src/ap/AccessPoint.tsx | 38 + interface/src/ap/types.ts | 27 + interface/src/api/Endpoints.ts | 22 + interface/src/api/Env.ts | 24 + interface/src/api/index.ts | 2 + .../src/authentication/AuthenticatedRoute.tsx | 42 + .../src/authentication/Authentication.ts | 114 + .../authentication/AuthenticationContext.tsx | 59 + .../authentication/AuthenticationWrapper.tsx | 109 + .../authentication/UnauthenticatedRoute.tsx | 30 + interface/src/authentication/index.ts | 6 + interface/src/components/ApplicationError.tsx | 59 + .../src/components/BlockFormControlLabel.tsx | 10 + interface/src/components/ErrorButton.tsx | 11 + interface/src/components/FormActions.tsx | 7 + interface/src/components/FormButton.tsx | 13 + .../src/components/FullScreenLoading.tsx | 32 + interface/src/components/HighlightAvatar.tsx | 23 + interface/src/components/MenuAppBar.tsx | 286 + .../src/components/PasswordValidator.tsx | 58 + interface/src/components/RestController.tsx | 113 + interface/src/components/RestFormLoader.tsx | 56 + interface/src/components/SectionContent.tsx | 33 + interface/src/components/SingleUpload.tsx | 96 + .../src/components/WebSocketController.tsx | 133 + .../src/components/WebSocketFormLoader.tsx | 40 + interface/src/components/index.ts | 17 + interface/src/features/ApplicationContext.tsx | 23 + interface/src/features/FeaturesContext.tsx | 27 + interface/src/features/FeaturesWrapper.tsx | 61 + interface/src/features/types.ts | 8 + interface/src/history.ts | 5 + interface/src/index.tsx | 13 + interface/src/mqtt/Mqtt.tsx | 37 + interface/src/mqtt/MqttSettingsController.tsx | 30 + interface/src/mqtt/MqttSettingsForm.tsx | 128 + interface/src/mqtt/MqttStatus.ts | 45 + interface/src/mqtt/MqttStatusController.tsx | 29 + interface/src/mqtt/MqttStatusForm.tsx | 83 + interface/src/mqtt/types.ts | 29 + interface/src/ntp/NTPSettingsController.tsx | 30 + interface/src/ntp/NTPSettingsForm.tsx | 80 + interface/src/ntp/NTPStatus.ts | 26 + interface/src/ntp/NTPStatusController.tsx | 30 + interface/src/ntp/NTPStatusForm.tsx | 198 + interface/src/ntp/NetworkTime.tsx | 39 + interface/src/ntp/TZ.tsx | 479 + interface/src/ntp/TimeFormat.ts | 5 + interface/src/ntp/types.ts | 23 + interface/src/project/GeneralInformation.tsx | 120 + interface/src/project/ProjectMenu.tsx | 27 + interface/src/project/ProjectRouting.tsx | 33 + interface/src/project/PumpControl.tsx | 37 + interface/src/project/SettingsController.tsx | 84 + interface/src/project/types.ts | 19 + interface/src/react-app-env.d.ts | 1 + .../src/security/ManageUsersController.tsx | 30 + interface/src/security/ManageUsersForm.tsx | 184 + interface/src/security/Security.tsx | 37 + .../security/SecuritySettingsController.tsx | 30 + .../src/security/SecuritySettingsForm.tsx | 52 + interface/src/security/UserForm.tsx | 86 + interface/src/security/types.ts | 11 + interface/src/serviceWorker.ts | 145 + .../src/system/OTASettingsController.tsx | 30 + interface/src/system/OTASettingsForm.tsx | 66 + interface/src/system/System.tsx | 51 + .../src/system/SystemStatusController.tsx | 30 + interface/src/system/SystemStatusForm.tsx | 245 + .../src/system/UploadFirmwareController.tsx | 71 + interface/src/system/UploadFirmwareForm.tsx | 35 + interface/src/system/types.ts | 37 + interface/src/validators/index.ts | 4 + interface/src/validators/isHostname.ts | 6 + interface/src/validators/isIP.ts | 5 + interface/src/validators/optional.ts | 1 + interface/src/validators/or.ts | 3 + interface/src/wifi/WiFiConnection.tsx | 62 + interface/src/wifi/WiFiConnectionContext.tsx | 13 + interface/src/wifi/WiFiNetworkScanner.tsx | 168 + interface/src/wifi/WiFiNetworkSelector.tsx | 54 + interface/src/wifi/WiFiSecurityModes.ts | 21 + interface/src/wifi/WiFiSettingsController.tsx | 29 + interface/src/wifi/WiFiSettingsForm.tsx | 200 + interface/src/wifi/WiFiStatus.ts | 41 + interface/src/wifi/WiFiStatusController.tsx | 29 + interface/src/wifi/WiFiStatusForm.tsx | 117 + interface/src/wifi/types.ts | 56 + interface/tsconfig.json | 25 + lib/framework/APSettingsService.cpp | 83 + lib/framework/APSettingsService.h | 123 + lib/framework/APStatus.cpp | 22 + lib/framework/APStatus.h | 31 + lib/framework/ArduinoJsonJWT.cpp | 144 + lib/framework/ArduinoJsonJWT.h | 37 + lib/framework/AuthenticationService.cpp | 48 + lib/framework/AuthenticationService.h | 30 + lib/framework/ESP8266React.cpp | 114 + lib/framework/ESP8266React.h | 122 + lib/framework/ESPFS.h | 7 + lib/framework/ESPUtils.h | 17 + lib/framework/FSPersistence.h | 98 + lib/framework/FactoryResetService.cpp | 37 + lib/framework/FactoryResetService.h | 32 + lib/framework/Features.h | 37 + lib/framework/FeaturesService.cpp | 42 + lib/framework/FeaturesService.h | 29 + lib/framework/HttpEndpoint.h | 165 + lib/framework/JsonUtils.h | 29 + lib/framework/MqttPubSub.h | 167 + lib/framework/MqttSettingsService.cpp | 161 + lib/framework/MqttSettingsService.h | 156 + lib/framework/MqttStatus.cpp | 24 + lib/framework/MqttStatus.h | 31 + lib/framework/NTPSettingsService.cpp | 90 + lib/framework/NTPSettingsService.h | 84 + lib/framework/NTPStatus.cpp | 40 + lib/framework/NTPStatus.h | 31 + lib/framework/OTASettingsService.cpp | 71 + lib/framework/OTASettingsService.h | 72 + lib/framework/RestartService.cpp | 13 + lib/framework/RestartService.h | 31 + lib/framework/SecurityManager.h | 102 + lib/framework/SecuritySettingsService.cpp | 140 + lib/framework/SecuritySettingsService.h | 114 + lib/framework/StatefulService.cpp | 3 + lib/framework/StatefulService.h | 148 + lib/framework/SystemStatus.cpp | 45 + lib/framework/SystemStatus.h | 29 + lib/framework/UploadFirmwareService.cpp | 85 + lib/framework/UploadFirmwareService.h | 38 + lib/framework/WebSocketTxRx.h | 273 + lib/framework/WiFiScanner.cpp | 70 + lib/framework/WiFiScanner.h | 35 + lib/framework/WiFiSettingsService.cpp | 100 + lib/framework/WiFiSettingsService.h | 110 + lib/framework/WiFiStatus.cpp | 75 + lib/framework/WiFiStatus.h | 45 + lib/readme.txt | 36 + media/build.png | Bin 0 -> 8646 bytes media/dark.png | Bin 0 -> 64313 bytes media/devserver.png | Bin 0 -> 73249 bytes media/esp12e.jpg | Bin 0 -> 17509 bytes media/esp32.jpg | Bin 0 -> 26212 bytes media/framework.png | Bin 0 -> 58594 bytes media/screenshots.png | Bin 0 -> 66132 bytes media/uploadfs.png | Bin 0 -> 8644 bytes media/uploadfw.png | Bin 0 -> 8823 bytes platformio.ini | 65 +- scripts/build_interface.py | 34 + src/GeneralInfoService.cpp | 48 + src/{WifiManager.h => GeneralInfoService.h} | 51 +- src/Heating.cpp | 13 +- src/Heating.h | 3 +- src/Pins.h | 3 + src/SettingsService.cpp | 70 + src/SettingsService.h | 111 + src/WifiManager.cpp | 173 - src/main.cpp | 69 +- 208 files changed, 25332 insertions(+), 335 deletions(-) create mode 100644 .clang-format create mode 100644 .gitlab-ci.yml delete mode 100644 .idea/.gitignore delete mode 100644 .idea/clion.iml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/platformio.iml delete mode 100644 .idea/serialmonitor_settings.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/watcherTasks.xml create mode 100644 .travis.yml create mode 100644 CMakeListsPrivate.txt create mode 100644 LICENSE.txt create mode 100644 factory_settings.ini create mode 100644 features.ini create mode 100644 interface/.env create mode 100644 interface/.env.development create mode 100644 interface/.env.production create mode 100644 interface/build/app/icon.png create mode 100644 interface/build/app/manifest.json create mode 100644 interface/build/css/roboto.css create mode 100644 interface/build/favicon.ico create mode 100644 interface/build/fonts/li.woff2 create mode 100644 interface/build/fonts/me.woff2 create mode 100644 interface/build/fonts/re.woff2 create mode 100644 interface/build/js/1.b30b.js.gz create mode 100644 interface/config-overrides.js create mode 100644 interface/package-lock.json create mode 100644 interface/package.json create mode 100644 interface/progmem-generator.js create mode 100644 interface/public/app/icon.png create mode 100644 interface/public/app/manifest.json create mode 100644 interface/public/css/roboto.css create mode 100644 interface/public/favicon.ico create mode 100644 interface/public/fonts/li.woff2 create mode 100644 interface/public/fonts/me.woff2 create mode 100644 interface/public/fonts/re.woff2 create mode 100644 interface/public/index.html create mode 100644 interface/src/App.tsx create mode 100644 interface/src/AppRouting.tsx create mode 100644 interface/src/CustomMuiTheme.tsx create mode 100644 interface/src/SignIn.tsx create mode 100644 interface/src/ap/APModes.ts create mode 100644 interface/src/ap/APSettingsController.tsx create mode 100644 interface/src/ap/APSettingsForm.tsx create mode 100644 interface/src/ap/APStatus.ts create mode 100644 interface/src/ap/APStatusController.tsx create mode 100644 interface/src/ap/APStatusForm.tsx create mode 100644 interface/src/ap/AccessPoint.tsx create mode 100644 interface/src/ap/types.ts create mode 100644 interface/src/api/Endpoints.ts create mode 100644 interface/src/api/Env.ts create mode 100644 interface/src/api/index.ts create mode 100644 interface/src/authentication/AuthenticatedRoute.tsx create mode 100644 interface/src/authentication/Authentication.ts create mode 100644 interface/src/authentication/AuthenticationContext.tsx create mode 100644 interface/src/authentication/AuthenticationWrapper.tsx create mode 100644 interface/src/authentication/UnauthenticatedRoute.tsx create mode 100644 interface/src/authentication/index.ts create mode 100644 interface/src/components/ApplicationError.tsx create mode 100644 interface/src/components/BlockFormControlLabel.tsx create mode 100644 interface/src/components/ErrorButton.tsx create mode 100644 interface/src/components/FormActions.tsx create mode 100644 interface/src/components/FormButton.tsx create mode 100644 interface/src/components/FullScreenLoading.tsx create mode 100644 interface/src/components/HighlightAvatar.tsx create mode 100644 interface/src/components/MenuAppBar.tsx create mode 100644 interface/src/components/PasswordValidator.tsx create mode 100644 interface/src/components/RestController.tsx create mode 100644 interface/src/components/RestFormLoader.tsx create mode 100644 interface/src/components/SectionContent.tsx create mode 100644 interface/src/components/SingleUpload.tsx create mode 100644 interface/src/components/WebSocketController.tsx create mode 100644 interface/src/components/WebSocketFormLoader.tsx create mode 100644 interface/src/components/index.ts create mode 100644 interface/src/features/ApplicationContext.tsx create mode 100644 interface/src/features/FeaturesContext.tsx create mode 100644 interface/src/features/FeaturesWrapper.tsx create mode 100644 interface/src/features/types.ts create mode 100644 interface/src/history.ts create mode 100644 interface/src/index.tsx create mode 100644 interface/src/mqtt/Mqtt.tsx create mode 100644 interface/src/mqtt/MqttSettingsController.tsx create mode 100644 interface/src/mqtt/MqttSettingsForm.tsx create mode 100644 interface/src/mqtt/MqttStatus.ts create mode 100644 interface/src/mqtt/MqttStatusController.tsx create mode 100644 interface/src/mqtt/MqttStatusForm.tsx create mode 100644 interface/src/mqtt/types.ts create mode 100644 interface/src/ntp/NTPSettingsController.tsx create mode 100644 interface/src/ntp/NTPSettingsForm.tsx create mode 100644 interface/src/ntp/NTPStatus.ts create mode 100644 interface/src/ntp/NTPStatusController.tsx create mode 100644 interface/src/ntp/NTPStatusForm.tsx create mode 100644 interface/src/ntp/NetworkTime.tsx create mode 100644 interface/src/ntp/TZ.tsx create mode 100644 interface/src/ntp/TimeFormat.ts create mode 100644 interface/src/ntp/types.ts create mode 100644 interface/src/project/GeneralInformation.tsx create mode 100644 interface/src/project/ProjectMenu.tsx create mode 100644 interface/src/project/ProjectRouting.tsx create mode 100644 interface/src/project/PumpControl.tsx create mode 100644 interface/src/project/SettingsController.tsx create mode 100644 interface/src/project/types.ts create mode 100644 interface/src/react-app-env.d.ts create mode 100644 interface/src/security/ManageUsersController.tsx create mode 100644 interface/src/security/ManageUsersForm.tsx create mode 100644 interface/src/security/Security.tsx create mode 100644 interface/src/security/SecuritySettingsController.tsx create mode 100644 interface/src/security/SecuritySettingsForm.tsx create mode 100644 interface/src/security/UserForm.tsx create mode 100644 interface/src/security/types.ts create mode 100644 interface/src/serviceWorker.ts create mode 100644 interface/src/system/OTASettingsController.tsx create mode 100644 interface/src/system/OTASettingsForm.tsx create mode 100644 interface/src/system/System.tsx create mode 100644 interface/src/system/SystemStatusController.tsx create mode 100644 interface/src/system/SystemStatusForm.tsx create mode 100644 interface/src/system/UploadFirmwareController.tsx create mode 100644 interface/src/system/UploadFirmwareForm.tsx create mode 100644 interface/src/system/types.ts create mode 100644 interface/src/validators/index.ts create mode 100644 interface/src/validators/isHostname.ts create mode 100644 interface/src/validators/isIP.ts create mode 100644 interface/src/validators/optional.ts create mode 100644 interface/src/validators/or.ts create mode 100644 interface/src/wifi/WiFiConnection.tsx create mode 100644 interface/src/wifi/WiFiConnectionContext.tsx create mode 100644 interface/src/wifi/WiFiNetworkScanner.tsx create mode 100644 interface/src/wifi/WiFiNetworkSelector.tsx create mode 100644 interface/src/wifi/WiFiSecurityModes.ts create mode 100644 interface/src/wifi/WiFiSettingsController.tsx create mode 100644 interface/src/wifi/WiFiSettingsForm.tsx create mode 100644 interface/src/wifi/WiFiStatus.ts create mode 100644 interface/src/wifi/WiFiStatusController.tsx create mode 100644 interface/src/wifi/WiFiStatusForm.tsx create mode 100644 interface/src/wifi/types.ts create mode 100644 interface/tsconfig.json create mode 100644 lib/framework/APSettingsService.cpp create mode 100644 lib/framework/APSettingsService.h create mode 100644 lib/framework/APStatus.cpp create mode 100644 lib/framework/APStatus.h create mode 100644 lib/framework/ArduinoJsonJWT.cpp create mode 100644 lib/framework/ArduinoJsonJWT.h create mode 100644 lib/framework/AuthenticationService.cpp create mode 100644 lib/framework/AuthenticationService.h create mode 100644 lib/framework/ESP8266React.cpp create mode 100644 lib/framework/ESP8266React.h create mode 100644 lib/framework/ESPFS.h create mode 100644 lib/framework/ESPUtils.h create mode 100644 lib/framework/FSPersistence.h create mode 100644 lib/framework/FactoryResetService.cpp create mode 100644 lib/framework/FactoryResetService.h create mode 100644 lib/framework/Features.h create mode 100644 lib/framework/FeaturesService.cpp create mode 100644 lib/framework/FeaturesService.h create mode 100644 lib/framework/HttpEndpoint.h create mode 100644 lib/framework/JsonUtils.h create mode 100644 lib/framework/MqttPubSub.h create mode 100644 lib/framework/MqttSettingsService.cpp create mode 100644 lib/framework/MqttSettingsService.h create mode 100644 lib/framework/MqttStatus.cpp create mode 100644 lib/framework/MqttStatus.h create mode 100644 lib/framework/NTPSettingsService.cpp create mode 100644 lib/framework/NTPSettingsService.h create mode 100644 lib/framework/NTPStatus.cpp create mode 100644 lib/framework/NTPStatus.h create mode 100644 lib/framework/OTASettingsService.cpp create mode 100644 lib/framework/OTASettingsService.h create mode 100644 lib/framework/RestartService.cpp create mode 100644 lib/framework/RestartService.h create mode 100644 lib/framework/SecurityManager.h create mode 100644 lib/framework/SecuritySettingsService.cpp create mode 100644 lib/framework/SecuritySettingsService.h create mode 100644 lib/framework/StatefulService.cpp create mode 100644 lib/framework/StatefulService.h create mode 100644 lib/framework/SystemStatus.cpp create mode 100644 lib/framework/SystemStatus.h create mode 100644 lib/framework/UploadFirmwareService.cpp create mode 100644 lib/framework/UploadFirmwareService.h create mode 100644 lib/framework/WebSocketTxRx.h create mode 100644 lib/framework/WiFiScanner.cpp create mode 100644 lib/framework/WiFiScanner.h create mode 100644 lib/framework/WiFiSettingsService.cpp create mode 100644 lib/framework/WiFiSettingsService.h create mode 100644 lib/framework/WiFiStatus.cpp create mode 100644 lib/framework/WiFiStatus.h create mode 100644 lib/readme.txt create mode 100644 media/build.png create mode 100644 media/dark.png create mode 100644 media/devserver.png create mode 100644 media/esp12e.jpg create mode 100644 media/esp32.jpg create mode 100644 media/framework.png create mode 100644 media/screenshots.png create mode 100644 media/uploadfs.png create mode 100644 media/uploadfw.png create mode 100644 scripts/build_interface.py create mode 100644 src/GeneralInfoService.cpp rename src/{WifiManager.h => GeneralInfoService.h} (50%) create mode 100644 src/SettingsService.cpp create mode 100644 src/SettingsService.h delete mode 100644 src/WifiManager.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..4e688ba --- /dev/null +++ b/.clang-format @@ -0,0 +1,16 @@ +Language: Cpp +BasedOnStyle: Google +ColumnLimit: 120 +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +BinPackArguments: false +BinPackParameters: false +BreakConstructorInitializers: AfterColon +AllowAllParametersOfDeclarationOnNextLine: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ExperimentalAutoDetectBinPacking: false +KeepEmptyLinesAtTheStartOfBlocks: false +DerivePointerAlignment: false +SortIncludes: false diff --git a/.gitignore b/.gitignore index ff1a518..facc712 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ .pio -CMakeListsPrivate.txt +.clang_complete +.gcc-flags.json +*Thumbs.db +/data/www +/lib/framework/WWWData.h +/interface/build +/interface/node_modules +.vscode diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..8ea88b2 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,19 @@ +image: nikolaik/python-nodejs:python3.9-nodejs15-slim + +stages: + - build + +cache: + paths: + - "~/.platformio" + +before_script: + - "pip install -U platformio" + - "platformio update" + +build: + stage: build + script: "platformio run -e esp12e" + artifacts: + paths: + - .pio/build/esp12e/*.bin \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 5c98b42..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Default ignored files -/workspace.xml \ No newline at end of file diff --git a/.idea/clion.iml b/.idea/clion.iml deleted file mode 100644 index f08604b..0000000 --- a/.idea/clion.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 3463fba..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 9ce81f0..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/platformio.iml b/.idea/platformio.iml deleted file mode 100644 index f08604b..0000000 --- a/.idea/platformio.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/serialmonitor_settings.xml b/.idea/serialmonitor_settings.xml deleted file mode 100644 index af0a408..0000000 --- a/.idea/serialmonitor_settings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml deleted file mode 100644 index 5760ff9..0000000 --- a/.idea/watcherTasks.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..30aa006 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +language: python +python: + - "3.8" + +before_install: + - nvm install 10.15.3 + - nvm use 10.15.3 + +sudo: false +cache: + directories: + - "~/.platformio" + +install: + - pip install -U platformio + - platformio update + +script: + - platformio run -e esp12e -e node32s diff --git a/CMakeListsPrivate.txt b/CMakeListsPrivate.txt new file mode 100644 index 0000000..c21e136 --- /dev/null +++ b/CMakeListsPrivate.txt @@ -0,0 +1,289 @@ +# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE +# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags +# +# If you need to override existing CMake configuration or add extra, +# please create `CMakeListsUser.txt` in the root of project. +# The `CMakeListsUser.txt` will not be overwritten by PlatformIO. + + + +set(CMAKE_CONFIGURATION_TYPES "esp12e;node32s;" CACHE STRING "Build Types reflect PlatformIO Environments" FORCE) + + +SET(CMAKE_C_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-gcc") +SET(CMAKE_CXX_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-g++") +SET(CMAKE_CXX_FLAGS "-fno-rtti -std=c++11 -Os -mlongcalls -mtext-section-literals -falign-functions=4 -U__STRICT_ANSI__ -ffunction-sections -fdata-sections -fno-exceptions -Wall") +SET(CMAKE_C_FLAGS "-std=gnu99 -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -Os -mlongcalls -mtext-section-literals -falign-functions=4 -U__STRICT_ANSI__ -ffunction-sections -fdata-sections -fno-exceptions -Wall") + +SET(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 11) + +if (CMAKE_BUILD_TYPE MATCHES "esp12e") + add_definitions(-D'PLATFORMIO=50003') + add_definitions(-D'ESP8266') + add_definitions(-D'ARDUINO_ARCH_ESP8266') + add_definitions(-D'ARDUINO_ESP8266_ESP12') + add_definitions(-D'FACTORY_WIFI_SSID=\"\"') + add_definitions(-D'FACTORY_WIFI_PASSWORD=\"\"') + add_definitions(-D'FACTORY_AP_PROVISION_MODE=AP_MODE_DISCONNECTED') + add_definitions(-D'FACTORY_AP_SSID=\"ESP8266-React\"') + add_definitions(-D'FACTORY_AP_PASSWORD=\"esp-react\"') + add_definitions(-D'FACTORY_AP_LOCAL_IP=\"192.168.4.1\"') + add_definitions(-D'FACTORY_AP_GATEWAY_IP=\"192.168.4.1\"') + add_definitions(-D'FACTORY_AP_SUBNET_MASK=\"255.255.255.0\"') + add_definitions(-D'FACTORY_ADMIN_USERNAME=\"admin\"') + add_definitions(-D'FACTORY_ADMIN_PASSWORD=\"admin\"') + add_definitions(-D'FACTORY_GUEST_USERNAME=\"guest\"') + add_definitions(-D'FACTORY_GUEST_PASSWORD=\"guest\"') + add_definitions(-D'FACTORY_NTP_ENABLED=true') + add_definitions(-D'FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/London\"') + add_definitions(-D'FACTORY_NTP_TIME_ZONE_FORMAT=\"GMT0BST,M3.5.0/1,M10.5.0\"') + add_definitions(-D'FACTORY_NTP_SERVER=\"time.google.com\"') + add_definitions(-D'FACTORY_OTA_PORT=8266') + add_definitions(-D'FACTORY_OTA_PASSWORD=\"esp-react\"') + add_definitions(-D'FACTORY_OTA_ENABLED=true') + add_definitions(-D'FACTORY_MQTT_ENABLED=false') + add_definitions(-D'FACTORY_MQTT_HOST=\"test.mosquitto.org\"') + add_definitions(-D'FACTORY_MQTT_PORT=1883') + add_definitions(-D'FACTORY_MQTT_USERNAME=\"\"') + add_definitions(-D'FACTORY_MQTT_PASSWORD=\"\"') + add_definitions(-D'FACTORY_MQTT_KEEP_ALIVE=60') + add_definitions(-D'FACTORY_MQTT_CLEAN_SESSION=true') + add_definitions(-D'FACTORY_MQTT_MAX_TOPIC_LENGTH=128') + add_definitions(-D'FT_PROJECT=1') + add_definitions(-D'FT_SECURITY=0') + add_definitions(-D'FT_MQTT=0') + add_definitions(-D'FT_NTP=0') + add_definitions(-D'FT_OTA=1') + add_definitions(-D'FT_UPLOAD_FIRMWARE=1') + add_definitions(-D'NO_GLOBAL_ARDUINOOTA') + add_definitions(-D'ENABLE_CORS') + add_definitions(-D'CORS_ORIGIN=\"http://localhost:3000\"') + add_definitions(-D'PROGMEM_WWW') + add_definitions(-D'F_CPU=160000000L') + add_definitions(-D'__ets__') + add_definitions(-D'ICACHE_FLASH') + add_definitions(-D'ARDUINO=10805') + add_definitions(-D'ARDUINO_BOARD=\"PLATFORMIO_ESP12E\"') + add_definitions(-D'FLASHMODE_DIO') + add_definitions(-D'LWIP_OPEN_SRC') + add_definitions(-D'NONOSDK22x_190703=1') + add_definitions(-D'TCP_MSS=536') + add_definitions(-D'LWIP_FEATURES=1') + add_definitions(-D'LWIP_IPV6=0') + add_definitions(-D'VTABLES_IN_FLASH') + + include_directories("${CMAKE_CURRENT_LIST_DIR}/include") + include_directories("${CMAKE_CURRENT_LIST_DIR}/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/lib/framework") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ArduinoOTA") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266mDNS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/DNSServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/LittleFS/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp12e/DHT/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Ticker/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp12e/AsyncMqttClient/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp12e/ESP Async WebServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Hash/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp12e/ESPAsyncTCP/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFi/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp12e/ArduinoJson/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/tools/sdk/include") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/tools/sdk/libc/xtensa-lx106-elf/include") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/cores/esp8266") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/tools/sdk/lwip2/include") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/variants/nodemcu") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp12e/ESPAsyncTCP@1.2.0/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/EEPROM") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266AVRISP/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266HTTPClient/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266HTTPUpdateServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266LLMNR") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266NetBIOS") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266SSDP") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266SdFat/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WebServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266WiFiMesh/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/ESP8266httpUpdate/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Ethernet/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/GDBStub/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SD/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SDFS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SPI") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SPISlave/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Servo/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/SoftwareSerial/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/TFT_Touch_Shield_V2") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/Wire") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif8266/libraries/esp8266/src") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/4.8.2") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/4.8.2/xtensa-lx106-elf") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/lib/gcc/xtensa-lx106-elf/4.8.2/include-fixed") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/lib/gcc/xtensa-lx106-elf/4.8.2/include") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include") + include_directories("$ENV{HOME}/.platformio/packages/tool-unity") + + FILE(GLOB_RECURSE EXTRA_LIB_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp12e/*.* + ) +endif() + +if (CMAKE_BUILD_TYPE MATCHES "node32s") + add_definitions(-D'PLATFORMIO=50003') + add_definitions(-D'ARDUINO_Node32s') + add_definitions(-D'FACTORY_WIFI_SSID=\"\"') + add_definitions(-D'FACTORY_WIFI_PASSWORD=\"\"') + add_definitions(-D'FACTORY_AP_PROVISION_MODE=AP_MODE_DISCONNECTED') + add_definitions(-D'FACTORY_AP_SSID=\"ESP8266-React\"') + add_definitions(-D'FACTORY_AP_PASSWORD=\"esp-react\"') + add_definitions(-D'FACTORY_AP_LOCAL_IP=\"192.168.4.1\"') + add_definitions(-D'FACTORY_AP_GATEWAY_IP=\"192.168.4.1\"') + add_definitions(-D'FACTORY_AP_SUBNET_MASK=\"255.255.255.0\"') + add_definitions(-D'FACTORY_ADMIN_USERNAME=\"admin\"') + add_definitions(-D'FACTORY_ADMIN_PASSWORD=\"admin\"') + add_definitions(-D'FACTORY_GUEST_USERNAME=\"guest\"') + add_definitions(-D'FACTORY_GUEST_PASSWORD=\"guest\"') + add_definitions(-D'FACTORY_NTP_ENABLED=true') + add_definitions(-D'FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/London\"') + add_definitions(-D'FACTORY_NTP_TIME_ZONE_FORMAT=\"GMT0BST,M3.5.0/1,M10.5.0\"') + add_definitions(-D'FACTORY_NTP_SERVER=\"time.google.com\"') + add_definitions(-D'FACTORY_OTA_PORT=8266') + add_definitions(-D'FACTORY_OTA_PASSWORD=\"esp-react\"') + add_definitions(-D'FACTORY_OTA_ENABLED=true') + add_definitions(-D'FACTORY_MQTT_ENABLED=false') + add_definitions(-D'FACTORY_MQTT_HOST=\"test.mosquitto.org\"') + add_definitions(-D'FACTORY_MQTT_PORT=1883') + add_definitions(-D'FACTORY_MQTT_USERNAME=\"\"') + add_definitions(-D'FACTORY_MQTT_PASSWORD=\"\"') + add_definitions(-D'FACTORY_MQTT_KEEP_ALIVE=60') + add_definitions(-D'FACTORY_MQTT_CLEAN_SESSION=true') + add_definitions(-D'FACTORY_MQTT_MAX_TOPIC_LENGTH=128') + add_definitions(-D'FT_PROJECT=1') + add_definitions(-D'FT_SECURITY=0') + add_definitions(-D'FT_MQTT=0') + add_definitions(-D'FT_NTP=0') + add_definitions(-D'FT_OTA=1') + add_definitions(-D'FT_UPLOAD_FIRMWARE=1') + add_definitions(-D'NO_GLOBAL_ARDUINOOTA') + add_definitions(-D'ENABLE_CORS') + add_definitions(-D'CORS_ORIGIN=\"http://localhost:3000\"') + add_definitions(-D'PROGMEM_WWW') + add_definitions(-D'ESP32') + add_definitions(-D'ESP_PLATFORM') + add_definitions(-D'F_CPU=240000000L') + add_definitions(-D'HAVE_CONFIG_H') + add_definitions(-D'MBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"') + add_definitions(-D'ARDUINO=10805') + add_definitions(-D'ARDUINO_ARCH_ESP32') + add_definitions(-D'ARDUINO_VARIANT=\"esp32\"') + add_definitions(-D'ARDUINO_BOARD=\"Node32s\"') + + include_directories("${CMAKE_CURRENT_LIST_DIR}/include") + include_directories("${CMAKE_CURRENT_LIST_DIR}/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/lib/framework") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Update/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/node32s/AsyncMqttClient/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/node32s/ESP Async WebServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/FS/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/node32s/AsyncTCP/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/node32s/ArduinoJson/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/config") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_trace") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_update") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/asio") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bootloader_support") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bt") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/coap") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/console") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/driver") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-tls") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_adc_cal") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_event") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_client") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_server") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_https_ota") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_ringbuf") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ethernet") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/expat") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fatfs") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freemodbus") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freertos") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/heap") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/idf_test") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/jsmn") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/json") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/libsodium") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/log") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/lwip") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mbedtls") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mdns") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/micro-ecc") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mqtt") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/newlib") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nghttp") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nvs_flash") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/openssl") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protobuf-c") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protocomm") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/pthread") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/sdmmc") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/smartconfig_ack") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/soc") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spi_flash") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spiffs") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcp_transport") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcpip_adapter") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ulp") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/vfs") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wear_levelling") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wifi_provisioning") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wpa_supplicant") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/xtensa-debug-module") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-face") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32-camera") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fb_gfx") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/cores/esp32") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/variants/esp32") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/AzureIoT/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SD/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/xtensa-esp32-elf/include/c++/5.2.0") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/xtensa-esp32-elf/include/c++/5.2.0/xtensa-esp32-elf") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/lib/gcc/xtensa-esp32-elf/5.2.0/include-fixed") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/lib/gcc/xtensa-esp32-elf/5.2.0/include") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/xtensa-esp32-elf/include") + include_directories("$ENV{HOME}/.platformio/packages/tool-unity") + + FILE(GLOB_RECURSE EXTRA_LIB_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/node32s/*.* + ) +endif() + +FILE(GLOB_RECURSE SRC_LIST + ${CMAKE_CURRENT_LIST_DIR}/src/*.* + ${CMAKE_CURRENT_LIST_DIR}/lib/*.* +) + +list(APPEND SRC_LIST ${EXTRA_LIB_SOURCES}) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/factory_settings.ini b/factory_settings.ini new file mode 100644 index 0000000..4cbcf5c --- /dev/null +++ b/factory_settings.ini @@ -0,0 +1,48 @@ +[factory_settings] +build_flags = + ; WiFi settings + -D FACTORY_WIFI_SSID=\"\" + -D FACTORY_WIFI_PASSWORD=\"\" + ; if unspecified the devices hardware ID will be used + ; -D FACTORY_WIFI_HOSTNAME=\"esp-react\" + + ; Access point settings + -D FACTORY_AP_PROVISION_MODE=AP_MODE_DISCONNECTED + -D FACTORY_AP_SSID=\"ESP8266-React\" ; 1-64 characters + -D FACTORY_AP_PASSWORD=\"esp-react\" ; 8-64 characters + -D FACTORY_AP_LOCAL_IP=\"192.168.4.1\" + -D FACTORY_AP_GATEWAY_IP=\"192.168.4.1\" + -D FACTORY_AP_SUBNET_MASK=\"255.255.255.0\" + + ; User credentials for admin and guest user + -D FACTORY_ADMIN_USERNAME=\"admin\" + -D FACTORY_ADMIN_PASSWORD=\"admin\" + -D FACTORY_GUEST_USERNAME=\"guest\" + -D FACTORY_GUEST_PASSWORD=\"guest\" + + ; NTP settings + -D FACTORY_NTP_ENABLED=true + -D FACTORY_NTP_TIME_ZONE_LABEL=\"Europe/London\" + -D FACTORY_NTP_TIME_ZONE_FORMAT=\"GMT0BST,M3.5.0/1,M10.5.0\" + -D FACTORY_NTP_SERVER=\"time.google.com\" + + ; OTA settings + -D FACTORY_OTA_PORT=8266 + -D FACTORY_OTA_PASSWORD=\"esp-react\" + -D FACTORY_OTA_ENABLED=true + + ; MQTT settings + -D FACTORY_MQTT_ENABLED=false + -D FACTORY_MQTT_HOST=\"test.mosquitto.org\" + -D FACTORY_MQTT_PORT=1883 + -D FACTORY_MQTT_USERNAME=\"\" + -D FACTORY_MQTT_PASSWORD=\"\" + ; if unspecified the devices hardware ID will be used + ;-D FACTORY_MQTT_CLIENT_ID=\"esp-react\" + -D FACTORY_MQTT_KEEP_ALIVE=60 + -D FACTORY_MQTT_CLEAN_SESSION=true + -D FACTORY_MQTT_MAX_TOPIC_LENGTH=128 + + ; JWT Secret + ; if unspecified the devices hardware ID will be used + ; -D FACTORY_JWT_SECRET=\"esp8266-react\" diff --git a/features.ini b/features.ini new file mode 100644 index 0000000..daa620c --- /dev/null +++ b/features.ini @@ -0,0 +1,8 @@ +[features] +build_flags = + -D FT_PROJECT=1 + -D FT_SECURITY=0 + -D FT_MQTT=0 + -D FT_NTP=0 + -D FT_OTA=1 + -D FT_UPLOAD_FIRMWARE=1 diff --git a/interface/.env b/interface/.env new file mode 100644 index 0000000..a312b2a --- /dev/null +++ b/interface/.env @@ -0,0 +1,5 @@ +# This is the name of your project. It appears on the sign-in page and in the menu bar. +REACT_APP_PROJECT_NAME=ESP8266 React + +# This is the url path your project will be exposed under. +REACT_APP_PROJECT_PATH=project diff --git a/interface/.env.development b/interface/.env.development new file mode 100644 index 0000000..bd0a2fd --- /dev/null +++ b/interface/.env.development @@ -0,0 +1,4 @@ +# Change the IP address to that of your ESP device to enable local development of the UI. +# Remember to also enable CORS in platformio.ini before uploading the code to the device. +REACT_APP_HTTP_ROOT=http://192.168.0.230 +REACT_APP_WEB_SOCKET_ROOT=ws://192.168.0.230 diff --git a/interface/.env.production b/interface/.env.production new file mode 100644 index 0000000..ba7cc18 --- /dev/null +++ b/interface/.env.production @@ -0,0 +1 @@ +GENERATE_SOURCEMAP=false diff --git a/interface/build/app/icon.png b/interface/build/app/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..13dd442c80a693e407fb8c2615f699e4639d3eea GIT binary patch literal 8940 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 literal 0 HcmV?d00001 diff --git a/interface/build/app/manifest.json b/interface/build/app/manifest.json new file mode 100644 index 0000000..f775661 --- /dev/null +++ b/interface/build/app/manifest.json @@ -0,0 +1,12 @@ +{ + "name":"ESP8266 React", + "icons":[ + { + "src":"/app/icon.png", + "sizes":"48x48 72x72 96x96 128x128 256x256" + } + ], + "start_url":"/", + "display":"fullscreen", + "orientation":"any" +} diff --git a/interface/build/css/roboto.css b/interface/build/css/roboto.css new file mode 100644 index 0000000..ac21f0f --- /dev/null +++ b/interface/build/css/roboto.css @@ -0,0 +1,22 @@ +/* Just supporting latin due to size constrains on the esp chip */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/li.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; +} +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), url(../fonts/re.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; +} +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/me.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; +} \ No newline at end of file diff --git a/interface/build/favicon.ico b/interface/build/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..399ccae7c23cffc07389cf431b329ac611fc6c01 GIT binary patch literal 1150 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 O6y7R}gQBj@I4BA`2c0zl literal 0 HcmV?d00001 diff --git a/interface/build/js/1.b30b.js.gz b/interface/build/js/1.b30b.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..3c4fd46d58cb95c70d88668325f790624a524b1f GIT binary patch literal 735 zcmV<50wDb#iwFP!000021C3N&Yuhjs{VRzdj6_u}DWep-V(){|LHA}%QJm|-ZGJ)(xOFC&aInDl(%(Jl@6K3o;lL}Y z6fsQEG&O}P)6{d@`aOvoyo|EA5UV`m(2GVdEd5YP%QTiGQ0P)v{G)w^CQTdcD)$po z>bc)Hbs&_`+(BraUbH;|F0EAu(z5z=Di8;TbTc)$nVA9R5TCnkr{wRPcUJ0Bcz7^+bV~z!SRNTZRJ)K5rw@^14CPDkK zBk1-KoZKkLu=ox_7CPEtJtv+|Z_?@^dz&DgaXd`DxIa8@j7rnt$%DBMuF<<6a+jv> zUHLYap;)SgEcs@(t%9VZ?7igV;Q{;@Hl;0B1K#kW|6Y}K>f)@Tv_L7lN!=t7-@o=vFBj>mg+%yoWuo1mDP3h2%BoLmPl?U-gK5 zPYlvL0iv^6#19oHYK`?YoBPFXpN&z+H;vx*xbS10Kfe%3(l11fHJy0X?Uy;?T$PX5 zyX+r_^9)B^jwLcd`k9N@nOB;Ofgf_3m=J4Nk$g&e=A{Vx#uv#GY^2F z`uY;JKo!gXM?}{_tCfQp^-M{c4_o2TOCHJV>MZiLOF RixIT5{4Y*n?cehS003RFYTW<; literal 0 HcmV?d00001 diff --git a/interface/config-overrides.js b/interface/config-overrides.js new file mode 100644 index 0000000..61cd113 --- /dev/null +++ b/interface/config-overrides.js @@ -0,0 +1,37 @@ +const ManifestPlugin = require('webpack-manifest-plugin'); +const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const CompressionPlugin = require('compression-webpack-plugin'); +const ProgmemGenerator = require('./progmem-generator.js'); + +const path = require('path'); +const fs = require('fs'); + +module.exports = function override(config, env) { + if (env === "production") { + // rename the ouput file, we need it's path to be short, for embedded FS + config.output.filename = 'js/[id].[chunkhash:4].js'; + config.output.chunkFilename = 'js/[id].[chunkhash:4].js'; + + // take out the manifest and service worker plugins + config.plugins = config.plugins.filter(plugin => !(plugin instanceof ManifestPlugin)); + config.plugins = config.plugins.filter(plugin => !(plugin instanceof WorkboxWebpackPlugin.GenerateSW)); + + // shorten css filenames + const miniCssExtractPlugin = config.plugins.find((plugin) => plugin instanceof MiniCssExtractPlugin); + miniCssExtractPlugin.options.filename = "css/[id].[contenthash:4].css"; + miniCssExtractPlugin.options.chunkFilename = "css/[id].[contenthash:4].c.css"; + + // build progmem data files + config.plugins.push(new ProgmemGenerator({ outputPath: "../lib/framework/WWWData.h", bytesPerLine: 20 })); + + // add compression plugin, compress javascript + config.plugins.push(new CompressionPlugin({ + filename: "[path].gz[query]", + algorithm: "gzip", + test: /\.(js)$/, + deleteOriginalAssets: true + })); + } + return config; +} diff --git a/interface/package-lock.json b/interface/package-lock.json new file mode 100644 index 0000000..014040e --- /dev/null +++ b/interface/package-lock.json @@ -0,0 +1,14652 @@ +{ + "name": "esp8266-react", + "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.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.5.tgz", + "integrity": "sha512-DTsS7cxrsH3by8nqQSpFSyjSfSYl57D6Cf4q8dW3LK83tBKBDCkfcay1nYkXq1nIHXnpX8WMMb/O25HOy3h1zg==" + }, + "@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/generator": { + "version": "7.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" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.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.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.1.tgz", + "integrity": "sha512-rsZ4LGvFTZnzdNZR5HZdmJVuXK8834R5QkF3WvcnBhrlVtF0HSIUC6zbreL9MgjTywhKokn8RIYRiq99+DLAxA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^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.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz", + "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==", + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@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.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@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-regex": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "requires": { + "lodash": "^4.17.19" + } + }, + "@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.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", + "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==" + }, + "@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.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", + "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-decorators": "^7.8.3" + } + }, + "@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.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.5.tgz", + "integrity": "sha512-UiAnkKuOrCyjZ3sYNHlRlfuZJbBHknMQ9VMwVeX97Ofwx7RpD6gS2HfqTCh8KNUQgcOm8IKt103oR4KIjh7Q8g==", + "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.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/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-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-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.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz", + "integrity": "sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-flow": "^7.8.3" + } + }, + "@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.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.5.tgz", + "integrity": "sha512-2xkcPqqrYiOQgSlM/iwto1paPijjsDbUynN13tI6bosDz/jOW3CRzYguIE8wKX32h+msbBM22Dv5fwrFkUOZjQ==", + "requires": { + "@babel/helper-builder-react-jsx": "^7.10.4", + "@babel/helper-builder-react-jsx-experimental": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "^7.12.1" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.5.tgz", + "integrity": "sha512-1JJusg3iPgsZDthyWiCr3KQiGs31ikU/mSf2N2dSYEAO0GEImmVUbWf0VoSDGDFTAn5Dj4DUiR6SdIXHY7tELA==", + "requires": { + "@babel/helper-builder-react-jsx-experimental": "^7.12.1", + "@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.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", + "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.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.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.1.tgz", + "integrity": "sha512-CiUgKQ3AGVk7kveIaPEET1jNDhZZEl1RPMWdTBE1799bdz++SwqDHStmxfCtDfBhQgCl38YRiSnrMuUMZIWSUQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^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.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" + }, + "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.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.5.tgz", + "integrity": "sha512-jcs++VPrgyFehkMezHtezS2BpnUlR7tQFAyesJn1vGTO9aTFZrgIQrA5YydlTwxbcjMwkFY6i04flCigRRr3GA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-react-display-name": "^7.12.1", + "@babel/plugin-transform-react-jsx": "^7.12.5", + "@babel/plugin-transform-react-jsx-development": "^7.12.5", + "@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.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz", + "integrity": "sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-typescript": "^7.9.0" + } + }, + "@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.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", + "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", + "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.5", + "@babel/types": "^7.12.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.12.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", + "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@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==" + }, + "@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" + } + }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + } + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + } + }, + "@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" + } + }, + "@material-ui/core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz", + "integrity": "sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.10.0", + "@material-ui/system": "^4.9.14", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.10.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", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/icons": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.9.1.tgz", + "integrity": "sha512-GBitL3oBWO0hzBhvA9KxqcowRUsA0qzwKkURyC8nppnC3fw54KPKZ+d4V1Eeg/UnDRSzDaI9nGCdel/eh9AQMg==", + "requires": { + "@babel/runtime": "^7.4.4" + } + }, + "@material-ui/styles": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz", + "integrity": "sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.9.6", + "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" + } + }, + "@material-ui/system": { + "version": "4.9.14", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz", + "integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + } + }, + "@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.10.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz", + "integrity": "sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" + }, + "@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" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig==" + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ==" + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz", + "integrity": "sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w==" + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz", + "integrity": "sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w==" + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz", + "integrity": "sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w==" + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz", + "integrity": "sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w==" + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz", + "integrity": "sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw==" + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz", + "integrity": "sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw==" + }, + "@svgr/babel-preset": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.3.tgz", + "integrity": "sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0", + "@svgr/babel-plugin-svg-dynamic-title": "^4.3.3", + "@svgr/babel-plugin-svg-em-dimensions": "^4.2.0", + "@svgr/babel-plugin-transform-react-native-svg": "^4.2.0", + "@svgr/babel-plugin-transform-svg-component": "^4.2.0" + } + }, + "@svgr/core": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.3.tgz", + "integrity": "sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w==", + "requires": { + "@svgr/plugin-jsx": "^4.3.3", + "camelcase": "^5.3.1", + "cosmiconfig": "^5.2.1" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz", + "integrity": "sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg==", + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@svgr/plugin-jsx": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz", + "integrity": "sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w==", + "requires": { + "@babel/core": "^7.4.5", + "@svgr/babel-preset": "^4.3.3", + "@svgr/hast-util-to-babel-ast": "^4.3.2", + "svg-parser": "^2.0.0" + } + }, + "@svgr/plugin-svgo": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz", + "integrity": "sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==", + "requires": { + "cosmiconfig": "^5.2.1", + "merge-deep": "^3.0.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz", + "integrity": "sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg==", + "requires": { + "@babel/core": "^7.4.5", + "@babel/plugin-transform-react-constant-elements": "^7.0.0", + "@babel/preset-env": "^7.4.5", + "@babel/preset-react": "^7.0.0", + "@svgr/core": "^4.3.3", + "@svgr/plugin-jsx": "^4.3.3", + "@svgr/plugin-svgo": "^4.3.1", + "loader-utils": "^1.2.3" + } + }, + "@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.0.3", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.3.tgz", + "integrity": "sha512-uCoznIPDmnickEi6D0v11SBpW0OuVqHJCa7syXqQHy5uktSCreIlt0iglsCnmvz8yCb38hGcWeseA8cWJSwv5Q==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.15.tgz", + "integrity": "sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A==", + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" + }, + "@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/history": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.8.tgz", + "integrity": "sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==" + }, + "@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": "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/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/jwt-decode": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-3.1.0.tgz", + "integrity": "sha512-tthwik7TKkou3mVnBnvVuHnHElbjtdbM63pdBCbZTirCt3WAdM73Y79mOri7+ljsS99ZVwUFZHLMxJuJnv/z1w==", + "requires": { + "jwt-decode": "*" + } + }, + "@types/lodash": { + "version": "4.14.165", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz", + "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==" + }, + "@types/material-ui": { + "version": "0.21.8", + "resolved": "https://registry.npmjs.org/@types/material-ui/-/material-ui-0.21.8.tgz", + "integrity": "sha512-Rsx3tRNoYkidDKfMfh+cegtOHMl73akzKnQ5pzxTrbx5oaUXLtG6YVlvtS43uebOSTDf8GQNaseB52r3zVagEg==", + "requires": { + "@types/react": "*", + "@types/react-addons-linked-state-mixin": "*" + } + }, + "@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": "12.19.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.4.tgz", + "integrity": "sha512-o3oj1bETk8kBwzz1WlO6JWL/AfAA3Vm6J1B3C9CsdxHYp7XgPiH7OEXPUbZTndHlRaIElrANkQfe6ZmfJb3H2w==" + }, + "@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/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": "16.9.56", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.56.tgz", + "integrity": "sha512-gIkl4J44G/qxbuC6r2Xh+D3CGZpJ+NdWTItAPmZbR5mUS+JQ8Zvzpl0ea5qT/ZT3ZNTUcDKUVqV3xBE8wv/DyQ==", + "requires": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.4.tgz", + "integrity": "sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA==" + } + } + }, + "@types/react-addons-linked-state-mixin": { + "version": "0.14.21", + "resolved": "https://registry.npmjs.org/@types/react-addons-linked-state-mixin/-/react-addons-linked-state-mixin-0.14.21.tgz", + "integrity": "sha512-3UF7Szd3JyuU+z90kqu8L4VdDWp7SUC0eRjV2QmMEliaHODGLi5XyO5ctS50K/lG6fjC0dSAPVbvnqv0nPoGMQ==", + "requires": { + "@types/react": "*" + } + }, + "@types/react-dom": { + "version": "16.9.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.9.tgz", + "integrity": "sha512-jE16FNWO3Logq/Lf+yvEAjKzhpST/Eac8EMd1i4dgZdMczfgqC8EjpxwNgEe3SExHYLliabXDh9DEhhqnlXJhg==", + "requires": { + "@types/react": "*" + } + }, + "@types/react-material-ui-form-validator": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/react-material-ui-form-validator/-/react-material-ui-form-validator-2.1.0.tgz", + "integrity": "sha512-izwjulCvMsN01H8oF8X1IN7QDMHeaGmjYoAxL/cmlUJLtFH0BLLUNmlmZERrjNM+MOJAXUaOkwoCqOHlCtqCzQ==", + "requires": { + "@types/material-ui": "*", + "@types/react": "*" + } + }, + "@types/react-router": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.8.tgz", + "integrity": "sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg==", + "requires": { + "@types/history": "*", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.6.tgz", + "integrity": "sha512-gjrxYqxz37zWEdMVvQtWPFMFj1dRDb4TGOcgyOfSXTrEXdF92L00WE3C471O3TV/RF1oskcStkXsOU0Ete4s/g==", + "requires": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@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/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" + }, + "@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": "*" + } + }, + "@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": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", + "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "requires": { + "@typescript-eslint/experimental-utils": "2.34.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", + "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + } + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@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": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.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==" + } + } + }, + "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": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + }, + "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": "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" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "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-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" + }, + "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.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "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" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "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=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==" + }, + "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==" + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "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" + } + }, + "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": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "requires": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.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": { + "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": "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" + } + }, + "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" + } + }, + "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" + } + }, + "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=" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "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" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "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": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + }, + "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=" + } + } + }, + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "requires": { + "@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" + } + }, + "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" + } + }, + "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" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "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==" + } + } + }, + "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-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "babel-preset-react-app": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz", + "integrity": "sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA==", + "requires": { + "@babel/core": "7.9.0", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-proposal-decorators": "7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3", + "@babel/plugin-proposal-numeric-separator": "7.8.3", + "@babel/plugin-proposal-optional-chaining": "7.9.0", + "@babel/plugin-transform-flow-strip-types": "7.9.0", + "@babel/plugin-transform-react-display-name": "7.8.3", + "@babel/plugin-transform-runtime": "7.9.0", + "@babel/preset-env": "7.9.0", + "@babel/preset-react": "7.9.1", + "@babel/preset-typescript": "7.9.0", + "@babel/runtime": "7.9.0", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz", + "integrity": "sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/preset-env": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", + "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", + "requires": { + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", + "@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.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.0", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.0", + "browserslist": "^4.9.1", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/preset-react": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.1.tgz", + "integrity": "sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-react-display-name": "^7.8.3", + "@babel/plugin-transform-react-jsx": "^7.9.1", + "@babel/plugin-transform-react-jsx-development": "^7.9.0", + "@babel/plugin-transform-react-jsx-self": "^7.9.0", + "@babel/plugin-transform-react-jsx-source": "^7.9.0" + } + }, + "@babel/runtime": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.0.tgz", + "integrity": "sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA==", + "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.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, + "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" + } + }, + "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==" + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "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" + } + }, + "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==" + }, + "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": "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" + } + } + } + }, + "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==" + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + } + } + }, + "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.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.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==" + } + } + }, + "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" + } + }, + "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.14.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz", + "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==", + "requires": { + "caniuse-lite": "^1.0.30001157", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.591", + "escalade": "^3.1.1", + "node-releases": "^1.1.66" + } + }, + "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" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "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-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" + } + }, + "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" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "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" + } + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + }, + "camel-case": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", + "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", + "requires": { + "pascal-case": "^3.1.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "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.30001157", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001157.tgz", + "integrity": "sha512-gOerH9Wz2IRZ2ZPdMfBvyOi3cjaz4O4dgNwPGzx8EhqAs4+2IL/O+fJsbt+znSigujoZG8bVcIAUM/I/E5K3MA==" + }, + "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" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "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": { + "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" + } + }, + "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" + } + }, + "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" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "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" + } + } + } + }, + "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" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "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" + } + }, + "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" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + }, + "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": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "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=" + }, + "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" + } + } + } + }, + "clone-deep": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", + "requires": { + "for-own": "^0.1.3", + "is-plain-object": "^2.0.1", + "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", + "shallow-clone": "^0.1.2" + } + }, + "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" + } + }, + "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": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==" + }, + "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=" + }, + "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==" + } + } + }, + "compression-webpack-plugin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-4.0.1.tgz", + "integrity": "sha512-0mg6PgwTsUe5LEcUrOu3ob32vraDx2VdbMGAT1PARcOV+UJWDYZFdkSo6RbHoGQ061mmmkC7XpRKOlvwm/gzJQ==", + "requires": { + "cacache": "^15.0.5", + "find-cache-dir": "^3.3.1", + "schema-utils": "^2.7.0", + "serialize-javascript": "^4.0.0", + "webpack-sources": "^1.4.3" + } + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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" + }, + "dependencies": { + "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==" + } + } + }, + "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" + }, + "dependencies": { + "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==" + } + } + }, + "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" + }, + "dependencies": { + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "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.7.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.7.0.tgz", + "integrity": "sha512-NwS7fI5M5B85EwpWuIwJN4i/fbisQUwLwiSNUWeXlkAZ0sbBjLEvLvFLf1uzAUV66PcEPt4xCGCmOZSxVf3xzA==" + }, + "core-js-compat": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.7.0.tgz", + "integrity": "sha512-V8yBI3+ZLDVomoWICO6kq/CD28Y4r1M7CWeO4AGpMdMfseu8bkSubBmUPySMGKRTS+su4XQ07zUkAsiu9FCWTg==", + "requires": { + "browserslist": "^4.14.6", + "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.7.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.7.0.tgz", + "integrity": "sha512-EZD2ckZysv8MMt4J6HSvS9K2GdtlZtdBncKAmF9lr2n0c9dJUaUN88PSTjvgwCgQPWKTkERXITgS6JJRAnljtg==" + }, + "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": "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" + } + }, + "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" + } + }, + "create-react-context": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", + "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", + "requires": { + "gud": "^1.0.0", + "warning": "^4.0.3" + } + }, + "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" + } + }, + "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" + } + }, + "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": "3.4.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz", + "integrity": "sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA==", + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.23", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.1.1", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.0.2", + "schema-utils": "^2.6.0" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + } + } + }, + "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" + } + }, + "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==" + }, + "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" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.1.0.tgz", + "integrity": "sha512-h+6w/W1WqXaJA4tb1dk7r5tVbOm97MsKxzwnvOR04UQ6GILroryjMWu3pmCCtL2mLaEStQ0fZgeGiy99mo7iyg==", + "requires": { + "css-tree": "^1.0.0" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0.tgz", + "integrity": "sha512-CdVYz/Yuqw0VdKhXPBIgi8DO3NicJVYZNWeX9XcIuSp9ZoFT5IcleVRW07O5rMjdcx1mb+MEJPknTTEW7DdsYw==", + "requires": { + "mdn-data": "2.0.12", + "source-map": "^0.6.1" + } + }, + "mdn-data": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.12.tgz", + "integrity": "sha512-ULbAlgzVb8IqZ0Hsxm6hHSlQl3Jckst2YEQS7fODu9ilNWy2LvcoSY7TRFIktABP2mdppBioc66va90T+NUs8Q==" + } + } + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "requires": { + "cssom": "0.3.x" + } + }, + "csstype": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.13.tgz", + "integrity": "sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A==" + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "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=" + }, + "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=" + }, + "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=" + }, + "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" + } + }, + "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==" + } + } + }, + "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": { + "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==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "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": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" + }, + "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": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.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-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" + }, + "dependencies": { + "csstype": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.4.tgz", + "integrity": "sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA==" + } + } + }, + "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.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" + } + } + }, + "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": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", + "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", + "requires": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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=" + }, + "electron-to-chromium": { + "version": "1.3.592", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.592.tgz", + "integrity": "sha512-kGNowksvqQiPb1pUSQKpd8JFoGPLxYOwduNRCqCxGh/2Q1qE2JdmwouCW41lUzDxOb/2RIV4lR0tVIfboWlO9A==" + }, + "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==" + } + } + }, + "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==" + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" + }, + "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==" + } + } + }, + "eslint-config-react-app": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz", + "integrity": "sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ==", + "requires": { + "confusing-browser-globals": "^1.0.9" + } + }, + "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-loader": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-3.0.3.tgz", + "integrity": "sha512-+YRqB95PnNvxNp1HEjQmvf9KNvCin5HXYYseOXVC2U0KEcw4IkQ2IQEBG46j7+gW39bMzeu0GsUhVbBY3Votpw==", + "requires": { + "fs-extra": "^8.1.0", + "loader-fs-cache": "^1.0.2", + "loader-utils": "^1.2.3", + "object-hash": "^2.0.1", + "schema-utils": "^2.6.1" + } + }, + "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": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", + "integrity": "sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ==", + "requires": { + "lodash": "^4.17.15" + } + }, + "eslint-plugin-import": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", + "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "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=" + }, + "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" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "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": { + "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" + } + }, + "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" + } + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz", + "integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==", + "requires": { + "@babel/runtime": "^7.4.5", + "aria-query": "^3.0.0", + "array-includes": "^3.0.3", + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.2", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^7.0.2", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.1" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + } + } + }, + "eslint-plugin-react": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", + "requires": { + "array-includes": "^3.1.1", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" + }, + "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" + } + }, + "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" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", + "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==" + }, + "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" + } + }, + "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==" + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "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==" + }, + "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": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, + "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=" + }, + "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=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "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==" + } + } + }, + "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" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "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" + } + }, + "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==" + } + } + }, + "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": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "dependencies": { + "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" + } + } + } + } + } + }, + "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=" + }, + "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==" + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "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": "4.3.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz", + "integrity": "sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==", + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.5.0" + } + }, + "file-selector": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.2.3.tgz", + "integrity": "sha512-d+hc9ctodLSVG55V2V5I4/eJBEr2p2na/kDN46Ty7PBhdp/Q5NmeQTXKa1Hx3AcIL1lgSFKZI0ve/v5ZXGCDkQ==", + "requires": { + "tslib": "^2.0.3" + } + }, + "filesize": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", + "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==" + }, + "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" + } + } + } + }, + "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": "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" + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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==" + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "^1.0.1" + } + }, + "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": "3.1.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", + "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", + "requires": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^3.3.0", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "form-data": { + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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" + } + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "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-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" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "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==" + } + } + }, + "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": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + } + } + }, + "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=" + }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, + "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" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + } + } + }, + "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-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.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=" + } + } + }, + "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": { + "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" + } + }, + "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" + } + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "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" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" + } + } + }, + "html-webpack-plugin": { + "version": "4.0.0-beta.11", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz", + "integrity": "sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg==", + "requires": { + "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": { + "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" + } + }, + "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=" + }, + "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": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "immer": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", + "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==" + }, + "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": "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" + } + }, + "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" + } + }, + "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" + }, + "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-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" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "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==" + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "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==" + }, + "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" + } + }, + "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" + } + } + } + }, + "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" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "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" + } + }, + "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==", + "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.1.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", + "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "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" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" + }, + "is-glob": { + "version": "4.0.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-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": "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" + } + }, + "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-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": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "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": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==" + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "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" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "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" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "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" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "requires": { + "html-escaper": "^2.0.0" + } + }, + "jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" + }, + "dependencies": { + "jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "requires": { + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" + } + } + } + }, + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } + }, + "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-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "requires": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-jsdom-fourteen": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz", + "integrity": "sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q==", + "requires": { + "@jest/environment": "^24.3.0", + "@jest/fake-timers": "^24.3.0", + "@jest/types": "^24.3.0", + "jest-mock": "^24.0.0", + "jest-util": "^24.0.0", + "jsdom": "^14.1.0" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "jsdom": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.1.0.tgz", + "integrity": "sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng==", + "requires": { + "abab": "^2.0.0", + "acorn": "^6.0.4", + "acorn-globals": "^4.3.0", + "array-equal": "^1.0.0", + "cssom": "^0.3.4", + "cssstyle": "^1.1.1", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.0", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.1.3", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.5.0", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^6.1.2", + "xml-name-validator": "^3.0.0" + } + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "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" + } + } + } + }, + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^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-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "requires": { + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "dependencies": { + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true + } + } + }, + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + } + }, + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "requires": { + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "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" + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "requires": { + "@jest/types": "^24.9.0" + } + }, + "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": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" + }, + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "requires": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "requires": { + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + } + }, + "jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + } + }, + "jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" + } + }, + "jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" + }, + "jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + }, + "dependencies": { + "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" + } + } + } + }, + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "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" + } + } + } + }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + } + }, + "jest-watch-typeahead": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz", + "integrity": "sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.1", + "jest-regex-util": "^24.9.0", + "jest-watcher": "^24.3.0", + "slash": "^3.0.0", + "string-length": "^3.1.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "string-length": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz", + "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==", + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^5.2.0" + } + } + } + }, + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + } + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" + } + } + }, + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "~0.0.0" + } + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "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.4.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.4.0.tgz", + "integrity": "sha512-l7EwdwhsDishXzqTc3lbsbyZ83tlUl5L/Hb16pHCvZliA9lRDdNBZmHzeJHP0sxqD0t1mrMmMR8XroR12JBYzw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.4.tgz", + "integrity": "sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA==" + } + } + }, + "jss-plugin-camel-case": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.4.0.tgz", + "integrity": "sha512-9oDjsQ/AgdBbMyRjc06Kl3P8lDCSEts2vYZiPZfGAxbGCegqE4RnMob3mDaBby5H9vL9gWmyyImhLRWqIkRUCw==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.4.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.4.0.tgz", + "integrity": "sha512-BYJ+Y3RUYiMEgmlcYMLqwbA49DcSWsGgHpVmEEllTC8MK5iJ7++pT9TnKkKBnNZZxTV75ycyFCR5xeLSOzVm4A==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0" + } + }, + "jss-plugin-global": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.4.0.tgz", + "integrity": "sha512-b8IHMJUmv29cidt3nI4bUI1+Mo5RZE37kqthaFpmxf5K7r2aAegGliAw4hXvA70ca6ckAoXMUl4SN/zxiRcRag==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0" + } + }, + "jss-plugin-nested": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.4.0.tgz", + "integrity": "sha512-cKgpeHIxAP0ygeWh+drpLbrxFiak6zzJ2toVRi/NmHbpkNaLjTLgePmOz5+67ln3qzJiPdXXJB1tbOyYKAP4Pw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.4.0.tgz", + "integrity": "sha512-j/t0R40/2fp+Nzt6GgHeUFnHVY2kPGF5drUVlgkcwYoHCgtBDOhTTsOfdaQFW6sHWfoQYgnGV4CXdjlPiRrzwA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.4.0.tgz", + "integrity": "sha512-w8504Cdfu66+0SJoLkr6GUQlEb8keHg8ymtJXdVHWh0YvFxDG2l/nS93SI5Gfx0fV29dO6yUugXnKzDFJxrdFQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.4.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.4.0.tgz", + "integrity": "sha512-DpF+/a+GU8hMh/948sBGnKSNfKkoHg2p9aRFUmyoyxgKjOeH9n74Ht3Yt8lOgdZsuWNJbPrvaa3U4PXKwxVpTQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.4.0" + } + }, + "jsx-ast-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", + "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", + "requires": { + "array-includes": "^3.1.1", + "object.assign": "^4.1.0" + } + }, + "jwt-decode": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.1.tgz", + "integrity": "sha512-EaH9dTD9ogCmxZRdiTsIUIJslqjoFfk8nEAi+Bq8u/aUjrVuhZ6eZjhWRH6SC9NBA0Lwr3K35H2zDnWvK/n4vQ==" + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" + }, + "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" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "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" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" + }, + "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==" + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "requires": { + "leven": "^3.1.0" + } + }, + "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" + } + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "loader-fs-cache": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", + "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "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" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "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": "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" + }, + "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" + } + } + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.0.tgz", + "integrity": "sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ==" + }, + "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.1", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", + "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", + "requires": { + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "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" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "requires": { + "tmpl": "1.0.x" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "merge-deep": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", + "integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==", + "requires": { + "arr-union": "^3.1.0", + "clone-deep": "^0.2.4", + "kind-of": "^3.0.2" + } + }, + "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": "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" + }, + "dependencies": { + "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==" + } + } + }, + "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": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "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==" + }, + "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.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "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" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=" + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "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" + }, + "dependencies": { + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.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=" + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "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" + }, + "dependencies": { + "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==" + } + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", + "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", + "requires": { + "lower-case": "^2.0.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" + }, + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "node-releases": { + "version": "1.1.66", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.66.tgz", + "integrity": "sha512-JHEQ1iWPGK+38VLB2H9ef2otU4l8s3yAMt9Xf934r6+ojCYDMHPMqvCc9TnzfeFSP1QEOeU6YZEd3+De0LTCgg==" + }, + "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": "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" + } + }, + "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" + } + }, + "notistack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.1.tgz", + "integrity": "sha512-2T1WkokzRCM8N9EdueaXja160IMFIMHVhRu0fGkDje7qCzwBHlTMZY2NULQzB2GFOO6iGVzl5GCX2XrJIzI8bw==", + "requires": { + "clsx": "^1.1.0", + "hoist-non-react-statics": "^3.3.0" + } + }, + "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" + } + } + } + }, + "object-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", + "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==" + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" + }, + "object-is": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz", + "integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "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" + } + } + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", + "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.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.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.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" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA==", + "requires": { + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "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" + } + }, + "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=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "requires": { + "p-reduce": "^1.0.0" + } + }, + "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-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=" + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "param-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", + "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", + "requires": { + "dot-case": "^3.0.3", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "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" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + } + } + }, + "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": "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" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" + }, + "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.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", + "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", + "requires": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "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": "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" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "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": "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" + } + }, + "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=" + } + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" + }, + "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.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "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" + } + } + } + }, + "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": { + "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.1.0", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", + "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", + "requires": { + "postcss": "^7.0.0" + } + }, + "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" + } + }, + "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": { + "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": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", + "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", + "requires": { + "postcss": "^7.0.0" + } + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "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": "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" + }, + "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==" + } + } + }, + "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=" + }, + "promise-polyfill": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.0.tgz", + "integrity": "sha512-OzSf6gcCUQ01byV4BgwyUCswlaQQ6gzXc23aLQWhicvfX9kfsUiUhgt3CCQej8jDnl8/PhGF31JdHX2/MzF3WA==" + }, + "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": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-app-polyfill": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz", + "integrity": "sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g==", + "requires": { + "core-js": "^3.5.0", + "object-assign": "^4.1.1", + "promise": "^8.0.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.3", + "whatwg-fetch": "^3.0.0" + } + }, + "react-app-rewired": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.1.6.tgz", + "integrity": "sha512-06flj0kK5tf/RN4naRv/sn6j3sQd7rsURoRLKLpffXDzJeNiAaTNic+0I8Basojy5WDwREkTqrMLewSAjcb13w==", + "dev": true, + "requires": { + "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==", + "dev": true + } + } + }, + "react-dev-utils": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", + "integrity": "sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ==", + "requires": { + "@babel/code-frame": "7.8.3", + "address": "1.1.2", + "browserslist": "4.10.0", + "chalk": "2.4.2", + "cross-spawn": "7.0.1", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "2.0.0", + "filesize": "6.0.1", + "find-up": "4.1.0", + "fork-ts-checker-webpack-plugin": "3.1.1", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.1.1", + "immer": "1.10.0", + "inquirer": "7.0.4", + "is-root": "2.1.0", + "loader-utils": "1.2.3", + "open": "^7.0.2", + "pkg-up": "3.1.0", + "react-error-overlay": "^6.0.7", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "browserslist": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.10.0.tgz", + "integrity": "sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA==", + "requires": { + "caniuse-lite": "^1.0.30001035", + "electron-to-chromium": "^1.3.378", + "node-releases": "^1.1.52", + "pkg-up": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "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==" + }, + "inquirer": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", + "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + } + }, + "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==" + }, + "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" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + } + } + }, + "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": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-dropzone": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-11.2.4.tgz", + "integrity": "sha512-EGSvK2CxFTuc28WxwuJCICyuYFX8b+sRumwU6Bs6sTbElV2HtQkT0d6C+HEee6XfbjiLIZ+Th9uji27rvo2wGw==", + "requires": { + "attr-accept": "^2.2.1", + "file-selector": "^0.2.2", + "prop-types": "^15.7.2" + } + }, + "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-form-validator-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/react-form-validator-core/-/react-form-validator-core-1.0.0.tgz", + "integrity": "sha512-J+itG0oD/6VikXWJlOyjpoe3QaB35iX2WeFuQ1psxyJ5KkjMncBcOjUw/lemW8dYCOC7vQTFGUjlvwkGenTgig==", + "requires": { + "create-react-context": "^0.3.0", + "promise-polyfill": "8.1.0", + "prop-types": "^15.0.0", + "react-lifecycles-compat": "^3.0.2" + } + }, + "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-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-material-ui-form-validator": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-material-ui-form-validator/-/react-material-ui-form-validator-2.1.1.tgz", + "integrity": "sha512-4+W6dbRVyfUnWPHaBWJTLo6LTyim/ZyCWre/GUuBalbH0l4KMlOO7VUcz+h9Vy4cTQT1/TQIxzdfitD5Y+nYMw==", + "requires": { + "prop-types": "^15.0.0", + "react-form-validator-core": "1.0.0" + } + }, + "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" + } + }, + "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": "3.4.4", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.4.tgz", + "integrity": "sha512-7J7GZyF/QvZkKAZLneiOIhHozvOMHey7hO9cdO9u68jjhGZlI8hDdOm6UyuHofn6Ajc9Uji5I6Psm/nKNuWdyw==", + "requires": { + "@babel/core": "7.9.0", + "@svgr/webpack": "4.3.3", + "@typescript-eslint/eslint-plugin": "^2.10.0", + "@typescript-eslint/parser": "^2.10.0", + "babel-eslint": "10.1.0", + "babel-jest": "^24.9.0", + "babel-loader": "8.1.0", + "babel-plugin-named-asset-import": "^0.3.6", + "babel-preset-react-app": "^9.1.2", + "camelcase": "^5.3.1", + "case-sensitive-paths-webpack-plugin": "2.3.0", + "css-loader": "3.4.2", + "dotenv": "8.2.0", + "dotenv-expand": "5.1.0", + "eslint": "^6.6.0", + "eslint-config-react-app": "^5.2.1", + "eslint-loader": "3.0.3", + "eslint-plugin-flowtype": "4.6.0", + "eslint-plugin-import": "2.20.1", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-react": "7.19.0", + "eslint-plugin-react-hooks": "^1.6.1", + "file-loader": "4.3.0", + "fs-extra": "^8.1.0", + "fsevents": "2.1.2", + "html-webpack-plugin": "4.0.0-beta.11", + "identity-obj-proxy": "3.0.0", + "jest": "24.9.0", + "jest-environment-jsdom-fourteen": "1.0.1", + "jest-resolve": "24.9.0", + "jest-watch-typeahead": "0.4.2", + "mini-css-extract-plugin": "0.9.0", + "optimize-css-assets-webpack-plugin": "5.0.3", + "pnp-webpack-plugin": "1.6.4", + "postcss-flexbugs-fixes": "4.1.0", + "postcss-loader": "3.0.0", + "postcss-normalize": "8.0.1", + "postcss-preset-env": "6.7.0", + "postcss-safe-parser": "4.0.1", + "react-app-polyfill": "^1.0.6", + "react-dev-utils": "^10.2.1", + "resolve": "1.15.0", + "resolve-url-loader": "3.1.2", + "sass-loader": "8.0.2", + "semver": "6.3.0", + "style-loader": "0.23.1", + "terser-webpack-plugin": "2.3.8", + "ts-pnp": "1.1.6", + "url-loader": "2.3.0", + "webpack": "4.42.0", + "webpack-dev-server": "3.11.0", + "webpack-manifest-plugin": "2.2.0", + "workbox-webpack-plugin": "4.3.1" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^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=" + } + } + }, + "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==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "requires": { + "util.promisify": "^1.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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=" + }, + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "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=" + }, + "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": { + "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" + } + }, + "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" + } + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "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=" + }, + "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": "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" + } + }, + "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" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, + "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" + } + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex": { + "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" + } + }, + "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": { + "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" + } + }, + "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==" + }, + "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" + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "requires": { + "xmlchars": "^2.1.1" + } + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "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": "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": { + "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=" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "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" + } + }, + "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": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "requires": { + "is-buffer": "^1.0.2" + } + }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=" + } + } + }, + "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==" + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + }, + "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" + }, + "dependencies": { + "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=" + } + } + }, + "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=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "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" + } + }, + "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==" + } + } + }, + "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" + } + }, + "sockette": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/sockette/-/sockette-2.0.6.tgz", + "integrity": "sha512-W6iG8RGV6Zife3Cj+FhuyHV447E6fqFM2hKmnaQrTvg3OydINV3Msj3WPFbX76blUlUxvQSMMMdrJxce8NqI5Q==" + }, + "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" + } + }, + "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.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "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.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-resolve": { + "version": "0.5.3", + "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" + } + }, + "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=" + }, + "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.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==" + }, + "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": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==" + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "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": { + "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.prototype.matchall": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz", + "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", + "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "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" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", + "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + } + }, + "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": "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" + }, + "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-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-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": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + } + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "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=" + }, + "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" + } + } + } + }, + "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" + } + }, + "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" + } + }, + "terser-webpack-plugin": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", + "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", + "requires": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.3.1", + "jest-worker": "^25.4.0", + "p-limit": "^2.3.0", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.6.12", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "requires": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "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-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "requires": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.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" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "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": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "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" + } + }, + "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": "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" + } + }, + "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": "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" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "ts-pnp": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", + "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==" + }, + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "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.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "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=" + }, + "typescript": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", + "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==" + }, + "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" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "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=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "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": "2.3.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.3.0.tgz", + "integrity": "sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog==", + "requires": { + "loader-utils": "^1.2.3", + "mime": "^2.4.4", + "schema-utils": "^2.5.0" + } + }, + "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" + } + }, + "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": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "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==" + }, + "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" + } + }, + "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": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, + "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" + } + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "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": { + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true + }, + "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" + } + }, + "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" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "optional": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "optional": true + }, + "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" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, + "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" + } + } + } + }, + "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": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "webpack": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.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.1", + "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.6.0", + "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==" + }, + "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" + } + }, + "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": "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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=" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "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": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "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" + } + }, + "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": { + "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" + } + } + } + }, + "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=" + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "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" + } + }, + "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" + } + } + } + }, + "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" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "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" + } + }, + "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==" + }, + "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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "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" + } + }, + "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" + } + } + } + }, + "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" + } + }, + "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": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "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": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz", + "integrity": "sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-broadcast-update": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz", + "integrity": "sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-build": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-4.3.1.tgz", + "integrity": "sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw==", + "requires": { + "@babel/runtime": "^7.3.4", + "@hapi/joi": "^15.0.0", + "common-tags": "^1.8.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.3", + "lodash.template": "^4.4.0", + "pretty-bytes": "^5.1.0", + "stringify-object": "^3.3.0", + "strip-comments": "^1.0.2", + "workbox-background-sync": "^4.3.1", + "workbox-broadcast-update": "^4.3.1", + "workbox-cacheable-response": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-expiration": "^4.3.1", + "workbox-google-analytics": "^4.3.1", + "workbox-navigation-preload": "^4.3.1", + "workbox-precaching": "^4.3.1", + "workbox-range-requests": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1", + "workbox-streams": "^4.3.1", + "workbox-sw": "^4.3.1", + "workbox-window": "^4.3.1" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "workbox-cacheable-response": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz", + "integrity": "sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-4.3.1.tgz", + "integrity": "sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg==" + }, + "workbox-expiration": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-4.3.1.tgz", + "integrity": "sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-google-analytics": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz", + "integrity": "sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg==", + "requires": { + "workbox-background-sync": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1" + } + }, + "workbox-navigation-preload": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz", + "integrity": "sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-precaching": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-4.3.1.tgz", + "integrity": "sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-range-requests": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz", + "integrity": "sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-routing": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-4.3.1.tgz", + "integrity": "sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-strategies": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-4.3.1.tgz", + "integrity": "sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-streams": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-4.3.1.tgz", + "integrity": "sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-sw": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-4.3.1.tgz", + "integrity": "sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==" + }, + "workbox-webpack-plugin": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz", + "integrity": "sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ==", + "requires": { + "@babel/runtime": "^7.0.0", + "json-stable-stringify": "^1.0.1", + "workbox-build": "^4.3.1" + } + }, + "workbox-window": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-4.3.1.tgz", + "integrity": "sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "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": "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": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "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=" + }, + "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" + } + } + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "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==" + }, + "xregexp": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.0.tgz", + "integrity": "sha512-83y4aa8o8o4NZe+L+46wpa+F1cWR/wCGOWI3tzqUso0w3/KAvXy0+Di7Oe/cbNMixDR4Jmi7NEybWU6ps25Wkg==", + "requires": { + "@babel/runtime-corejs3": "^7.12.1" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "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": "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" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "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" + } + }, + "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=" + }, + "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=" + }, + "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" + } + } + } + }, + "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" + } + }, + "zlib": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz", + "integrity": "sha1-bnyXL8NxxkWmr7A6sUdp3vEU/MA=" + } + } +} diff --git a/interface/package.json b/interface/package.json new file mode 100644 index 0000000..b4080e1 --- /dev/null +++ b/interface/package.json @@ -0,0 +1,57 @@ +{ + "name": "esp8266-react", + "version": "0.1.0", + "private": true, + "dependencies": { + "@material-ui/core": "^4.11.0", + "@material-ui/icons": "^4.9.1", + "@types/jwt-decode": "^3.1.0", + "@types/lodash": "^4.14.165", + "@types/node": "^12.12.32", + "@types/react": "^16.9.56", + "@types/react-dom": "^16.9.9", + "@types/react-material-ui-form-validator": "^2.1.0", + "@types/react-router": "^5.1.8", + "@types/react-router-dom": "^5.1.6", + "compression-webpack-plugin": "^4.0.0", + "jwt-decode": "^3.1.1", + "lodash": "^4.17.20", + "mime-types": "^2.1.27", + "moment": "^2.29.1", + "notistack": "^1.0.1", + "react": "^16.14.0", + "react-dom": "^16.14.0", + "react-dropzone": "^11.2.4", + "react-form-validator-core": "^1.0.0", + "react-material-ui-form-validator": "^2.1.1", + "react-router": "^5.2.0", + "react-router-dom": "^5.2.0", + "react-scripts": "3.4.4", + "sockette": "^2.0.6", + "typescript": "^4.0.2", + "zlib": "^1.0.5" + }, + "scripts": { + "start": "react-app-rewired start", + "build": "react-app-rewired build", + "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" + ] + }, + "devDependencies": { + "react-app-rewired": "^2.1.6" + } +} diff --git a/interface/progmem-generator.js b/interface/progmem-generator.js new file mode 100644 index 0000000..674adae --- /dev/null +++ b/interface/progmem-generator.js @@ -0,0 +1,122 @@ +const { resolve, relative, sep } = require('path'); +const { readdirSync, existsSync, unlinkSync, readFileSync, createWriteStream } = require('fs'); +var zlib = require('zlib'); +var mime = require('mime-types'); + +const ARDUINO_INCLUDES = "#include \n\n"; + +function getFilesSync(dir, files = []) { + readdirSync(dir, { withFileTypes: true }).forEach(entry => { + const entryPath = resolve(dir, entry.name); + if (entry.isDirectory()) { + getFilesSync(entryPath, files); + } else { + files.push(entryPath); + } + }) + return files; +} + +function coherseToBuffer(input) { + return Buffer.isBuffer(input) ? input : Buffer.from(input); +} + +function cleanAndOpen(path) { + if (existsSync(path)) { + unlinkSync(path); + } + return createWriteStream(path, { flags: "w+" }); +} + +class ProgmemGenerator { + + constructor(options = {}) { + const { outputPath, bytesPerLine = 20, indent = " ", includes = ARDUINO_INCLUDES } = options; + this.options = { outputPath, bytesPerLine, indent, includes }; + } + + apply(compiler) { + compiler.hooks.emit.tapAsync( + { name: 'ProgmemGenerator' }, + (compilation, callback) => { + const { outputPath, bytesPerLine, indent, includes } = this.options; + const fileInfo = []; + const writeStream = cleanAndOpen(resolve(compilation.options.context, outputPath)); + try { + const writeIncludes = () => { + writeStream.write(includes); + } + + const writeFile = (relativeFilePath, buffer) => { + const variable = "ESP_REACT_DATA_" + fileInfo.length; + const mimeType = mime.lookup(relativeFilePath); + var size = 0; + writeStream.write("const uint8_t " + variable + "[] PROGMEM = {"); + const zipBuffer = zlib.gzipSync(buffer); + zipBuffer.forEach((b) => { + if (!(size % bytesPerLine)) { + writeStream.write("\n"); + writeStream.write(indent); + } + writeStream.write("0x" + ("00" + b.toString(16).toUpperCase()).substr(-2) + ","); + size++; + }); + if (size % bytesPerLine) { + writeStream.write("\n"); + } + writeStream.write("};\n\n"); + fileInfo.push({ + uri: '/' + relativeFilePath.replace(sep, '/'), + mimeType, + variable, + size + }); + }; + + const writeFiles = () => { + // process static files + const buildPath = compilation.options.output.path; + for (const filePath of getFilesSync(buildPath)) { + const readStream = readFileSync(filePath); + const relativeFilePath = relative(buildPath, filePath); + writeFile(relativeFilePath, readStream); + } + // process assets + const { assets } = compilation; + Object.keys(assets).forEach((relativeFilePath) => { + writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source())); + }); + } + + const generateWWWClass = () => { + return `typedef std::function RouteRegistrationHandler; + +class WWWData { +${indent}public: +${indent.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) { +${fileInfo.map(file => `${indent.repeat(3)}handler("${file.uri}", "${file.mimeType}", ${file.variable}, ${file.size});`).join('\n')} +${indent.repeat(2)}} +}; +`; + } + + const writeWWWClass = () => { + writeStream.write(generateWWWClass()); + } + + writeIncludes(); + writeFiles(); + writeWWWClass(); + + writeStream.on('finish', () => { + callback(); + }); + } finally { + writeStream.end(); + } + } + ); + } +} + +module.exports = ProgmemGenerator; diff --git a/interface/public/app/icon.png b/interface/public/app/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..13dd442c80a693e407fb8c2615f699e4639d3eea GIT binary patch literal 8940 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 literal 0 HcmV?d00001 diff --git a/interface/public/app/manifest.json b/interface/public/app/manifest.json new file mode 100644 index 0000000..f775661 --- /dev/null +++ b/interface/public/app/manifest.json @@ -0,0 +1,12 @@ +{ + "name":"ESP8266 React", + "icons":[ + { + "src":"/app/icon.png", + "sizes":"48x48 72x72 96x96 128x128 256x256" + } + ], + "start_url":"/", + "display":"fullscreen", + "orientation":"any" +} diff --git a/interface/public/css/roboto.css b/interface/public/css/roboto.css new file mode 100644 index 0000000..ac21f0f --- /dev/null +++ b/interface/public/css/roboto.css @@ -0,0 +1,22 @@ +/* Just supporting latin due to size constrains on the esp chip */ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/li.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; +} +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), url(../fonts/re.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; +} +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/me.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215; +} \ No newline at end of file diff --git a/interface/public/favicon.ico b/interface/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..399ccae7c23cffc07389cf431b329ac611fc6c01 GIT binary patch literal 1150 zcmbu8OK4L;6o#iLcHyQVh)XxpMr}a^MFcmxsJeDh7b^J3y~G;=0Uv0kP0>gji3!yR zzFMs`%|aW~)JLoBPEgQ=dTmK)T3WE!`lv3u_&xtkCXH>Rpt<~aCg+^*%-l0`l&X-Y zs!GXwy)srRwN@!rBNCHX@^%@N65pEDc{%?}UIE*sM3tg?QCu`7nlFg+ZV`QqDUt!Z zh8(p{6cv3F8=6HN7v?UR)91u6Rs}vfoMw|^V+?{LThKbXU9=6CN4BDEbO$bes&jmW zm|hw4Ic(P|nR8vo-(+tZ6Lg@W`3U7XNA(q=Od#WzYL5A#J(O2^HpMO<{ zXrCANp0%RmX%IKkXOI|(;Zm{zjjwAAh)}wFw0&b?7|H^j^wjecq4w1}my*_!_e>J)$ zj^e|w6gtx(;oZgWw=4@@uNNMV2l1B?y#M(acXADSeeRz%K#RQz;p{Gi9-V+uQa_*1 z2fyDB%Q}hhljFFO*(tFb^*NGVbbhseoL?+`8a>7H+bo<@H}d-Y{`da;%l+kDFWlcH t{qudHXO`(7={^0EeB1|nll3UqzqBps-|udPew8T0RR9106b6t5&!@I0E>VC06Xgd0RR9100000000000000000000 z0000QWE+`49D_;*U;u_p2v`Y&JP`~Ef!8#FzhDc4UH}q-cmXy7Bm;*w1Rw>1d22OL!bWWbQ(raAW9U)b&bi^E;Mx3;sOZ9*kHOTKHefe$%B>b=Wfai7lKSxdIhGr}M4@_rSdIxTm&+Li6QCm;I$ zDZqkhB)gOBqWw(~qLNrL2B>9W2Oh%1H`l*5H`6(JKvUv;E|75hPkws)l6-qSBA2cBc9Dsn-3F#xGR!jX~_C5MoA_X4q00(Iw*LU*-FU+LJDNo6=m z(TiepR^&g{v@&4a=9Zd@Weox%!HJoaX6oz8v1Zx&>$0Xb*8>$r`V4~zBQ$g}G<$ z8J5Fq9-RGCF>en462sJSMd@NjWmoz?lnIZajGL=F86vL4t{dixfpH zmPDL*iIT0f${K6Q^*QFa6HYqiw0>utbB&d@jk^%d3v1 zhJm>;5K)5szrnpPQ(L?Q*U;biKpewnhk;>h8Zy^ z^M&K4=Nw7ii_Z%+nm9y#B+D&K$b=hfQgw!Ip4VM z{}?eZk1z_e$*cTY!|^I*hGA%e4lS>(uVzHnC}G@QDc#&{tGwuMOc%z#uf6NV35AI( zuzltVR4r7{{6ebIe8qsolb#HB{X5aC^0@Y7?FBHWxw=p9zN&I{KcQkl$3Ln=RnVh~ zoT0klcxTRS-kzJiDk@LP6m9L~=@WU77bv&kovM}vo{!RX&%&-`*wLQ3kBhsT!5of@ z@>TurPX($cP2vV>T%La<{;lRbM{95^uG%o*as1&0R@Iy`yO78%MN<iBuRA1$f#Lq6+^47W@3%C z46U<{2?Cg8a{B7~oPs&+G?sqn5U#iZx#UaTLY?1l?fh2~21R zE!3LNAl!Vsg5jf-2&>+9nY=|_2iE?KiT40%m)gBc}u4 zF!ikfK}nQ+g84`rd_=mOB*?eH2?^AVf6rifrgx9>zC(4xgyxq{7F$$=9ur~j=wL{y zNheEgriUKl5cZLCfNML&U^d&Vw%S)!e6biGnzq|!s~vXQWw$-{=BFXXANPKhiWH+9 zaM1r9au^2Tm;wOryrGEz#EZ)rpi_D$;P0Drcv*ehu^w3Ho#hP+uMHQ1KbUqn9sU8# z*;N#f&}#sIcFCePiiB5R&1Aolo~QYe(Oqam1i%A{#t49pT3zmcw5MHk%dq!UXfeb! zQ;+NEsT|UnG$p5z=A;+NCyU8F=cG!75+vOZv`@cFZX5AI$f)6Zq!Br})boi)zGaX> z&eF^op!(tY^ycE?_5bC+hu^DJrBazAt=x7>EeUCmnDbKe6GJ)+R6twsB)+jSWA))=L6G841`0NQ&mwE&@m4)_@)fLhYq zu1}88%^uR_UXHSl)8x_51^VPg8n|R{$=KU~oI5<^GLKNu$NZe zg!c@{547=-Z@lI^KWOJCe;JkkkV%!4iO>bY!l4_uQCJlArm!UJLt$yy$HKCaM{uOD zeB`klFRUDSA}0%LB2O3AN1iQg75H?3XCj2k*b)mCqhyM|}Seq+OidbF3 zwJ0hZh4=QovD0ps)G~#zU=XKx_j7Faz-Z zpfn;R2M}5!l_OOP{*(h6cyf|0g?J<>n8&A3iY$rJ@BvL}v^Gzs!zUfYvvg_Dyg~Y*2+*< zW@5wqRWnFsGNFDtm#Q~yCbH?$=R*3|Do4;Q;6IMS%>;5(ACbxG12IZq z?4dU2V}M`+d!KcLfI}w6;xLYzM?@0I)8WOu?7u4NG^Ru*a53rZ9^DRZbt7y>n^Q%81fxLC_-Lejru=Mf;B% zP&5)y)EH4c)s_b;Y6QlOm5T}dLdaTKdibDgqBvmVIyLJHDbFRN)EJ;@On_B(ghqXF zyN|^|c|rA0w%7@Ci2IbHGVXQIK(m2jyA9+j?2^K5q*`(}*>&pjT|cqeOMpx~b6ACuF^^Q`hqAnS*(tn4&t1C66LCtn zcp_dq(hOMI>Z5_oGnXT#V!TjEBgj2QWCHA<;RvSG?aL@~!3l>oxhh3%KuUKo;9>~1 z$zE*@oP?Oqr-$bj=yP+b+dSlRX`~Ku4F@eTEzJUElZl)e&}4M-P3=LiiwsgRUB79r+306LlZ54+<~AL*XtZNfO# zvZ`jY+5WSscqaJ1*{|D;_whfS({9t&%OkxnvSBAgrVMj8C$?*|`pUFx$A4m1;uI`y z8m!Dti88LKZUfw{D%XKxTN)^yWV;0@Hh*J&VAr!D%1NjDbdU%uO&C#(mS?}WdW`?IOcwWwY7|@MU%#V0> zOX3G!v4Ml?c&f>bkN+*(Z6N2NEIuP#qY<0vGGe zoJj`gQ>EE7nFR&2^kQ@8#A1X)#Q`6a7n8?4@awWb5d6?y;{eB%Y& z8a#_C6TA1=JUVS0&?p11+s9SX)|tFeE3X zp)AGVk735~4WboEBMBe#hhuz8WGR~k0$~OrZE;|{^RFnjYkt5S58^xHqG3JsNplXR z4d4y|njE~rN52Z_q9B81H@ZvaY`NrplE$f(6*x`4PA13Gwpv%V zr(N&_JHm(8ROy^AM4gMZ4v!~;LbeHP={YhD*IJbPkK1FqMSvMW)o~WVS7b{JX?O&R zd1SPpCD0ZzFoK2fDk4^fyf((emdxWh=_|fwBNQ}}N!8GX@Y}$o(hrQs`e1#dipzM2 zNaVo=2R8R=F)~jQ)1?g-#4ufaKF1Xe`_$`Wmq4E>YiU$a8-hlG$-O>cLDlWc%@+|& zQKpzGM4gg`ssa`c!IuN!#sJ3Nynt@r<1PF5R^4nQcmcdZSgKBLuD!T0n+P2>kREQV zl7b`PN`5qqEz~q!_n~po!hkZ406nGcl%?CrRZID8CgsUwe8*I{?jhfMn_W&*H zCXSe*Gv+q^S!pw2HoYM?^agHN=!N+$woAWie8uB-We8N2W|0^B=D%S9LSvw6NBeh^j!u!0Jcsj43I;&gst zL^9V*YJbr=UWh62Ih^72LeuOhOGL*s5-8}+J)dtrDmMs+6p%2*Hu76%1_ao1C1bCU zPT=2_^_nt_g<*$oAoi`^EjXZl8i!EM$S;NKqlWE3#v9>Hi!O?ill4G#I(6dUHwX|= zSSpw{7>|s{-6>_-jc*c9_e3u!ITwcB7FO^8<(?tA#MlyUQs8O%TNoljzXmXh8Ikvh zH~LV8aY?wDQn4ORbkyGg38RQqwHCQU;#MUx-%!i*06|TOqXPg!jn!xs^L{)1alJT7 zOot?j6OI%SfD99+Omn!xh~tXFsU^oD!`)|#p%+}mrb1q4nM617{`)?Z!yU`RzFYgB z=(+bD2v&2h4HJ@qgerd;{QX$|Khdw$qwak3)^3CR{zni?$jufRZ&`~bDjR1PF73RE zS-8Br|M@Jvx}h(JTT{dY^V5Q2Y9gJBa7{~d!kwqk!*e_CJemfpM1n@Hu#_QnwJfQw z{YO`Ox=lh&JCo7K%M6wZ#L#`bP++iKAQtrWz|m1ElUhl2ZQpuYGi`be=}3v74$1p} zqENeF4At8cOAGrxVy~k~CEM#nAF?>?jdN~tD;IT@XI-je<~3*5GIH1b3I+&2>UPaM z&tv5~JFWOo);`}ChBJq%Xl*0@?T!}KB{%MGOxBhpch`t>cyVdXNnw8@bL^cXaDJf_ z7GsxEk({odgvuJsjx2}Ugo+!U47;PQX4;9}=CaZ_?z$!j z{0KY(0tC6RfcU<5FZ@tmz$e!#F0$V@v%Zd7cxAAJ&WN60A}7y1To+;3A3LuUFZ_*| z1UtmUmfO0rJ+iB-i?W4H9FRmBm`5{a9^V+krwAw-9Hp$jgu%~mmXdB_V+NRD)_7-G zCBLS$V4%DQOgxu(?J@c>5hQk4sw@6UR#Uul*z}CQ{jHbQ(>Dnu{nu2N>gkvN+u_H5 zZ;ia(lpCSQ74gb)t7@iu>$>JEyjbd1M))(LLHsUB8>iiJ-tPT=l(9!L*SYw|)9mpGL5ho9zuT!!YAB7fH#&2sM^^ z=_q^f@8k8&KLbO|{BgE=gj&3iBzkcz;nfXE#Rci(o!X<9_V+i{Rt`3brCYK1Eotek zb;${>l^LA&s^s(L4JLuZ7y@%R9=ny67yWuBDe2Bivi5raf&P70kW%1iVcKv{+F z5Y+&otqA$GCyg8ui-!6~jE`hzd}LkU)e!UV6gSF=qV8y_e^Hj=9Ph&@`=EY9z6eo< z+;rcVOg!+tify=jC!kA1c-$p*Q6Kj!>!q+|yRp{3r~LR=Usb71Te+p%e>_D*+V}hX z@Gt-Qq{&pv>lI$wS4A0oxIge$U-RE)=u z|4`hI81y97^ws5Z1XWdW7}s*K9hs@wohe-~qQl3F2cPc${G#DUH%Ap1IXS`6_}9?# zYS$nA=S(d!dghgir0~z6#^m^9-~K-HK7gP~yN@)~=uD(dR%;z^9N2T#=E2@)`*bA| zezR;J0D-;}18wfRahU)?rQ)|K?esQkXyvss0D?-xZ$G!)(n+__?0c1gB3UjrDI z>*xiEZS8q-XpV8XcBP58^!AhtzlHekZdOJuNzd-20m#9LA>T6xOa~YMK{2?dT&BD8 z@HCIXL;~jjpWc1Fa`o}OSw>BBO=(tVFJ!as|GU@cWq&{AJ=%?XDnmGGP}LGg7cN9JN9T!* z`Ai*1W7~hv>~kfv+4_(sSD<^Lir7TlZs`fN)x{6i+GXPJwO7_(s&BW|cXiWo*+0CI zdcL^)=lO?%EL!(qTUqIV@DilP#W^Wst>6sDS>~CigDT)=;MF45o1+O#_3E6N*AD5; z)|-n1Qq~rvcbRLi)f#UE@`BvC^KZSB+*-_Tyq2LF5xz57mpmI=Ie0m{VzRBvKgW(>G*2fmDxP+Y zwl5cB?5u1)gBLRVMg24{MaTZE;1RH*?$!%x>9f7RB%ZyFyVbY8fLmMaxos5P&E_6$ z`qOsmsUSxDyiC)ZO4r;vcLO@5M}Vg2oxP>=SdOZ~KHw#Y+1o@povWC;?=&UmfR%ua zP=VQ&V+*&IKfEg9G1?dfA74FMF7ya3KC*e3d-8GiX~yZ3o7n|=@36_ZgMsHHURmSs z`&u8res}|*k8fb?0X4b(X>m!4rYxmZ0tKY%9RM}C17;JTk8i3R_L6^mfvSGpPwhHY zp{JfW4s?7Xm~$#S+sUV ztQ*)&I_>x#Q$9pd4}N!D2)V*0_@~j+P4(sfK2RNgMBz!SBm#7xr;`K^$L^n&q>Ei| zeo;!PC8|cgKrB8fYI%v#aAmb-OXX1{LP-rn{*l*ySo}KOMfiFQ<_haX17$v zHwa&DDy|BjJ4Gn}d8j^qhs;OP0Xh(Ax#Y$NgHJR8kiOdduJm5O#Giz_cS?D0!i=Gr z_c@GDYc;CCpO3ig>1R7$T1Xs_Z+z(rF0e9iw7-x%vIqKy(>D!m$=FHT$eToeQgnxQ zC%3eAm0H%xq#rQ|i;5$qiKU6%#6>9od#E~ok9=8jBk}b5%g>idODMR9xedGWatTi$ zwke%ldw1xu#{Y7&0%QEAzguNhM-uEQrR{+w!-ISAQJrm*z`2X`SzuXtPAZ{2Q z4YI{c;07S8PfsJ&Cn&R@fpAdn30%C-FieDtcI{~4o(Rn<@aNOa?3>%Qe;wKk{(8d6 zxv^vEPgkFq`_bFr_jmmO(|@^{7*RL>>zb9R!VJG`L-%Qws&s&OOpq+2^6yXFRg$EO zueQA}i>}72p`_IlYD1z*TR-IEIdJk0sYP-HaWDW>rj_3q!SDOTM(ewh8^{59&EOgw zzO?OKl$!WeZw+Dv^JL6(I-CZ%6g0Y_zht9t21RfqP8ilWJCfWIuC?$)w}p8ivW68K z!^L^J#rVSQsyrNMo*8!=g~P9UvOy_a12v6R9u>6@?XvG-=)-kCQy<6U=CTs058W69 zZq~+Z=2~NgK(m#f(Fi@Q_0&IO9Ui4_3l~ z5IGA&j2!gr5z>C#&d0_~=oL6-Pnh4r;vOgh18ssc5bu)|d$`f^Y~>u-JZwIPr5r7v zK}6c9O`-P+fmzI$B%>Jil1C<_wPgl^iyc4jK!x2T=C`Kev2`S z-wzBwJ4|wJ*Kc_;@Idm{+bn%=ux*Q{r{x^_XLZYHqAl~BsLn@K9}!9;MgXh3htlj* zjQriqjgk82eX*=4ct;ljD4xWWDMl*{J1!IR^p($li^;z`=-BV zW21|~DK1Q86$&b4xDp)6T9E2wGwVuv)Kpqg?derh$Kc(0oYKx~_w;UQYs%s`<+Sm= zeA+t`+aBJCZEa}u@-|IkWG1}d%1lUnkQM(fGb`!cJr3}qE$N-vuG^7UGr8|BA}~uB zUyLQgGSoM8DHL%r=Uo=5W+z@QJ_mj)H?sP;9~GAwdD2fOI4ip8_vu?vW9Ka{q>`5C zkgAo=uDZcYl9Od%ty2iH1LMm@qo~>VlU~~XS&{XSv)3N}c(n``jP}$w_oq`_i~>s? zYBVSHhcG@lW$z+(&?pEGYh<0n!g>EAgdNFb@6c2l|9pzfYHItYZ`pBJbYl2kI&LkG zENiUS?Aa9gb@pCWZ>}o~dw4TEzCOo4jnxnt9*K{EJ&Y4Hz?8aMd8fKs^t*-4x(Wi` zB_&azifo^^n zYuj*1Omk8iGoPDg5OB!b$@MJR;B{-_vjTP!JTVD8dL>-*2>PZ*#XfOX_7e4BGbaGqRha-URMM5k&&IG!Y0i+M`s-$>6O({6PPY{gh*?-ar zV|OTU#7i%KC+6&%6CgxKdIvhYcm;kVgLWgGozW4fhzt8{I~+&}M%CidZ;E<73-_^( zzx82ZR(LD6=uK)jVDy`5jbufcO7g3iq|x2D?VevIbc!dr(o6t&p=j;|99Lm!bNUx)=Z>9utCV< zh^)5$*1YPw!X>d?k`#6!JE=JlAG0IxMRyNN5UzqZ2pb|&ryhPlitw*fu8cn7_h-_y zz4MYy^HBZ+{;Qfm#_m`doOnnQ;eujWO82BZk8z@+PB^D8I`H->_~rA z=enTKg)r-=w`KHb>tRd7gC2+N)&1+|e_gx24QnQPcM!JU;*@v&+>h%xQ}X6FY53km z5K!v^1E_6xce&_eE?G5cbtv&v=a3*AJVwj|L?`yfRefH`*@1S#`Kf!p7FVTqLv0R2 z?jBs5`)*s^gQ=9ApGtI6M;}N74_zN`?WhdYtOkES=45j3WE!Oyu&(8^r=R|K68vXM z-}I*q8{`<6TS~^4_ItS(8HS0sGjeXo>@M7->FKXMbyHt&9hjW??tkI?O}nj`q~3Y? znuOy8ygt6>l`ookyq=bxsGV>BiJYXpD6YgPR~M2mkBVqf_mZQtzL}Z6o`oswtd*IL zp1Fmdu4p-!NOgD2i@K=u_5wmIAd>E_YjLW7Tus~5?1J&GXYw}s2$~otfldstZ-dHs zI#|OHpjb+B40;_(cxDZAkCu)B)|a8z4iVm4!+hh!G8*Ygw*nJZ7oS+M%tr78HS*uP zpu;@e(ZLW$RW~%!!xJ6icHp@>G#RfP2gN|V+>UO6a{QfzA05yPISy!dY6peKK^E#P z4{O|W@8-vgH1sLiaLO_A&&g(Dk|zC#v8FM3Btj27>!$aEEG%FFXiA4Ytmmh z6X@N|uVDW00Z9d&un${U*7j?_Jj48sFZh@CPeH%Ad@}=tgI$xKHxuaD-BHfcc{B(R zHk;yU;>A{@zH$XT$A4{Y_dMVoR;`7tDapk=NLOA%!R0iL|2^G=+fMb3^A&tsMM1E9 zFaHeG>|a~|e}jBZKHfKe5I>kJJ~R6OAp^p#-|~ph*5$1D(~mtiQwn0{r_X;o}rf5YI<^NH63f|5oUdG&c@FO zl}C$X$Bw$s$J#fMmQxS|*3`yv z3YsCytv5EVEdcu9rKbXEhWG~=y1>Fi@NQ1Q(RD$na41v`Dt8Eay-S1q!%4vz zyWL6EYiD}C%L2Xk0UPMW$^B?(JRz84{|eNw^I>jekr{GyOu(y+hfKJQgP)0=+H|zf;o5iTU9Fuge(04=vuX%y2>vAXT765i{{wR>6z2r)WA+q$!zC&xl`_vyX79a z*Wb5Q(Sg-Go0*xj_+$U@7RE0bqvJ1ebHp;&2j7GF=VymYN9ZsW7GcGBl<&goEIt*w zgYip7>*h-w^+3)av{hL)+hF_>VVf^Wk_U4Bpp%Q;gS5`RDVt#W8Zppr9TBDJUke@t0USe3`{GVsmMBg0s>E zLJEbC3{qEt3@TFi=1VksAm`hKaAZ}!Ky8CPBZ?#IoS8r(*eC~82X!m9D{e`#0Hs*8 zSuwXQDhVXnR%$@pkx~&SrM3eSo(MJ(rWnH`0^R(p0RV9D_MkKjkbXL#|LfAx%UOAT zpdW+R?tJzi2G_i?DyyddtX8CF&YA*6fOv9s$^gX6g3|l{arNn}ecdrRYDMQd@XIbe$*1hA!KgfjoasDbNAv7HG26j;GH2tDV>C z$Ou?0^Hcq;W~e6PJ-!n%=_{uzZRnX;@6KB~-XDMwpuMqkm4O?Wmo|Xj^-Vst7vO>1 zB<=Zgsl&vH4LsNYde^t13weEA{8sA=bk=@Dr|O>D6Jt4n2Rml<*#z*n))UzqXmSJA zyS~XM{|56HthE)(UYtPe0A%Kkh-36MILAJk`bvLhW5J)0zwXGS^LgPpP`i;Gx;b&Yd!t`@`Vz|X)68y&{D6{iQ!f`xGx zpHd_a-|-dr4v6AH7pY?&j-LdJGg~t_y3o8bW7^H+7iz+2reba#KOO3Ip6}qV#I??kiP|Mb5gsd^{4i$2ps;=P5 z4g_jc3#_VA-;Nl|gd8E4$!R6O4h9KLhE_glzL3o&Gz+7uT4`3E8dAJ4Q`fJA_SAl1 z?E}>n;UDk+(eDoY4@GD+_Pvy)>Wuiz`pJ>$q@x~-yqrxA z78e62e91-0Bm|Vc?TLX*@Zl*dc^PNyPBn*~Nang;~L7|10of?cr7^Qm-yvW@S~ zQ82V#tK=*`{9) zqh(0qLB8H@z^!iw9`o0rSNrrT&6Hk0<_}ya1o!5XMWU-?)1!-5n^ zYOz@(v4ApmhRmU=WL4JDB3J`Elesc~)3&)M$fMb8onB5lFtBq?-xFtWS+oTu0RV$M zxD5b{(v95gG*+(U3@Hgf86Y9YFgWXU6Kzt29<2=>&T~HWq`E`b#2y6U0RVj|7Vn0E zd4v5%Xy~a-x`T^+i;2qHqD92PzTHa0ee}RC^S~!%1pQ91pb6e;h7O zpvKeVSmXk8R_LZm6t3F_Z^>Xa6CWk3eC5Rr*&;!((7Wshsf?m6pnD&J~>}sry#0S4!+LO58r7b6of`Wf4w!N+{V>2kq4F z=t+b6DD5)nKSak$h z+Gn5b;=)a!he!EWy>_pLX~be^a7YY$4msFB`qJN}q5Ibe*x#Dp!nk2T^nqp0-gK9~MgNHu6nK_iF6k0))H8wZR8`g3?Bs95d zX{r5wg=Y#C%{M$_(&(vn)UP6-$d{)Wn{W`rw(4O7yj%DHagszf%XNRB;h)gG(r!7dZ1 zJ(K`giOvOuckKx#Y1$e&5e$qm{FK5%Av`hP7u%9x!lspxRWP<7S%TQ~ea{A8syr3r zt$7TD!&CP!?N1ThY`{@SmDta&2j>Avh7*`U1R|qBV?0i3W$`2glE+A*Nh$A5YBS_+ zk+jG<;+M}!ka2Ivpv~jyklrpVB&5MsX29!F-=Y!~un!|aD=kWk>Wff554lt=SS^cS zS)UTa=p3Ie=+zbt*;G4{Nt?9i*`fII2mqv8=y`ci%{IY)eB6oeB~K%->X9n3W^$Qm zu!)-TGBC~yx?%?-tDcL2=mIcrKQO~>k=m&XQVo9R{<;iYkM zcYN(x{*|U=arLgf-|irceiOz4N;fzdjpVRtT>HDT={xZgUp_49N>6kZUR!OHVYCqn zscE7mwWYB6>mSIR1x4|*P~bb6 z3~<+UhL6V3mtC{#L9h91g^TC=-cT-sqwn^o7R%gywrTHu;Wp^>y!#dTul2%gCu4P; zfAuyJ>T+_Nyi9&350kwO&5N@wRgXQ{HdoaAR0TaXGydb(EBdj^Jo!`ZWT{4Tdlyy? zYbRaicnr6Ggx1gduh_#FuRAw=KGlEde#SAd>V3-narFej8>#gk{)q`Eqk35ptWyP> zENXox90$aq*Fm-~)U8&Xj-If#)}6e}rEoacsbS-iNaX~Wg5^8eo9Y)Ql_=F1Gvm8; zwMv)e)mR_;m@o|_hG;fQ;vxO3#edvH-E(>h65^G&caGKhu0XlQaFs;|ZSSS~tQNyI zASvq?(C&ITC9Hr=0!l9^NJv_Bqc0SZdae|oL)64l6~Kcjp_=_Fr2|f3(y*iPJBPkl zQdI!pHyndH7|-x+zlIN9+$3;bdIzbZ4h4`W`3$^l7rUoiR2mO6xO)_lK3{=DzQ~GbSGS@56zxMkZq_~-(#D6Ggs1vgmdulEJ^8#H>2yhX9}iK zcjjs2eZ5Qx&UWJN>8>N(fjwm-%**Xg=tAtcFV!^LH$nlpA%d?7<&VVHiqb0a`c|1> zJ~2)2YOJ4Ol*ERk^E#G&SK#3ocV^=u>3B|3f}eNkjSh5vnk&Y_nDbnFQ4PvdvvguH zj50NKj0YU7ZO2UeKK$pCeag?^S<&J{`{^aGsDKR1!Uvh`CEqKxoodgN-gYLyrgKd4 z`)Tl<^De+t>7}HJK|22=rMA{4=@e3^tnj}%CSz18k>Ax7ZAm@cF9i8=vAvXr7`&MI z>&WLUUKIiEm|bLcILJy(&kf} zXbjTvY`aF)U#_9s(y=x02{zeR^eH&zLRj$OwEMu*$WIzjxr_1(a|wv+YD_+NlImzq zD?LGM=DMnR-ujgXpFTU-&dK4Xlesq$ng&+*YFiq(QeTR>;O*?%O_ zDW?A%&E24S2;Byt=$vTfaE&cv`sM%Yo0i5 z@uVG0-lX#G!*5=Yp+1c?hcLMlOv2lqkIZ61snjW`;;8!fqz*Ef8kKay>P*%4DfTK! zwxHcw=+ijR&5aADu&E5j+Lj6>uRG99=EJCq+f5f^h^jTo=F(M!|LZa9#c^}cMl?4Q z9$c$;n~v4CjuC*ODH|qZyiZlDuPO|in#lx*fj47=nvkDJ@MSNUHL3hHX~Rtkc8y6dyScyb)1`FYZDv0rJG@kpI{&KHt-;v9 zUM-T&bmVyzd$V~-j>nMhzBy^*4RfRe5hpWZUmNP`fxRnkj`X8{mTP#3uu2Wvhjeth zwNmfut(uD2$Xtu-fCcF`){J+1bEa>VeRl<@E8Xfst)7(&*q;vO(CSu~6^GgKisLL1 zkt5RW+nJhpLrSWvMLZ$}1@tkHkWULy9Fs#cZw>GJg)BT`<=kqAc*UoA{+QY@D!*Dt zD-rYvUj#ng8(7E-i+GLrCgN@8=ehNjyEv9sKF=f0;xZdi<0~Z8^Vm7v9bd@6Bi4vh z#2x2W=VnX|`Ez0mX(WOU5s2px27upf!2pFwQfh@nEQ5#X+jK-U*eFbs5;astj>X-~ z#B%30$V?egMGu;LN0K$4kBOvEN*#+0sTmpBvm+9-)^wVYO3DJ4LSvX%X;&)mBNUO* z4QWlF4IU0iFi@ou4CG8^kN+XmUGkS-{zw1$?_luLGyni_{&$ug0KkJ0_0=!(?*k3v z14RHdU;qFRP`huh4WM!1Kjc5b!NU;P&BRnL3|Ka2wAzx0KmM?iPhFAXrR=MSCCwXz*>ny^xgY(>{ZR6-%`%as$rr-9y zt`%#q!+nyZXSuBZ>go5U?s$BAhO`XUmqG})3|2!xR-TP*%@=!&d{39Jie>Msklm|{ zI?R}Z9OeyV-s|jY!XHx(I*nCn`T9XG>Ud>cAaTvh>647c37!4OoJrELWm+&ZZJt|I zb)f1kob$pTaMEFE`--k7ME->d%T#q!^~@W@<2&?@PmqSUUOOwa%`Qc2Nzt|gGPZL{ zC!b_zht&=evHNC^INFr8+j%j~v$_`vY$|E9b&kt+>?&mMP?9E5S5+yQ4D;7Hof}Wh zh?F)W`HfUol_9yH)wpFU^3XwWX_|+iq&Li$TTU*4Ty7G)cGfI;@>M7_PnNlgk(@Yi{DdT- zyfRd_%$)|wmCi1kS&%(7O2HHf?=@4AOod8i%3vo-o-}!io_H6?$rW zB0**m2qPw7Yxj5uxVOVn&6nW`$4lFW0&GBtv@shb+==1~=-uh%pmtmykgVqFCN12S&8TGnRFtXDnu%|%Bu38o5&>ToYV200$rp zf>Rq9eI?V)5zp-arhMuR9EErsfLm%9Ma`m|l4Sq?EkUyZgIzsyYGx!@e{ae)v5nH& z4Xsw}PW|^s0r}8dpolmI6o?W^a0~=^P{xkX*eAI^&(H18eeW%j zF-F)!qP7v~tobE+un{Awj091{8HIlAexm;~8>-FN@yAp8?{nU>`WSA>ugdl1;0+X8Qiw}9xXA}b>+ET9B- zWORkEtZ=edOG`SVa52M^o&PgnksvddnE{&Z-M!tJQP^GSf>xI#eUS9|!iT)44?5kw zQ;>~fVj)TToS|ccZ)OxSb#Vi308L>^=(qtxW(Lgum#NzRcL*fGIYYY&sdH-TJ-~sG zJ-u2t9ryug&vzhAA4H9YK?!sSnTr+2xLpSXM^ElZsOdauCvOnhQ&BpXsL^!)e`??M>T>rb-6%fXM`16Auw#Av_ zwF>i7sHi}dm8hx;ty+avuSNR~V!DrjFaR!qzyUyLJ^-*C&LSkbKMf3nvER=x&V{i* z7pLXG*guj=^IWctVAd|(1?HGyILN>++WuF~ORRh2TRI$YmtbOOcss+RPO(R8e_#of|t#wT-R4gR_gPn}>Yr^cge#`~#JtDs_Y=Iwme*bIsO2 zbr&vPx_ss8wTA0AZr*?JP>LUUtVxSjZQAwd)u-QpK_7gCcw_`YPGl-e(-~=E1TlyV z2ZHAl;r-n#0waq$4a z%?)Xxl{VU+j?|^x^Tm&VM4b@f^8Cmg5rbpx9ySv#w9-bq?X6HB z{R}YZkny|Y%yNe&AH?J-94~B|mCurb1mmCgspKuBqHvIp9bT}zi67<}4*k|!0 zMP`rBOOr*JZG8S-Rk?0e8f?pRCSAi;s@d>Y{PAFUAqYUbzxgnpiAAl@1nOmd7FFL` z>Rqv=zL$C1+un}w%rzz_)!2{x#MEkd#G zck#MX4~(iwAl_eZZ^mP5F1x`#w3j|%#_H({-X#8peiTFMn~nojU7x28&3md&QxgCI zLE5^d?XaU(dbx+-`4a1UE^jv#AT&Op%#U~>Y-*@{(3HQ&tUbRq{NQOl`j^yOwZ&m_ zY4S%|<`;ySO>j+=jTEQ|m$vK+y}H@jN=7fIFqts1eR!oJ?d<0}V()|X{>w+)y62D(xf89p& z)1Ef;!VP(BVwUE)(;B<_EEtf2R}={p6MhSBVM9n|gpLpNPY4a07@?D+ z{bsT8=32ki=349R&zI@i?Ry5pzXCcKgSomDV=cAX z$XSt#iaeAzMcHy4J5^1lsbIQtXQ-Z+(!G`8Q!xyymI;xl2sIQBt1v>WHGmaBg>lM? zSH9LUzB-JJx4@12Dls;$g^t^<<8*#>;VO3R-Siu7((XS-PoA-xgrEET4INFh-%yKo zOg$$PdJV$a%d$jY^kWfys1c!xSU5Ujj2#psQ)AAGaaD|ah0jjA}Df| z_(1~5A(jLeBF2S7kx1o=s?Zpl7gLyy_Z>@&Swo6hdor@oCPo~JzKBF$M6pOcoDqcX zF!lr!mT+KfYKM3eJiz!N@6jUWcRd4JqbF;d>XPuD!dT4*(OzQk?^1=0O}(mFUDJY; zff_t3LRHG3rZ822^S6>2O`vJh<6uvw|Bzph2bTXS&qW}~&B{muHzm_f_nj-t<99KH zkQ@TQVfLp1g21G_21}tL;Y;y3iB)L3%LXu=qHtK-(+<{43 z*J8_&(Iz@=waozC;t=7Mbl_Wvz1bB&4>>(#`M#KG*p4{tkfV+{?u3(0wGU^E{oQ9Q zP@)v+tUBkM_ZJKzG64V{uRWj90PSS80BS0B<1f;`F&$cTmjf&HvwgGAcS;{nfXQ!9 zz-W+uZ!bU$T>=22W66Vx;X`vbKCE)#u|F71AR>VPJctoY0Prla*Z*I8%^gn-_>2Oz zA9dZSmTG%fWcp^(Oqn@zWNyTz;*&Xh`iB)__C4*i26r_Y^hFrecmvZl!)XuSe!|!E zG0G5j7zEUJ&(8Nb1#}sUih=Ctuo}Tci#Iz>mx1zKwrI2YXyP_5B#tg zz!K3%d)NHUK2DNiPEpTku2Db(x4B^MP{CcEa?LcN;~B5G$7|lOjAq(-LI<5Jr;C1` zn*pjAae>UtgFL*bFjV+ z`_I9Ky!aiD1)>~m%!^IJu{)a?&qTH|naOO!5=*u-1vxwL#FJf=Qp)b?NvwiB?^|V@ z+D|9!Webls+HIo`#p)~;AwjUj$iQ*807RpSB5Vf;s6*b9C&W#GGjb3SYe7IGK}0tJ zLwW-N76U>C0ko?F0stgQ0Lco`oJD9|lnzl`yi7RD!V}`9B$9~DZI&mA5~U<2A(5@= zDsYMTj>IjzRT{G>u~w}0OVx_K#hFQ|Bwd`DQ31OqAq#|nEyl+}m zlw1np5_Uq-y=w;Q}mL!g_rS{ zhcv3?0~^F-B1U^T?vuq+O0pyYYK@oYp{RKoV@pVhmqZ*aJv^@DtQD#jYt@yk*Sc5Cr-;KKArK&tNn zY@Y(C?S15wc$ESSV*vb(Qdpr9E+=Xn99v#~10F1xR4gzuOHW9t0Nhqf1}Dy{!KiGN zgT;2E?a~=9s*wu2q?1;p7IKTvZtXV31Of&UWYZL*Ti8%e7Iv%)gYEZ&Lh+%q zdn3xSoJQ?M%42WIQJ$-Q$)`=}tFB|4KoO~x|0vKHwAlpK+bN(J%3xFEOcMoj;iY!w zjn$+T(d5Tqj9uf^eLuN2vl(sD#E*V(`MESY{MhN-RoC@9GYngoZb!xpQ9g9!a27Y3 zto78*x~1=e%JRMw$9$(vrf)3ydJ~cLji;keT`&dOSl4J{tjU$4gWI|7qI=P8=l1B+ zQ246Sx(Z^HqAz0R+stgH{~JAu;~%yECzz?E@JdB4rE!QJtw-85RM9bl%4#U2Qh{fP zt29O~tg%g5cmO2kDzGptMdWIMX17`(GzOF_RnCP=T}4d8(%Ov%&@8Yotsi!n08MPo zvKi;1L1WMX2sOP;d!ZQ^Y3t|hdc`}>xEqk=7(D-9AMy6z2T_sF0#k=j&!W*yI*s#i ztnDJZaFFbC!91QA-U!x56mFWep&o^nm5>g)5|m3ry9j9&T}#{tfAhNF^==C{$i%aN zWg5Xj=1?5kEBdvg4iNa*TZ2n<&k{@*{u)$#wxqYaF4!V8I zlqm0+C>n@<_y|Xlhq@X|bLnZ|r!24*-GcUC-_eDGlUgoCi(D%|Fiw#BFkm+uvdWWj zfNs9kgT{3QPC{wLgCl19H3T}Sqi1UXY0l{dkpT-{fLZ0G|M%2InIuG5<=Cv1WFb@0#f5B&i4382>%S zAEh5krc~ZktHi3>457L2C{EgGW4>y=$8vjWp}0i!V6Yi4hY&4eCqm@G8db~aq8lZctz=Z5Xg42Dd&K{uczn^L&56-P!U0Dercc$sL#TWs37VDl_tZvj z+?t3s(^^|B)8$0(33>C84D8Okve0gscy9|unXN9n*pqM%w3FG7_E>hriG)RMUd19Kipaa}7Ny1{qF7cSvvgSIvP@Fate@9eg zmq3qFY{y8!7!7u>)C;u;xRWwPe_j_hwPZc3D`<>52&6mPL;YJ*7J>w}355dcirjC5 zDjhVr8ZX+TNejKfJysi;6!vJx{<1F61TW#&*7n}$BR-KF+zxH+NyTEOTagVip#`E> z&?CrtJ1iXpdXXN7%%eFKz|OWnhr~AAnxSbKO~w@63DDol1iW{6Tek!Y2!@m$B-rfp zqjN}LEB~dc2X%8;dkEz6&SvnamG|Qgb#Wp=glIJBtIH0p81Yz*N=9MPBx1+(>HB8o zL69juIx2|!Fc4SnOrdC?Dq-P)5p7?X7h;av(*mQ8a8rUvz}ZAvQ5GiP=Kjfw1(gJ= z(TGx6FHcF5A<3y}3GO`Op8QK2Yn;;5r1`Vk^io7FW z8X5`IthaYw`JxRqtkxPRA1iotaF9UzYS^K62R-5(0Nfj(g=)Kiq`NWS;hRdmSb#^< zm^Tk%EKg8*Hy=17?+~1G3!PZlof2BYV3 z{pgSA_F)hmHJk~~zvy5`A;cPHT;@1bP#j#L`8_yGRRM;_d^cdG|6 zdKxx~Ic@cCZ~(0iifhrjW@dnDhG`s>jK{~cXF#?OFO6gY9k7y_+En2^U7Sa0=}6LvbposM?6Ew*qx3M?CzNEB%fk0S>Jei=Lc634`p)d03i z_{0~kQmU666!R$~9Holm0Z?VWNztK=q)vU(*pcmfut$4}B*cc5!$#xlrQ0_ec5RA^ z?a^!@4G=i6)f1yV#cL!`AV@o*ErJKfVuv`5XR(|BaM=)7ol=n^`Ve#aA_%CNZB2slhO$5 z;XiZB`{C8yUKUe_LkSztN<nj>{piM0}@mUhN4j5QvQvam5SHn+k35k;Xd)2LDC zRNDlvz?xe(h!lhXRX;yQmQ8ghIXmb3;@#0l@P>@+CE3OGE5DTpYazHjUXfQO(RC>1+N;RY4=65NEj5MG)FG_| z;r4ZF1(9kzF8m`Vq8Myt@+7?Yn~Dch;|XpwJ<>dUC~qP)@tqn!#^{4V3{QFZ#>%QyfsoM40_T#%Y__ZEyK9uQo;^NDbQBR_px0+c`Sb{C(Qgob!zSBh> z;C1C8a2m2QmlbVfWJhF$2LDX4=1_es&J>Qv(y->I2cr5 z&6gJA5f+;sE#fklpOs}Ve_p;E81X(i&m*eB>WBwACm4t;3h)h}hPX$EIEzBU?k;p*6d_>#*WD9>d{o^ZOn|-;#-`^g?=F zQ1!a-Pc>}&)9_aVs=rKUqi~{`6a}I4dcwQuq-K#ctJnJ0K8n6^al!0F7)KyjWjuFoT`1&{wY= z-JQCwR5`x<4`_(6J^Sy7uQ4^rZs6WjCqN^cXWFvt2u3Y_IKMxDN0!XoY{nt30lmTA zhy7aaDpux0#Ac~D1FEuU!UvV--!Di>*9kvkA40aqh_gck`=gf!&N~p;zz9E?f9ebO zCqCKbw?)}+@W|g2u5yLHe=ib0U-kXkcsxR*(gMAiJchb9t)gjc&!aez+)(?+NriKI z_|j#Yj7h;%)~|dvM@NN9rX(c@2~8q@mr1PBx_i6QvfB~%Goq^p5ki1J=W}-L`uSa9 z-6kvhE0FM_Wi=Zi-_Y88pdr@;XjHA_n#nhK%GU{C!19R1x4%I(6`cTjNBr0=Syj{a zZy1xIa`X>)L$D!2^yJcuu zvx$EemGcWY9EvwyVtuUd|MeS>D%J2S!r9l>`@a2mX7~2Y$lRvvf(%v2m{E@5VbvRl zPK*k_h%1E$^{j6B?vud$Iw&dJ(I=jhYda^}#x{TP&AsJ3QOo4>*|#-hRqGcA+pY8t z>K{Bi^jNp3Y7_LwviZod`1~V(O^#*fD{90}?tWlcp>_baH8bfZ>g4FcA%GrP*_#hA zn(|daX2Oq_Qdhnh0C(0E0*t1@-fDmzS$$5KSk*i;XS-T|VRhC@pWQF$7pR=bS)Ag@ z3{}Pda=dOZYszQ45*q>CX91dc-IHwNXAKiM(hH~Tqx+usi8Z{=I&UW@)`Vf1{hX=f z^RL^XNY)9+Q}VyNY)1S1686v@0dx>u^^I&9du}1KLnkBegq4~k_Q6uhsFAgxdT+f( zXNI4+#fEq)y=l^m{&JTEuK0^#-8cB{8SU>4@z^j1DJ-TAIAtYdHCR}x{v4DIH~29w zil7aTI0XUm9er;#cD`1!I_Uya&Kx3E5Ej$z?V#}L*r}a~x1;_(Uz_~+qoSDm@a`4G zMT}}+UR)H6{D86>S>_p$433(Ymktk&;@#&}wpDtxjSruPq2(ld8QM*)tT#bAADcltg`Km9D{bcbc5q92(?WHULv zyhFnya}qn8B$9?j-63R>OBOm-QUq-fA!9^P5i;>W`77T5JzX@0gTj~`u7DO+RWy|$ z7X~!y;bQUS2e$UZKb+4Aayxa~VR)B|R;rmpJzFA*YP^pkm&e;FTN_ypL zYttyGVf_0*hNG*mjjzK2G_dh~g1Fk3Wf%q)$(aY&p;A$djA3iZxM@+ZkAu5cHku#K4%Fat0JX8oRQpPh7^~z-xKN%A>?~jy?n zrNb4_-yTSfYxQrpg*52ItAXBudqNI$yXnQ_o_aE{@;GH5?trc8-v2^ZL-*OLVh`-K z`Re@eF+R5MNiuj_`_tw7Boac&@)YUth_)0gW)L1A)tQ_0Tvt0*%wtMdJ`~G|t4b(UIXJd2L;M<;cuN<+l^>{ysT< z?2*dK^rViH&nLQeDR=%SzGGb~flhPY-0u!PB&)&ox2@D2z6r4txIbpf+V^6RvsCA; z@gnI@5B`0#_0|8nFA2WBE{@)@zA~TO$9<6t{-vzxsa?_R_>^>Bf=AKlL~ccTR!Vwm zMj>@zXge(8@05%fW@M6!HIZQ#=Q9}M zn6DXVbpWsIe=dsPZkuzp1@e@7l}_N3d6Fx3nh0bV66uLVh9Qs>>aYHtK5h1bnBQ~@ z*0bCe+SIpPTHa70C?-2wJCMBjVe~K`uCt?~m3t+pN}wWFS6&7#FFH;vJPxjc$=Bu` zCxEM`x*c(2Z0uOKV@|gtdSd9h@Ay5(EY|@r(wq<#78l_cRLyMk){3FQF`DWPvc661 zgv5djj-i{Pm22#Io6|Lk6g*%%Rl_06@MPG8#KL-{vfTrMw@d&}_h2k!&54j_tyoac zi>5P-VJccdGls3c^PeJ2-F=&Ge!}0dx_M8VCuW_&N2MVgcLPrRg=0eYC6^RgU+0)$~6_Ii2x0!wno@UPZG>R}f zonOZa?LKP?F*F&w=*0zM%N2A0!vj}`PaiRbMuAcsVktFHro2f0R4Uw=k{xcYGqeME zEp8kct4*2TuU@i72TTDPc`0=ginZY3ET9G!SQs3SJ!~XaDNxGttEU%9B_L2&FJ3{N zx+Za4s|_mbf=;Mq1%)X& z6yS{jgTeG1P$VP+W9jYZNT#^BksKZTJi_1OeLsKWN%uWnW#MgSk_CDf^}ts*Jrs^( zlmssz&VwET#PMyu-nBUe(H1@%tpew%j;bh3<`Fb}!j<@u=Kcn719-Lox^@^0fI(q; z)~CFy7qYD)9_J*e&Db8gk%3$hAQhTgM$p(P&*>u+sfA` zU3Dq+ShlK#wx4hGyVdsyU3lcv54r7$yZY}%JC{Y^kvlB|!_gVBPm<%qL5>kSgw^$r zPcE%?*BUFinT8yMox2RPY0kDvz}G+M9J8uB>!3a~y+l>V&CwRAVdm7xx8hqlL{C@{ zoXJ+5;$Pz|$p`+dz6mp5vEd2F?-ZAA*T3mUJG*#0I8z-EpX9TC>qejEbK-d8pcmWN z`^394NqHr_M2h|(rqWDz!9<7M3FSkl7H?&M7%nI{$x^fBl?N+vKWpSzXh8S^G37rbtg*3@=gM0cDB|!%%%JR<&X6o#yr^ z_9szknO^h5wJ_|AU3WZ+&icwZH@juWwb;b%B6&mqeq1tDIr^k?4mY(T6Z(CTRQYc` zvLPh>Xq~+x8^18&=nD&}9pZ3YS6Fpg-f<$iXaaQsNI9$!UM-WAy%$sqZOD+@EvShM z7%4jVJ3V1Ha1W!d;^DJbuSnMUR?{4C$!)NCA=l~bcfPFa2UiHQ>9`&MtbW8kB-HIr z$|#{brd>d3SeBrSXJE{4$&K8`uf048_KA6%+ZE2>b`DhWdYN>7mod28mXV;qY*!2p z2`_~}-tD<5D9R}sl;ta|H#_Kk@p?=|T@-`t7R9JzMS$nk;IOM|FcbBw#t3&~#AR*z zn;=#u`5fEVpkC=L=4y^~5KG{yf720i)`n7+C?D8EmYm(8;oUPpDHexUi;g_ z>(MEhcyU)I)6<8+bU)(~7Utu@q=HC?4UT+WSACqTaGYBW-rrjLNWK?-T@S7e$g#ZM zyA<4R@As5!yj`CktnWp7A>Am3OONrraad zlkJ&iypu;5A;|ZJj?W(sU}d!rIwx3VowQU`ok&!p278d*Ojp`gcs?Sis7y;>;w6h4 z>2wY%ndsn8(GBQ$HFRqMQVpQ>i@ZG0;WUC5o|)jQ-FWh%DjIK21QqFyvNn5Fz-t#y zxn4Cb0PGdBci+ls)*6+S)MjLr)|Td%lr&~$lr@xg@2RCz#Y#JC8NuQOm_3V7{U3*A zF8Z!{uI2a2y=9mI-+O6m-8(P+-B?{{a|FOLqJl*>S9CB|BfL-g#I{TREKOS4;VK9c9c21CG@w zm=^gWwgnsCj#S;DRw_L;u48QsI*xKc9^Ur;0|fpJ>yY@XNdHOUgkCmp+I$>c*3`VV zspdFqeqjSx5uV2|wpRgsw#NW=$`OvtF>~CUFelBa)akC00{wuTg;z&CkJ)jHdzPIW zJ=eK8d4t>IK04c{X1o44oNUj^13UlR&;Md`)YH&RN6)gevgbNDsBWP^t4MpAQh7b; zpxrZ#a&Mtf?vay^@+oo-O`yhE{x{CjVw|Nd?Ocl_qbUR;XQqhIOu6@L+(Lmz%clog zMAa)U-i2Y+K}Y6~(Sfv}tRq7SYNpHs$_#fx54hBWj~E$0y#-+Wmcdk!_MTaB4JB7r zcbHcGsHdBjm|bT^#YH$vR8@YZ!Xvdi=`d=sO{-nRscb%triB8rQIxgZF;QZfj=D#w zYA6e$I0HE(aWRG558+jhdo~dCK+1c7vVSIedj`O={5-pcK=$ZR!t9TvZEn|!qre{p zXlq+9B*k^Vr)6Z%>?OM^aB5q_GEuyZ&sFY->+?01VgS3n0JQnJ)(60~c2wUA1=QNA z+s-qtt!|{GO~661uI=WQ0;QP5y=#4y%TLOuSXfv+CIqz3+bwdsJ0(u+ldF;boW$Sn zEj57XyQfFa8B4RM34pF7I-p^zD9*HN>7J2(bK~9>e`vI-TOvJM-^AMuPIsrI3WLSk zUBOUr>XMR+0fd>FMtD;?{L*4b1!LsUEn}M$;Him)vrVlng1_$Hk78> zAv^(eVwZNa&rB8I|0v02ApCgt@(e=}P?&`9Q-EUUPD( zM0R29vCk>8{RJOhG;ap~hE2qE%Eo4nu^6+?wNHZ@QRqd2c06|YIrJsY&>^nIGw_fT zdh}N~Hr%7HjUr%O5~aJrpdGomE~q+omU618=tn};g_=GPy2`(`(Tz=BeOgPiLyus} z2K(|J+h8kK&GzOM2{+Az4CS7@TFUcT(_Xpyv<*j!U&r~wf>7$VFcdD%KUAe>1dnA< z&)f`-IPx>uuT>%mU-vAMbmz%2%%+QFX{OX`@#YxZ)i)wCE5c>7iK2IZOv&p!HyJ}0VN?#<(SoR(RvYMkZ0fK-$kgo@&lPj({R8M zV<2Y4-vshA7Tro>Fl^ZZ1N;_Ck_=xhOo8wS?Oy=@b&v?sS8ywuKRv*d217=2r=unI z>hwfnx=js1zGJ~rb-#>|56Z$#N!AU2!i1Aym;Bk7g|F7HBao;O5>qbLSU)>*;+e;7 zswF6)E6GYCrf`Od!1NglXZQF3ro+*GKLRT=WXQNbDoSOtStZifND=xtYg4O@wCuNZ zXiSBukIe{b+YN9-djt_yf(?rBI3o2HzJ9BNOz0_r9AX@+pbA^&anB5)$9TSnmEJnZmt7VE)ChB=unfwC3=y+Q&y$r1Ic z;%SF9B>a%i{@u{CYwlIyUU1J1ln5HSPx0Afd290^f|`0hUD<%o}J%JZgroDUnvh?;h7(@H!+lKCep%BCLNBMV-E0`g_9&t?U+f|+V0 zz~Ic_scn9WDUEgrGM$TVtf||Z72C9pD6HS=7F1U?6A)dw5eP-c3faj)MU`$q?``b1 z+5ry413X=kh=azfR>a~~unjcR4%3!&-eyeX#UY%bPl|4!?p;xuKt(=zTxg7Cv107A zQ|Kbw(u%5@&qMh0@F8~27^3A&2xWeUL6Y)h+hyUP0?=6Pe zN_LXD3n-i<*RT)WGP0r)exwxWdh4uUi=s*G#^xbJyM16c8SS_jfW`y@;z|s%>@)?X zVY-EB030qtJg^?R#pCN)-`~*s8b!2Co1iE|GZ!bS=#z^=TZk|bdYVG5s@+}ZvUJqq3}l~8K4eS@Ml&&A&1IOQ zJC9-<PF`kYhlMp(gZW9Gu4gtRaUA+v94W5_*QVSs#|>q zfl~LY$C(ZjYe8ucc-~7frssA$agRkL@lk~)G^1^w5*iqfZV z(FL7MTc46z927&koNKrKNGHVYRPRM`rn042Aj#WUjcJm!GT2p1Oo8$!)dSAsmKE5k zGFi*mXE;sGBb(eE$ViD*TDP<`M2V{BEQMX)na5KGo|~;68x-y$*;nYf(8|3pG8D?h zSb1qr2)W`qEz(0H=M&y7VKTL@9~Bg0FWCl)ji)eS)BR?~H*LKLkWj|$nt5y#cG$dJ z%hd6Jd+>8-sa+-_Gg_-OAAKVgdYeg|&8*De89NRk_Ps&r0|IA4Z z=QS0#ILo{H(_Qtt>_4s0Ry~Wu<9vH&^%@L;Ey8`3x~VWLS!u-d{h)`boJoh$J=|Nk zM=!sjcoOo@t2e*T#Ri;Oe4%;TenaLslmacXlJ6rCqi6*ed!!rHDRMq^>=?z@&Adp; zN^4X}#WIOk#X8Ci?iRC^qicOccD5qPIuo(V{s;IsIm?9sHx84P%inG(>&;Z9IlQx(qc$5Lz zBBd|40S>Aa2kzBv_JEQ4N>(Vf z0T=s{+rZ^X{TkcC_AKK}CdJZ-U4BP-Y~vl=WBKS7W7=%Y9N`}F@WoV0*2M>2uqc7* z9iU_P6nV5AD>O+*Y}Se``y^|4wO&z-`W&GQ&Qd*d%8=^)GOxX-g*Dx4(UaTbenZGG z9AU=jaUY=rImZd>!&OxZ04IRuePk7sth@Q+crLNClg&fyvwvEXKW|P>0Rf2I*Ssv6 zThIAcR^ucbR|g#aJAA4v7MN~&~$)x=ef0z?Qa z_HSkCRDKn^vNd+h<=f~*mm=Gg+(g%1a^bXvhI24BWlTuhn$fvbXf?_3dcH7t_p!c? z*F@(+kJ}CVX6Z^Lhld_em+f>Sp8Y(4eLnNeP5$kRZgsfJEEO?tzZ`_zpXcxafJw-+ zgB6Iz3pta4;H|a8n+RXj-&}p(Q3N(`UVCrmEp+m#jif{v(&4%iTXAdSJ&0RkC!eg( zaMqFJzSE$v_2bPJXofV7d8zH>V0%+y#nNKBZZSK zpnwQeV2sR@hDbLSi5pR(`fq4flD8;v5qRLM*2p@O-r_-o{rs9hVt^8MJ~T^ONk%TM zWi?gTXxz;iEONirvwIP6=nj*$Nx<0HrKI_~MgL0=VI1M(`PkwMI2tXck~Rq~gxJp- z>zV=u8LV`#?3r-%?p}2@P_}dA^C)Yqsf>nwicL3;&Sk@OF>`jY4df`!Oh|G;vOX&= zgZ{cvJ*`cODqJ;l{F>OA7r2&QyDCUcI1-i7}n8B+v zEjExKBG-s`s%;N;noSomHb$)0XpNU52~+}t|JuHRHBQmPx9|#YU_VI<1wrI6bEj*ZAev5)%82{hl!GWv13?A3cTp(R-G9ac}`SM$7)Q zm*JAl`04*(N`8J%VfJ(3fuj2;pup@9m`6By)XSqL`guD0BbyIEXyv**P5ooVj7h(o zi*xQ%f7Zmzw{`M5F)nX&3?A?~0R&bd^#LAz9Xl#4`(99QGsEO`dt=TDd3FcX+1Hsr z^)y4&i|N$yi%wn6p8D;lb~8>2$rIpfGpS6kT{VwWaJ}Ah^SaKBZ@)9+mwusJh3}@H zo=(S(MxmCj_snlUqVfd7c5|=*_TDJFG>Kg zU;qFRV9Y!L0BgEXl$(_Sq9*#dYorRG++%L6+4{1LZ8IoB-;2MLMgf zrpWx_z~Vww`(3fPII!mWYSEOKKkF!M&}zLJaVDk$>KJCc*xdffXumNXI!x+*Trst( z&hRJ z{t{}~H2-t%UON=dC7XJiSN&mKf#ub(@~$?wd&F&{sLM{s6)B_p{Bf_y@OTQ^<+A31 znt7%A8ss}iWXwjhr+C4Q)<}&GR7Re#da^L{$j$N@52VplH;PEb! zH-m&hlF`-Vo0O8RL0Y1$6a_Fc5fduTw6|YULjvSv0RSYET)7?OV?k4mO3opR8vj7!3jdzy}zt4IKi&ln#gDEC7fHr}L4q;?KwM%}d3bQVE<- zW2uVL;XHY!d|~dGtw5pqicN2p44F!a!3i9|@$C|Wj{<_~Txl2glP`sg&I)j@Pi4VN zG@3TY(-fPdgQ;Xeut4$+mxja;)G$9wnLIO^u?BM`wc-d@u@YH4-#L~ob_REt>dSC< zqUoiemM&FD4)$;R+_(&q6q=<|WJ)8Wixp*lS@9zngH++lW*DCYZ6AMudQ^wX_xJr=BRGAomDaNnu2 zrtlHfacB86Nch7;ee24XsHBeEppcr1bO#^| zf=L@_d=+e)hO^s20I9$1Vm6|JjRO)4`_iH)+oY$-{{NOhWyrc+(+=P&Itq;~moSmb za;PcG#b{HklW6bNgyv3$DXT=*jnciMxUi7driA)p(OvuU@bLMU?p_zpvvfc4ZF}nQ z5FR2pG=>k&Im?~B3$Nk{W8DbtKiv#+GjE^n2#tM`%fnM$kAE(zdSXuiuHr9x1<-rr z^$^YNeq&?w*pSG9f=Q%+&?BWswnUDuu>m70Wzw5Ll%isRqR?VsVKq?XH1(wv*`Lx2 z3JpyVe+uq)G`7-aNh4VFdMuMH6CL+GVRm``5k?{}pvb$}5}K(d39T?VjApX$;Rl-gZG!mrQa(rhG+ zTG?9cz4Q87bG|gh0^kGsfCa!HcmM{#0QmmD_xeVXKf5Cp5K4BaVw>Qr<= zP$nterAtxmzFm2>{|o36@15buuqTti1UeaHg@7v*gk*=#7a~LDq-cn`aOpA#O`Eo5 zEXpcXP=(__fpG+fHv|+!fI$Dt)GYn4u>hCgLfmfoAaW+i8W5WGtQF$4(SgXk9w1n=t= z9R>t30dzuh-REw^Fn|K&Ig>_PV(l|{x!B6TDkQ4E`r}ln*HBH>S}li8!g5nTNzObt zWl|@-GrG1iHw&6SJCDLoOlB&nQfkq%K!b1fSE>x>wHm6Qs^#*v-P&q?K~zENtAYs< z8+KTdPCDhZGh|Hxaug|1rb3mv3p8obX2O&iOV(@<*mLB}g&PlL%2lc|fsWy-Yp%Ot z(v(L}o_+fA?Z+<@CxnD0B&DQfWR)tQC#tP+P{-o}3{AWqY7>GD2NNAH40CG zaXbv#;_WS;0zU*n0wurNOOw4Z)oZiL@w~UL;#Cc`HhT6La22k>b+}=B)D{Q`Fc6?N z)>|9|gdhw_NI@DhkhSG{BM${A+Dg4vj#{}iy+F#{9Y>rpYJ#BJs)64Ywy_hsY#6A3YN$n*;2pe!cM?Dcqj3W> zIF?|QpHMo7in(C({I2f3e(2450d$YRYoV; zjI}+yS~$ChnQkhZYHKDEVigMhZQ5~D?s~+kJQ|284zP7YOaS7RfiQl{ zYK#qzp0{tua%(zz8;yL?>Z1Nl2ku(em&N=Bj=n~O#>*X+R;!mi2T1396*%hA@Bj4S z{RlkX9ugK zWOFO9Viw)GSG4H1yWcv6HNV$H%SCmSzY^tdVax3v z8_pg|@B8PvGv2){Vxm#g`wscdZx_)AJ<6ei@^T?Zv3=tJI?|_?RsXN`JyKnCvi1dl zPeyb_$Au-eH1ChNq2fQS;wZA|$U0&3mRB}gLuy$8k*1L{)jpS%(f6&k&9;EE@+c?k z+=JHj?9;71-q&w@1sC&S`;EqZ^G*IT6$6geEq8Uqq#DbiOm+ZFHW2il!eC0nNjimvqAp;R z%@RJsM}$B~A_^l#1)QYZPEp8diXcN-$x=3Ql$RofC{Z4&l!F>&rA`H1p!_r_nkHqZ zMY$MIBty!~h#hmQ8VZ<98%zkGaJG!u#cEh!kw7urC<}MWiOiX&cm|&eaG|N5!KWHj zNG%mI;RvC-0cNsi+@{PzxaBU$vIkf_RF3Q(S%dV{@t9{eq3k6xdF~ZBdgUyHn{XRE zxWRZatj5EU%z!yd6h?;fQKT@+6y`kRM64PsVIju|mT(a^f<~-N6OfC>|?y~y|?3JGpOCeq!=F4tvfCE9M`Zl(4fT4}<5DjxnGisr0Pi-vC z4O<(WUhF7Rq>s!5k=ZO9U>A;1z+fz=KqVp?QybquCX@)Qv`hdB zOnxc>0`Ao(NHI|3wc@0}RfJmC1OUZ#-Z(6ew@oN7+*}J7^ZZQ}kA<|sK`d>u6uRi?-^0fp6*Yu!7QKHdY zF=W_?Q7{l5B7o{AMKJ_0UN#hgIO?slzRUmT<*;SLV}KL&y~0Yk#tkfufDUlXzDV#N zxcgF@00(+CKwmOwaAq_dSn$K$Qr`sDUdKH##dQG}!C}G=*h8vj`&aLz1^2vk=m>9u zkPG=NH?}>TAWjq~fs?|iT)(2naCC$e;CPGUGf#P^%c{X@vwnf&#|dv*t#tIg zlsgS&3~i+Prpf($iLWc-uLs%RuKqD^fLe@a9?;xoxPqp!-ShN z*LA-m%d&qugK1BWM<4_vr~`R3+BB!=(@MXbS9#8g^ zQo}Vvip&A_-|@tgb#Nt)tuMjTh0ueBXYxB1ow(-|&iPYFfcH3e9ojBdx4aV2vu-sJ zN2jtyuIvK8!|kPMac+w<2*lIE^K@FCdrzD>TAEhpwuZElyxPX`xD$@NC11;zyfwrH zc=^&=@=dPZDL?Y9WN|cvTL$82Y;P$}yVOZ2jrVhMQkSN+3eo}ctOYu6FxH!&$_L&`hiU$+OY&j+LrVYG}uN5TlYBko=cZA;(+rlubd3z_mx%|`X-{l)~5dA zA0qLKrg5kCcpY%S2>{fufP5fu?pq*$=W5SG5a6Ip*c-qYT)#xx7J>(!Ne5QgmW2SO zy=WgPvI{Mj4YGp5)_^JPeG_b5x^n#R7Xr_K96tvfVAtm6xqCt(S>@qek85O7)K*wsx><6 zu-UP&CQ2VVlbCC@4*KrSsyU!BwbIFA>kdw7V_SW-_Jfpog*7&3ylG@GyT!3|vb3gf zDP+OcAWk5g(Lx z?r>8=m@|cj8ZGQHWS4XfDNXb;ZTz^oq$pO*f)r9t|KaZ>;>fr;ZK&9x2qaJx;_YG|>+Dp1ivyU0y_PDTv>%STSskt(Agay9CHD?r0MRpTjLh+tz5(X+zv5vxl zU4Ed`aiHFq71-32QmlD)-1Sf@KO;anR5>$b5O=bJ_4L^X$^sIY&ShMYl2rdM=u;M4 z0!55RmrhFZI3lYYM5Q-ZfbCS5kQbz%5rb76@124O1yWYhJ;QknA;8IE;WutqFUVwB z<(5WxMRQ82s$Cjl;$XA8o+Fp%C}X9ueU-C+vgYUA-zvA*Vf#q@$65R!$kA=Sy8X+Y zyKbJLa7eG%Cs=GRw$Zd?`_7%lzKu=+OY#`)W{Q}oD42F>jwz)8G1G(v?`HhKg_!=W zq9x7*V#2l5OAai{3e*eE-9w4|5wxX2<4)F=5IAgPOQZGWqJ_N>mBr$?1OOAbw}vBcDjCpq)+pm#WJi86%oCf!bL z48$>VQP9%-xl%pV&t+_T!uXbGPXpB!&?`60uVi_)`x=ZV;JU|v=#3SUShyyYJf)7M z8C~Vd?owDiBOFk~6W0ibC(MMj+RQB;Z*I|ale{VWt3pAE$`KD%U==AdD+q-Qme^j{ zq}ZW_Eb$HUc#A?hCDE8yKGESiD#@JkB#yd;Sb=a1(yk9l%$V|U$Ksq78l}X@*_q4C zaE^)hDp;}I=fpD$kMn@VT_JpgoRk`XrD51h(cVfwPJ{YJA zq9c|ga@mYhAkZu9`?pK!jz$6mEY9Mjz(6GhVJ}o`LYa_@f>mpoOEHqPDlgH1P+VT| zMhHV*n@Ux!M#V%5?$l@eUpA3r;OXSTpjU?TQ-X;d1ieOr_xCZg|4q0;Nrn*Q8(I`f;eITaZ4GP(v(hORGI6WFfYy#)fvVlQ z#DY?+59o{SG}oFJ$pn%*I#UXj``jQtNQ?$?Y(v`oI!+p1v)kZ%gVAJV3uk+@q1dHK z1LRW;NlG(BNTx5`ECmv$Olbn!(RSDw9fa*$WSN#K@~4eQWrYJi#q=W_L;3kGqHfrZ zaE=@Ho~*5kq0*=}c281iEd(!-@gpumkGuy&lHNUhOIOc8(X@N@Z zDd|1W%NII?q^m@Vo#em<@uVWG%o~8@^_g!8Zu>@;>IWPc{O5h@uY6$V<#LYOQsu0> zrenqXrK|2p)XkrZYAxC3mavr#$+87qhq{=ESQ*;qfqKaaGOae1lmA3Jt1`sh?kP>n zsh!^(Kw1&Dx$#I=V%|MQ<+vm1Yks*t)qNKEoLS1B1QADuqsZy^w_n=b7A=OV0bY-q%jy6_J>KMy?qxL2na3h@sNx6 zwA(gV>R4qIt#Ra;fA3~EIiA=^;XP1sv-_LmS?Kt28EiLry-)XYz6LLxkyffhY-AuY zCmLKfkB9ArW4Jhw&ZfB|KGhG zH{P{w6wkFjc~G$H8|!`P!ILLnZAB-ikE|%cjiWRDYJm3z9C^u<0)J~zmNnEvuETs5 zycdijV%0?xj?6sRODt=qy!?%tFttKF5emvbB)%fqaLEc7$= zGn%@NqON;Cw>*g^x(oPAtI+Oa)3Stc?{4PK#LU?0LfG*ao-x!I8+}=Mdo6t*M>89b zusp8S5}xo3uvLN1w%ChrIwYhUNG6noGj5}Vfo*1ikZn)2hh#*yN&LWD0*eZMJG%O# zQ?*%^2GIY;GSNSSyDMuv^%E=56 z3x#RPO;SkdMyyV2sKMricL&=_aD^Ybo9ExZ-8=_Vn_z#N^_W_eu?lUTdPmx!o*B8)l!G1iw{dVQb6Yf(vo$HqTJ_?jf zs3M05j)EdmBz@rT{_OI>(;1J%D}iU@Br^xo=8n>}U~`NSRgs^XTS&=DtII2eC`qbb z2TN5;HVm7p&{MOY=1+cEoL_P3UJ zexzkRA*E=%qOy3xTF=f{a@2T6vVxzddQDMlPAQbw<0Ts@mwh$v`v2|w5C865i%q{C zDd#C0-V-wM_Q~|ryC*DB9*MOzzbmVLmKJ7ZmKAaP3Wnz9Mu%sUw*0qEKE+pYFI^4a zOz=!)B>C--O2ZCrCy~~E>hY=cSmxR=ov1C8U(`2v?KU#oVrYv$IH6PZP|Ya~)D zQ$pe?Ayi>U^NeM|m!iKvz*Hht3T_uGva}Dr=7aI>PxB9S)>Tg2=lWClex7frxwlwo z*hp=Tx*Ny48kNCKw`Kh}mFk#**E`j=73XKR)fK^fEv+y; zk87lj@nHc1E zC(*kt{0esERVAEQu$VTTJyYFQ-IDaUBHGs^2D1VXm`Q-ZJZkipHSM5nfx7^)&Lw^* z1VOtyH=Z>PTyAOWA81_HB>xv=y7Ewbp4KZqN_(KXwoDEa&n4 zY2IVBLCl;aZy0YFHd=C!7eSkHI;EfKD!q66!Q;(+zw?*QKYy}$=fQ5U?@H3MXJS4j zVpC%A&&CaT)q35A6UFlTncR&(3Jr0iuO|VLG+CVhm?siWz;b9bDWo(F3o6qS0rNy+ z^)x_|rcVmCU%kHDf97%8>BoI1)zYiVtICB%+MhK+lH12m9kJXfJ!iQ2&IqLkFb+oS zyrPJaJ~=){3~OTLoI~u@M+|t|=L$&&^w$E1IwuLEtrFWshbXUPJs9`T=jW#Gh8Lrf zdjS%B(F`Y(cTU46n68)H%^$byS+VUI$tk<*ubJsn7RT%~$mAN+HRlty$s`5D8l%3g z<&}?pe9Am9$Q)3V8(3JoG^>lE2={Ox_5~P@)4Qc#Vn*%UihiPVwgia-!;9 zF3qaplTCF$sp^5h8FmAU`z+Ct_;;fys;`gQ7k-(3y;o<4rQ)@+vsZvO@fGz|pPz^1zk@T=3t<#gTo3Ny&rc6y zwtdv?J;Gv3`|~QR$Zlb2Q#ano(?5?_+|L`dZv0?d+nZPQAeV)2W0L#2hzXPHJ z!o!{OJS5HGbbth3Ozr6E^hHtW(2x}8q>x~3o)PtNRUu9J@*hfCI(mew7}0ZK$}0O4 zT`tnUM#U#f6mRj4wes0*pIwc48e_NhksyL?S7(Zgr7S(S9#A&#_lWgH#IMqqq63L3 zm+}%>FD*0X-@O{stL3Gu$74s-5qU{>R^8TFsww&3Rz7tTE&rdRG5+@srE~)= z|Cf#$>3mvH*s-xV)V)!V-}Tf$caQtWuJrVLL^2B!g75A9!D{IXKA^7%eAc6nz=L6Uf1 zPjKmZr(>tni)9$*uC9VUM+HFMsK8==FX|T~vu=v8#$XLraPE+bGGdX_7f)M213^kA6rI=B)2b+IQo4H4M;CuSI!3xg| zdxcrhy+IUBGJVV9nH>iaDf2g}0tfUrL*k1<8^>2}3DaAVT*Q4Qwt@|lnaig}}>p&12V{QCapjm<|_CWBLx!UHpEQc!U1hBW-gh{mi3 z_Zl;D@-lMC1()iUmcv_1D>L#+D;nZv=NjY7tFlOyHKDDy=lmLrs9AaHu%sm7quGSL z*~Ey4Nyjh2x%i04**M}OUGZT7#md#Ndx#W#2R<3EH?60Ytkt2F!W?#QEwYq@kHL47 z@twhMR5Ey-Zi|;Q%Jc1pFYHI$Ja3>%j<`#QGKVYcNgdIiPK5#YHAiJ9!(3~_8KVxm za)x=nove#nui?9Q=_y^cl%i&$x50VKTpdx%ZlefKwRF*5Cq7d_ON^*5}q zpA;D%obT@HO7Q!i)!%di)1kxN(R8A}w?Q1!+0u+{Z#+)ySzTZRs;lA zRQx}tVq&PKZepr(-qa$*)I|PNnSDrANMl!HMpZ^b7Z1-D{c3&V-dcx{vjQQ02J(M3 zE*f4`Yan)(p=wgY0)m1F7K6o9dvv+Kt*McQob-XAnyJF+2JhCyRl+JYi@6u zmGNpD)*I_wl|`(HY0fq%U&iH@revq3zm8{MNpAJmiCIW=YDyi z#B%gL)HXOhQBC)b#^^G)`!rsisja&@)oI$qm{z(z-O-Bh^^CM7xD)*>d^{rw)*hjd zryd%OzSsoWD%QaY+)RwtCUF;FtytI zRYzXe*q3STSzAPXd3`c~Fh%P1co2ERI(EBmg;XcLnNXYSY6>Ew*IT2aDvy${bcmN%GTr_tl@m&ms~>})25M*P^2G6 zQ3z+q!1O+}toCT;O{J$)bNs(&q@w(r(HcHFezU}gdk6pCMlU0K+U9bv#RZ$Bkg~qz z-3iz7(ez%3$lYL;{Xc;kZ+b$>Z+g5u*1Sf}YgyI1|JbLZ^;kZqU<#?CM$Y#GYfVK@ zc~1@dH?9aJiI{YUq-Yn{#F+lXgo(riQ#)BbeR(;3U2i?Syn?R58O0YHA&EJzr-wZ? z`-M+8$|oU%<0)>(qde5a#m=hgOY5LtVgrp_Q(>i~iD-Y%MRAsL-T))l3>dX|JQMhM zE{GQh1{gc1!b)Q4zJA`f#0t&@7&((*)pUA$i1)({?aV{SXb<+hFOONL9KNFo}f@OGsZg>pN`O-X&J4 z$G27u6jJK?KvPj$?Es~)st>BKM^2G*;KRc+lx+BjF>0wx{y$~3<(c5j;GTw_ID}t3 zq9y5ITb#`_JX5}8E8Fc@kB+cudJ!ohxv4lep)&>HTgT#^p=)G{*D^OVHR<)0$P&%s zW`lU28JQ7dbBp7m8*8#DogGz*_cx#4VM-}cG&{>BVQXWnt!ZwNYhzhhNmFIC2*q*lg|=9SFVw6smtl$0;3rCwB{9G>5o zlX(^K%JqB7H*LI*Uu;2sYC>yMMt)s8tW2}M0PC4nndOz(;C|XrgJ5B)ap59CU)RLk z4U0u%(E`}T+Nr9kv^jsnshYq4Zgp^jpNP$!-M@i6yAU7Wv&vIH((f$Iw|fFoF#iD1 z0<-?8C?}J!9TQ0C-NANn-G6?}y1=jhGg`j~FzX`-m@+%p^{m!~8-gDy7CreG$X0l# zusjj0$tE0-+QwqScy2)o9L(M;B_Dvo5=z0S1zq^h}TDAeUvd{;r%6D%m5ABR2 zrU5t+Cg{SFw;X|5^Z@zt1YPhFYmc?p+Gp*z4v3eBBoenoT+*t^_>c>g$T=n^or~Ps zxY&HCA34ac{WfY?g|2W?U`vRH>ko2zGTxui1Lv3^I~OUh4Khcho$+gza|~tYqE)9h zXpQhH*hv0(6#N$a-=ZM@SvTf{Ck_E%ND zHC(E?;%k&0FrGUGSSk1_gy;VKxT-BFU04!IROPs}vI1H@uTCtD=FQv*zzf!Iz3c&% ztjnu|#wrW5VNB#uO$WH>T>yKtZ;VlwpaU%RrWw;DOR|DqDv~Ld9Qh%_z&K)2xw1$! z%|GzcDG|4W@3k?f2k5I8J&0vqKOi2P3$#Gq2$kyrTn($?+bjDt> z7)M@&ioCG0Z^LQu@!VIAIR!xddc5O;Q_)HjK;Q9hz&z4W)W!sI&&IoR@vHD?3P`$e zay%N1U*uRIFGLW%TrXsBaZ41r>Fo3W8$bnwHjwD82>jI|iAu7mzqu{q$BVKqkeP@MvNyLDtf8R&+_F*}y2>8kYtX_k{nrF&gy z^^DDA_x*_@Ymo@2Zr!@sECsB=uwi4*q-Ode1825ZIo<8|bnDY}bi$=8*|+JWt(V4PPhG08u)T=DhB3&$(amXACWf8q=?b(0K80)Hvf^Jagc;W~HGXp|q>icLM*5zR z#CSnuF|qZRS(4brR1Jru;2Rztx?P|(eSZM(_6IQd4m$GmOkekC`84hRqsMxCH{!)!CF4c`zwo;SjIk1_06^@bJCi(~Z3`vc-!M?!VDI zn{)puBX5->Qnxng13CjiJE@aZG077drym65^Tk>0?SM*Ej&;l}vlpWuyn`P*V`Q48 zqlbz6%sX&tI?D zzY>Q(A$kp~1F?fiZ!5RGg|{^J@sAtO1DL9&^!0{?0)JtP2%$t%*@_gix&ll{QzYz| zMlm&Z%vBph2<%iQf(=Uz7#Q1GieJRCb49Vci~+>^?;1B}Iqu99-#SEGfQhj-khNh3 zGPdl+R>Z>G=6$2db=D_SFywt(iE*=u{o)zvbN;_6NO89Hp#Przemb6pF5MCUAeoX2 zF#8W{@V^eEANtotM!sp7N3s9Ao@06u4j;n^2@cLpl=pa4C@QBg4?-Q0o9oDR%RW^-TOWlISX#XqoNGZkqQ2Q|WSCev zCuP)npH#g=*2tigGA!?vGu>yfEUyQK$4LCdYS@EUeqZX4v{lH1Z?84%4+19RQj3v< zufdow8AzE^sz*+i&-ecQ^xl?A!l3(T0d8b6;^po%BzMqJZBE=JF_zUV2LTC4n3E$7 zTBQpPOQD-W2PgG_=%bW3O}Q-|;6rxCZ5lQn$ZgprxIgpV%IzUMhmT-^_;`(cPrUNQ z4pX9;o1{HKwo6CZtsF)gsWt``C28@8(=MZM6v4&#-+@&rL^=GJlHe&tVNa)t$t)Dj z0|Lo}##>jph%NwNy@6+mnh`IJ2?tfrO_4TbLHj|P!&8TUH)}OAG;^CIAb^4<9geUM zj0?S2rN^+6SA_OLwr%TsCUk;Ff1OqarIYO&_<1BOS4H3Q>k= z2-s!Yb8=gM-dDRcBevyf#?MH3GWHDGmq9E|G9uOu%n88|FHdM4|wb?bC zfe76K6db16n~HFonlxNeQV>>m>Iq+ThvOLH+o<5=!c#1SoV;)UshP{3Gxc!#$zP%L z!=D2CN52Kg@UQbC2PHQk;E?*t>8=Nqhs!q@{9s?2dFA;7E18|LR=vCxY^Y5@8RRTv zy%1Pg+O2kz4d#2P2tW$WTpBWAd$(QS1r<}BprOmUYtf#auJRh{!pITErw^uSP*7qh zMM(7l&NMcii7pP7I>4AURWQIY6-0X$^<;Rw$wT8b6*C$ z)!s&m1oi~1on3)yn?Jx5d0V9v)?J6B$}!?VhHpH~4Y=c=SdKaC9V|Cq=4mpJ4C&cj z|7p;dvx`yobshrb^nMOY#;`DJHwz!m5Z?|bK$cpQRa0c>*tzCm)T6Vr7#%oKWF_=5 z7^#-H?HsFCToa%|G0{b{GGhu&o(-$DgI_69gsPMfsb;A3*?-kmJxFeJq*s`{?6UN% z>uVSAbpthgI~|OCmeGnVg>oNqQ!_Q>X*s^ww5G@BY=KL=gGLx72>>G0H>K3Rp8bxC9pNZYh z1MIiowxgX`FCMyZ8;^${S%!^_i#pTXM%ca z22+0Bg}vGp=&`z6#9!VWjTB1wqIk}AmIJ#PM^wAij*^*{9Z|I=m~*pgw01PI z<9$(LY4YaDWZj~cqE0GJL}&!Sei-cGnyO#TW=vs?A_`>BE(iTD!n!}EDCfY`;J~Q) zH$VPMX{cbp--=@q)uOIS=fWsVO5PgN%=pr>wK8X-#+U0?dXj=jk$R7__r#A1!20y~ z%ovu-sLu`|6+1elS*hpE$SPQB&0y^3)2a@a9v^}zwc6dRtmI)Nb<|~lcW%vgS8gD~ z*k6$ff2a!}-g$0r$A|~tt-A0gSP|_oNT4w+*d^AM*u1qFS2+HfkxYKTHnQEq%A|Xb zL+vm|7dlB}JT2ijN)H0O^lm=DToQjzhfia0*}`zv{vk3?K}4{A;RJkG)jVt$0TcV2 z+|zCuO52qV_*Jsu=)za`-p zq?m0Q0=SjUohV))PbGom$X*10+jlXo{v1AI8*?;>zXxBiy!xCnF;Y+m^G$P*l(A1q zDiWQLRdR$kYQ)o7ElR)$7Lt+|1Sm252vlgGa5jW@d~#*bE*Q+a14;RyD$ECc3vEo( z;XzFp!}>YFIG~wdwv|F|SVna=_))>0|@p?&%*^2SP27}9IztKhyyWr90 z<9}K%wxEdft@yE)FUbq|kg=C33X!7Q@|0KeXbx4~NL- z=8F;@bX-%8=ZhOA<-WJtcqHtjMjaR)*2an)c|eD8+qlI|;|AN|?G1LdS66mE-}G8U zWcb<8wLouhXdG}}K8Nao9ZPm1#?Xztn5tI`KIu%?X&=aA3d9&~5urn+%YOgMf;GcL zLxz^oIJdrnj)K_zxbyGgBPNoTX$3 zatVz4Mo+tKY3j!tm-Z#njj2LnOf1%Q)IM8ZP=}!&;Tq1O6;YE|QxdrwF;G2%*6CWL zmU9j~qA>%zd*yp}?DwMhdG*-;?<~T>7FtL&x0D!7E>3u$5oOpf zhl1H>qLbZiU&s#(@br(qmm)5+>D`US(3zsas@;DSi;xWN*uvyyg z^jt2CGOJ~dT;-?=Mdmb~ee=$KZKTa@i^`vLXYg$iCEg|Iqwid;0Ri~aE-VdXX3eq8tm=`OJ(k@E8lUXVL>JvHr616b zw>I%b+1XuUzHY|3`FgxYFI_*D^+wN(a%Mj{meyP4o|{?S%R*Zl_)*{uxyz=j=VD85 zch{`ay60w7aBk+rKrT&tAeTno?ePBzdF;OJH=M z_HR|oZK43XfB^_#x$h1;0J~i4KSKXacaZ~uEBw9+_!`H5Z~m*fm*%7*^?PxhDr{^B z>|gxC&!xO3CvTD}BH_+w5v4>@nPdtnE;E=}lJqD*FSvm_C_^n|gE>U3Y~T1OH?BC{ z+>F~-b<4=DMHd%YK|_^r|Iss)#SLveU7&=J9*ii7V?<9%8}A^>gGmxB0`o5r5=Oe% z!T$F64ej^3dy-WzkRNgi1|Q)?faYML*2}p1YwS}@X&F0}Vp!^ybgCXxK8jj93+)sI zEyuO9c(f+BT%^${JUc)^d{P((>tvNvVSG}*z)?C#K^Jq8F$;L)C;->f1}uFqq}m}q z;m+0%r|TA8<>;8BbmEIa6FVYh-Sbh}Q($*;86)`lrHCtjtE^vhE=PXTgiDnvt7-ln zCT*H>u3km?Pi7nP%0qg2NGmfXHA!t9&`(}v@kewXN~|`CHN}5yu$#)Prke1&1-~S& zpBv9F8a&YnS;(=3`MwM!T^iA&e3h~Mg#76A*MSIz0k0SUDrY3OL3+KQuwXVj33 zDkpM9K(5osX(w_Bc{nRieu%VWedHaKlWcv``iU>gM)e(!0myr4I%8@ zH-zC7lnLLL$pjlBNQvJNNm%3EH_iFv5ASAR2RGFNqPts|)rvq9}np%pAx}R&?G4<4d2H z%_hA-gR#*fsFU53I8%m~2p8)kfFBvsi56syKt2}2(7yb#%$U$;zycw1Y118Y;Ff!| zPWdVsHI4l&4V(o-5E^zC8sdhi2jkr8a*{%5fI17tA>#`&;yky6ahRjA>M3pqx6xOU zLgy=0{(Xvbn}pd!U%#~SN-QAMPa zEz8$J#E$*x5ZOn=j)Moy&Vsb#)KEAn%x%Y|qjXw?X9U_x*P=PV5QdHUEDijjp!gwe zK`3g-<5^4-WNV^_EX8n=$=khbU{rWstK(0d5tp&(WhJ>(%$#e3qBpj{I) O6y7R}gQBj@I4BA`2c0zl literal 0 HcmV?d00001 diff --git a/interface/public/index.html b/interface/public/index.html new file mode 100644 index 0000000..209254a --- /dev/null +++ b/interface/public/index.html @@ -0,0 +1,16 @@ + + + + + + + + ESP8266 React + + + +
+ + diff --git a/interface/src/App.tsx b/interface/src/App.tsx new file mode 100644 index 0000000..532050e --- /dev/null +++ b/interface/src/App.tsx @@ -0,0 +1,50 @@ +import React, { Component, RefObject } from 'react'; +import { Redirect, Route, Switch } from 'react-router'; +import { SnackbarProvider } from 'notistack'; + +import { IconButton } from '@material-ui/core'; +import CloseIcon from '@material-ui/icons/Close'; + +import AppRouting from './AppRouting'; +import CustomMuiTheme from './CustomMuiTheme'; +import { PROJECT_NAME } from './api'; +import FeaturesWrapper from './features/FeaturesWrapper'; + +// this redirect forces a call to authenticationContext.refresh() which invalidates the JWT if it is invalid. +const unauthorizedRedirect = () => ; + +class App extends Component { + + notistackRef: RefObject = React.createRef(); + + componentDidMount() { + document.title = PROJECT_NAME; + } + + onClickDismiss = (key: string | number | undefined) => () => { + this.notistackRef.current.closeSnackbar(key); + } + + render() { + return ( + + ( + + + + )}> + + + + + + + + + ); + } +} + +export default App diff --git a/interface/src/AppRouting.tsx b/interface/src/AppRouting.tsx new file mode 100644 index 0000000..f17d5b5 --- /dev/null +++ b/interface/src/AppRouting.tsx @@ -0,0 +1,60 @@ +import React, { Component } from 'react'; +import { Switch, Redirect } from 'react-router'; + +import * as Authentication from './authentication/Authentication'; +import AuthenticationWrapper from './authentication/AuthenticationWrapper'; +import UnauthenticatedRoute from './authentication/UnauthenticatedRoute'; +import AuthenticatedRoute from './authentication/AuthenticatedRoute'; + +import SignIn from './SignIn'; +import ProjectRouting from './project/ProjectRouting'; +import WiFiConnection from './wifi/WiFiConnection'; +import AccessPoint from './ap/AccessPoint'; +import NetworkTime from './ntp/NetworkTime'; +import Security from './security/Security'; +import System from './system/System'; + +import { PROJECT_PATH } from './api'; +import Mqtt from './mqtt/Mqtt'; +import { withFeatures, WithFeaturesProps } from './features/FeaturesContext'; +import { Features } from './features/types'; + +export const getDefaultRoute = (features: Features) => features.project ? `/${PROJECT_PATH}/` : "/wifi/"; + +class AppRouting extends Component { + + componentDidMount() { + Authentication.clearLoginRedirect(); + } + + render() { + const { features } = this.props; + return ( + + + {features.security && ( + + )} + {features.project && ( + + )} + + + {features.ntp && ( + + )} + {features.mqtt && ( + + )} + {features.security && ( + + )} + + + + + ) + } +} + +export default withFeatures(AppRouting); diff --git a/interface/src/CustomMuiTheme.tsx b/interface/src/CustomMuiTheme.tsx new file mode 100644 index 0000000..570ed7f --- /dev/null +++ b/interface/src/CustomMuiTheme.tsx @@ -0,0 +1,39 @@ +import React, { Component } from 'react'; + +import { CssBaseline } from '@material-ui/core'; +import { MuiThemeProvider, createMuiTheme, StylesProvider } from '@material-ui/core/styles'; +import { blueGrey, indigo, orange, red, green } from '@material-ui/core/colors'; + +const theme = createMuiTheme({ + palette: { + primary: indigo, + secondary: blueGrey, + info: { + main: blueGrey[900] + }, + warning: { + main: orange[500] + }, + error: { + main: red[500] + }, + success: { + main: green[500] + } + }, +}); + +export default class CustomMuiTheme extends Component { + + render() { + return ( + + + + {this.props.children} + + + ); + } + +} diff --git a/interface/src/SignIn.tsx b/interface/src/SignIn.tsx new file mode 100644 index 0000000..e4df446 --- /dev/null +++ b/interface/src/SignIn.tsx @@ -0,0 +1,147 @@ +import React, { Component } from 'react'; +import { withSnackbar, WithSnackbarProps } from 'notistack'; +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; + +import { withStyles, createStyles, Theme, WithStyles } from '@material-ui/core/styles'; +import { Paper, Typography, Fab } from '@material-ui/core'; +import ForwardIcon from '@material-ui/icons/Forward'; + +import { withAuthenticationContext, AuthenticationContextProps } from './authentication/AuthenticationContext'; +import {PasswordValidator} from './components'; +import { PROJECT_NAME, SIGN_IN_ENDPOINT } from './api'; + +const styles = (theme: Theme) => createStyles({ + signInPage: { + display: "flex", + height: "100vh", + margin: "auto", + padding: theme.spacing(2), + justifyContent: "center", + flexDirection: "column", + maxWidth: theme.breakpoints.values.sm + }, + signInPanel: { + textAlign: "center", + padding: theme.spacing(2), + paddingTop: "200px", + backgroundImage: 'url("/app/icon.png")', + backgroundRepeat: "no-repeat", + backgroundPosition: "50% " + theme.spacing(2) + "px", + backgroundSize: "auto 150px", + width: "100%" + }, + extendedIcon: { + marginRight: theme.spacing(0.5), + }, + button: { + marginRight: theme.spacing(2), + marginTop: theme.spacing(2), + } +}); + +type SignInProps = WithSnackbarProps & WithStyles & AuthenticationContextProps; + +interface SignInState { + username: string, + password: string, + processing: boolean +} + +class SignIn extends Component { + + constructor(props: SignInProps) { + super(props); + this.state = { + username: '', + password: '', + processing: false + }; + } + + updateInputElement = (event: React.ChangeEvent): void => { + const { name, value } = event.currentTarget; + this.setState(prevState => ({ + ...prevState, + [name]: value, + })) + }; + + onSubmit = () => { + const { username, password } = this.state; + const { authenticationContext } = this.props; + this.setState({ processing: true }); + fetch(SIGN_IN_ENDPOINT, { + method: 'POST', + body: JSON.stringify({ username, password }), + headers: new Headers({ + 'Content-Type': 'application/json' + }) + }) + .then(response => { + if (response.status === 200) { + return response.json(); + } else if (response.status === 401) { + throw Error("Invalid credentials."); + } else { + throw Error("Invalid status code: " + response.status); + } + }).then(json => { + authenticationContext.signIn(json.access_token); + }) + .catch(error => { + this.props.enqueueSnackbar(error.message, { + variant: 'warning', + }); + this.setState({ processing: false }); + }); + }; + + render() { + const { username, password, processing } = this.state; + const { classes } = this.props; + return ( +
+ + {PROJECT_NAME} + + + + + + Sign In + + + +
+ ); + } + +} + +export default withAuthenticationContext(withSnackbar(withStyles(styles)(SignIn))); diff --git a/interface/src/ap/APModes.ts b/interface/src/ap/APModes.ts new file mode 100644 index 0000000..6a705db --- /dev/null +++ b/interface/src/ap/APModes.ts @@ -0,0 +1,5 @@ +import { APSettings, APProvisionMode } from "./types"; + +export const isAPEnabled = ({ provision_mode }: APSettings) => { + return provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED; +} diff --git a/interface/src/ap/APSettingsController.tsx b/interface/src/ap/APSettingsController.tsx new file mode 100644 index 0000000..3284b4a --- /dev/null +++ b/interface/src/ap/APSettingsController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import { AP_SETTINGS_ENDPOINT } from '../api'; +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; + +import APSettingsForm from './APSettingsForm'; +import { APSettings } from './types'; + +type APSettingsControllerProps = RestControllerProps; + +class APSettingsController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ) + } + +} + +export default restController(AP_SETTINGS_ENDPOINT, APSettingsController); diff --git a/interface/src/ap/APSettingsForm.tsx b/interface/src/ap/APSettingsForm.tsx new file mode 100644 index 0000000..4828c7b --- /dev/null +++ b/interface/src/ap/APSettingsForm.tsx @@ -0,0 +1,106 @@ +import React, { Fragment } from 'react'; +import { TextValidator, ValidatorForm, SelectValidator } from 'react-material-ui-form-validator'; + +import MenuItem from '@material-ui/core/MenuItem'; +import SaveIcon from '@material-ui/icons/Save'; + +import { PasswordValidator, RestFormProps, FormActions, FormButton } from '../components'; + +import { isAPEnabled } from './APModes'; +import { APSettings, APProvisionMode } from './types'; +import { isIP } from '../validators'; + +type APSettingsFormProps = RestFormProps; + +class APSettingsForm extends React.Component { + + componentWillMount() { + ValidatorForm.addValidationRule('isIP', isIP); + } + + render() { + const { data, handleValueChange, saveData } = this.props; + return ( + + + Always + When WiFi Disconnected + Never + + { + isAPEnabled(data) && + + + + + + + + } + + } variant="contained" color="primary" type="submit"> + Save + + + + ); + } +} + +export default APSettingsForm; diff --git a/interface/src/ap/APStatus.ts b/interface/src/ap/APStatus.ts new file mode 100644 index 0000000..c35cadc --- /dev/null +++ b/interface/src/ap/APStatus.ts @@ -0,0 +1,28 @@ +import { Theme } from "@material-ui/core"; +import { APStatus, APNetworkStatus } from "./types"; + +export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => { + switch (status) { + case APNetworkStatus.ACTIVE: + return theme.palette.success.main; + case APNetworkStatus.INACTIVE: + return theme.palette.info.main; + case APNetworkStatus.LINGERING: + return theme.palette.warning.main; + default: + return theme.palette.warning.main; + } +} + +export const apStatus = ({ status }: APStatus) => { + switch (status) { + case APNetworkStatus.ACTIVE: + return "Active"; + case APNetworkStatus.INACTIVE: + return "Inactive"; + case APNetworkStatus.LINGERING: + return "Lingering until idle"; + default: + return "Unknown"; + } +}; diff --git a/interface/src/ap/APStatusController.tsx b/interface/src/ap/APStatusController.tsx new file mode 100644 index 0000000..e406bca --- /dev/null +++ b/interface/src/ap/APStatusController.tsx @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { AP_STATUS_ENDPOINT } from '../api'; + +import APStatusForm from './APStatusForm'; +import { APStatus } from './types'; + +type APStatusControllerProps = RestControllerProps; + +class APStatusController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ) + } +} + +export default restController(AP_STATUS_ENDPOINT, APStatusController); diff --git a/interface/src/ap/APStatusForm.tsx b/interface/src/ap/APStatusForm.tsx new file mode 100644 index 0000000..88c2135 --- /dev/null +++ b/interface/src/ap/APStatusForm.tsx @@ -0,0 +1,78 @@ +import React, { Component, Fragment } from 'react'; + +import { WithTheme, withTheme } from '@material-ui/core/styles'; +import { Avatar, Divider, List, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'; + +import SettingsInputAntennaIcon from '@material-ui/icons/SettingsInputAntenna'; +import DeviceHubIcon from '@material-ui/icons/DeviceHub'; +import ComputerIcon from '@material-ui/icons/Computer'; +import RefreshIcon from '@material-ui/icons/Refresh'; + +import { RestFormProps, FormActions, FormButton, HighlightAvatar } from '../components'; +import { apStatusHighlight, apStatus } from './APStatus'; +import { APStatus } from './types'; + +type APStatusFormProps = RestFormProps & WithTheme; + +class APStatusForm extends Component { + + createListItems() { + const { data, theme } = this.props + return ( + + + + + + + + + + + + + IP + + + + + + + + + + + + + + + + + + + + + + + + ); + } + + render() { + return ( + + + {this.createListItems()} + + + } variant="contained" color="secondary" onClick={this.props.loadData}> + Refresh + + + + ); + } + +} + +export default withTheme(APStatusForm); diff --git a/interface/src/ap/AccessPoint.tsx b/interface/src/ap/AccessPoint.tsx new file mode 100644 index 0000000..eba011e --- /dev/null +++ b/interface/src/ap/AccessPoint.tsx @@ -0,0 +1,38 @@ +import React, { Component } from 'react'; +import { Redirect, Switch, RouteComponentProps } from 'react-router-dom' + +import { Tabs, Tab } from '@material-ui/core'; + +import { AuthenticatedContextProps, withAuthenticatedContext, AuthenticatedRoute } from '../authentication'; +import { MenuAppBar } from '../components'; + +import APSettingsController from './APSettingsController'; +import APStatusController from './APStatusController'; + +type AccessPointProps = AuthenticatedContextProps & RouteComponentProps; + +class AccessPoint extends Component { + + handleTabChange = (event: React.ChangeEvent<{}>, path: string) => { + this.props.history.push(path); + }; + + render() { + const { authenticatedContext } = this.props; + return ( + + + + + + + + + + + + ) + } +} + +export default withAuthenticatedContext(AccessPoint); diff --git a/interface/src/ap/types.ts b/interface/src/ap/types.ts new file mode 100644 index 0000000..437d0e6 --- /dev/null +++ b/interface/src/ap/types.ts @@ -0,0 +1,27 @@ +export enum APProvisionMode { + AP_MODE_ALWAYS = 0, + AP_MODE_DISCONNECTED = 1, + AP_NEVER = 2 +} + +export enum APNetworkStatus { + ACTIVE = 0, + INACTIVE = 1, + LINGERING = 2 +} + +export interface APStatus { + status: APNetworkStatus; + ip_address: string; + mac_address: string; + station_num: number; +} + +export interface APSettings { + provision_mode: APProvisionMode; + ssid: string; + password: string; + local_ip: string; + gateway_ip: string; + subnet_mask: string; +} diff --git a/interface/src/api/Endpoints.ts b/interface/src/api/Endpoints.ts new file mode 100644 index 0000000..a0be3d4 --- /dev/null +++ b/interface/src/api/Endpoints.ts @@ -0,0 +1,22 @@ +import { ENDPOINT_ROOT } from './Env'; + +export const FEATURES_ENDPOINT = ENDPOINT_ROOT + "features"; +export const NTP_STATUS_ENDPOINT = ENDPOINT_ROOT + "ntpStatus"; +export const NTP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "ntpSettings"; +export const TIME_ENDPOINT = ENDPOINT_ROOT + "time"; +export const AP_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "apSettings"; +export const AP_STATUS_ENDPOINT = ENDPOINT_ROOT + "apStatus"; +export const SCAN_NETWORKS_ENDPOINT = ENDPOINT_ROOT + "scanNetworks"; +export const LIST_NETWORKS_ENDPOINT = ENDPOINT_ROOT + "listNetworks"; +export const WIFI_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "wifiSettings"; +export const WIFI_STATUS_ENDPOINT = ENDPOINT_ROOT + "wifiStatus"; +export const OTA_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "otaSettings"; +export const UPLOAD_FIRMWARE_ENDPOINT = ENDPOINT_ROOT + "uploadFirmware"; +export const MQTT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "mqttSettings"; +export const MQTT_STATUS_ENDPOINT = ENDPOINT_ROOT + "mqttStatus"; +export const SYSTEM_STATUS_ENDPOINT = ENDPOINT_ROOT + "systemStatus"; +export const SIGN_IN_ENDPOINT = ENDPOINT_ROOT + "signIn"; +export const VERIFY_AUTHORIZATION_ENDPOINT = ENDPOINT_ROOT + "verifyAuthorization"; +export const SECURITY_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "securitySettings"; +export const RESTART_ENDPOINT = ENDPOINT_ROOT + "restart"; +export const FACTORY_RESET_ENDPOINT = ENDPOINT_ROOT + "factoryReset"; diff --git a/interface/src/api/Env.ts b/interface/src/api/Env.ts new file mode 100644 index 0000000..9992e68 --- /dev/null +++ b/interface/src/api/Env.ts @@ -0,0 +1,24 @@ +export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME!; +export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH!; + +export const ENDPOINT_ROOT = calculateEndpointRoot("/rest/"); +export const WEB_SOCKET_ROOT = calculateWebSocketRoot("/ws/"); + +function calculateEndpointRoot(endpointPath: string) { + const httpRoot = process.env.REACT_APP_HTTP_ROOT; + if (httpRoot) { + return httpRoot + endpointPath; + } + const location = window.location; + return location.protocol + "//" + location.host + endpointPath; +} + +function calculateWebSocketRoot(webSocketPath: string) { + const webSocketRoot = process.env.REACT_APP_WEB_SOCKET_ROOT; + if (webSocketRoot) { + return webSocketRoot + webSocketPath; + } + const location = window.location; + const webProtocol = location.protocol === "https:" ? "wss:" : "ws:"; + return webProtocol + "//" + location.host + webSocketPath; +} diff --git a/interface/src/api/index.ts b/interface/src/api/index.ts new file mode 100644 index 0000000..8ec5797 --- /dev/null +++ b/interface/src/api/index.ts @@ -0,0 +1,2 @@ +export * from './Env' +export * from './Endpoints' diff --git a/interface/src/authentication/AuthenticatedRoute.tsx b/interface/src/authentication/AuthenticatedRoute.tsx new file mode 100644 index 0000000..e07b69d --- /dev/null +++ b/interface/src/authentication/AuthenticatedRoute.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { Redirect, Route, RouteProps, RouteComponentProps } from "react-router-dom"; +import { withSnackbar, WithSnackbarProps } from 'notistack'; + +import * as Authentication from './Authentication'; +import { withAuthenticationContext, AuthenticationContextProps, AuthenticatedContext } from './AuthenticationContext'; + +type ChildComponent = React.ComponentType> | React.ComponentType; + +interface AuthenticatedRouteProps extends RouteProps, WithSnackbarProps, AuthenticationContextProps { + component: ChildComponent; +} + +type RenderComponent = (props: RouteComponentProps) => React.ReactNode; + +export class AuthenticatedRoute extends React.Component { + + render() { + const { enqueueSnackbar, authenticationContext, component: Component, ...rest } = this.props; + const { location } = this.props; + const renderComponent: RenderComponent = (props) => { + if (authenticationContext.me) { + return ( + + + + ); + } + Authentication.storeLoginRedirect(location); + enqueueSnackbar("Please sign in to continue.", { variant: 'info' }); + return ( + + ); + } + return ( + + ); + } + +} + +export default withSnackbar(withAuthenticationContext(AuthenticatedRoute)); diff --git a/interface/src/authentication/Authentication.ts b/interface/src/authentication/Authentication.ts new file mode 100644 index 0000000..4c87493 --- /dev/null +++ b/interface/src/authentication/Authentication.ts @@ -0,0 +1,114 @@ +import * as H from 'history'; + +import history from '../history'; +import { Features } from '../features/types'; +import { getDefaultRoute } from '../AppRouting'; + +export const ACCESS_TOKEN = 'access_token'; +export const SIGN_IN_PATHNAME = 'signInPathname'; +export const SIGN_IN_SEARCH = 'signInSearch'; + +/** + * Fallback to sessionStorage if localStorage is absent. WebView may not have local storage enabled. + */ +export function getStorage() { + return localStorage || sessionStorage; +} + +export function storeLoginRedirect(location?: H.Location) { + if (location) { + getStorage().setItem(SIGN_IN_PATHNAME, location.pathname); + getStorage().setItem(SIGN_IN_SEARCH, location.search); + } +} + +export function clearLoginRedirect() { + getStorage().removeItem(SIGN_IN_PATHNAME); + getStorage().removeItem(SIGN_IN_SEARCH); +} + +export function fetchLoginRedirect(features: Features): H.LocationDescriptorObject { + const signInPathname = getStorage().getItem(SIGN_IN_PATHNAME); + const signInSearch = getStorage().getItem(SIGN_IN_SEARCH); + clearLoginRedirect(); + return { + pathname: signInPathname || getDefaultRoute(features), + search: (signInPathname && signInSearch) || undefined + }; +} + +/** + * Wraps the normal fetch routene with one with provides the access token if present. + */ +export function authorizedFetch(url: RequestInfo, params?: RequestInit): Promise { + const accessToken = getStorage().getItem(ACCESS_TOKEN); + if (accessToken) { + params = params || {}; + params.credentials = 'include'; + params.headers = { + ...params.headers, + "Authorization": 'Bearer ' + accessToken + }; + } + return fetch(url, params); +} + +/** + * fetch() does not yet support upload progress, this wrapper allows us to configure the xhr request + * for a single file upload and takes care of adding the Authroization header and redirecting on + * authroization errors as we do for normal fetch operations. + */ +export function redirectingAuthorizedUpload(xhr: XMLHttpRequest, url: string, file: File, onProgress: (event: ProgressEvent) => void): Promise { + return new Promise((resolve, reject) => { + xhr.open("POST", url, true); + const accessToken = getStorage().getItem(ACCESS_TOKEN); + if (accessToken) { + xhr.withCredentials = true; + xhr.setRequestHeader("Authorization", 'Bearer ' + accessToken); + } + xhr.upload.onprogress = onProgress; + xhr.onload = function () { + if (xhr.status === 401 || xhr.status === 403) { + history.push("/unauthorized"); + } else { + resolve(); + } + }; + xhr.onerror = function (event: ProgressEvent) { + reject(new DOMException('Error', 'UploadError')); + }; + xhr.onabort = function () { + reject(new DOMException('Aborted', 'AbortError')); + }; + const formData = new FormData(); + formData.append('file', file); + xhr.send(formData); + }); +} + +/** + * Wraps the normal fetch routene which redirects on 401 response. + */ +export function redirectingAuthorizedFetch(url: RequestInfo, params?: RequestInit): Promise { + return new Promise((resolve, reject) => { + authorizedFetch(url, params).then(response => { + if (response.status === 401 || response.status === 403) { + history.push("/unauthorized"); + } else { + resolve(response); + } + }).catch(error => { + reject(error); + }); + }); +} + +export function addAccessTokenParameter(url: string) { + const accessToken = getStorage().getItem(ACCESS_TOKEN); + if (!accessToken) { + return url; + } + const parsedUrl = new URL(url); + parsedUrl.searchParams.set(ACCESS_TOKEN, accessToken); + return parsedUrl.toString(); +} diff --git a/interface/src/authentication/AuthenticationContext.tsx b/interface/src/authentication/AuthenticationContext.tsx new file mode 100644 index 0000000..aaf22ba --- /dev/null +++ b/interface/src/authentication/AuthenticationContext.tsx @@ -0,0 +1,59 @@ +import * as React from "react"; + +export interface Me { + username: string; + admin: boolean; +} + +export interface AuthenticationContext { + refresh: () => void; + signIn: (accessToken: string) => void; + signOut: () => void; + me?: Me; +} + +const AuthenticationContextDefaultValue = {} as AuthenticationContext +export const AuthenticationContext = React.createContext( + AuthenticationContextDefaultValue +); + +export interface AuthenticationContextProps { + authenticationContext: AuthenticationContext; +} + +export function withAuthenticationContext(Component: React.ComponentType) { + return class extends React.Component> { + render() { + return ( + + {authenticationContext => } + + ); + } + }; +} + +export interface AuthenticatedContext extends AuthenticationContext { + me: Me; +} + +const AuthenticatedContextDefaultValue = {} as AuthenticatedContext +export const AuthenticatedContext = React.createContext( + AuthenticatedContextDefaultValue +); + +export interface AuthenticatedContextProps { + authenticatedContext: AuthenticatedContext; +} + +export function withAuthenticatedContext(Component: React.ComponentType) { + return class extends React.Component> { + render() { + return ( + + {authenticatedContext => } + + ); + } + }; +} diff --git a/interface/src/authentication/AuthenticationWrapper.tsx b/interface/src/authentication/AuthenticationWrapper.tsx new file mode 100644 index 0000000..2b65a13 --- /dev/null +++ b/interface/src/authentication/AuthenticationWrapper.tsx @@ -0,0 +1,109 @@ +import * as React from 'react'; +import { withSnackbar, WithSnackbarProps } from 'notistack'; +import jwtDecode from 'jwt-decode'; + +import history from '../history' +import { VERIFY_AUTHORIZATION_ENDPOINT } from '../api'; +import { ACCESS_TOKEN, authorizedFetch, getStorage } from './Authentication'; +import { AuthenticationContext, Me } from './AuthenticationContext'; +import FullScreenLoading from '../components/FullScreenLoading'; +import { withFeatures, WithFeaturesProps } from '../features/FeaturesContext'; + +export const decodeMeJWT = (accessToken: string): Me => jwtDecode(accessToken) as Me; + +interface AuthenticationWrapperState { + context: AuthenticationContext; + initialized: boolean; +} + +type AuthenticationWrapperProps = WithSnackbarProps & WithFeaturesProps; + +class AuthenticationWrapper extends React.Component { + + constructor(props: AuthenticationWrapperProps) { + super(props); + this.state = { + context: { + refresh: this.refresh, + signIn: this.signIn, + signOut: this.signOut, + }, + initialized: false + }; + } + + componentDidMount() { + this.refresh(); + } + + render() { + return ( + + {this.state.initialized ? this.renderContent() : this.renderContentLoading()} + + ); + } + + renderContent() { + return ( + + {this.props.children} + + ); + } + + renderContentLoading() { + return ( + + ); + } + + refresh = () => { + if (!this.props.features.security) { + this.setState({ initialized: true, context: { ...this.state.context, me: { admin: true, username: "admin" } } }); + return; + } + const accessToken = getStorage().getItem(ACCESS_TOKEN) + if (accessToken) { + authorizedFetch(VERIFY_AUTHORIZATION_ENDPOINT) + .then(response => { + const me = response.status === 200 ? decodeMeJWT(accessToken) : undefined; + this.setState({ initialized: true, context: { ...this.state.context, me } }); + }).catch(error => { + this.setState({ initialized: true, context: { ...this.state.context, me: undefined } }); + this.props.enqueueSnackbar("Error verifying authorization: " + error.message, { + variant: 'error', + }); + }); + } else { + this.setState({ initialized: true, context: { ...this.state.context, me: undefined } }); + } + } + + signIn = (accessToken: string) => { + try { + getStorage().setItem(ACCESS_TOKEN, accessToken); + const me: Me = decodeMeJWT(accessToken); + this.setState({ context: { ...this.state.context, me } }); + this.props.enqueueSnackbar(`Logged in as ${me.username}`, { variant: 'success' }); + } catch (err) { + this.setState({ initialized: true, context: { ...this.state.context, me: undefined } }); + throw new Error("Failed to parse JWT " + err.message); + } + } + + signOut = () => { + getStorage().removeItem(ACCESS_TOKEN); + this.setState({ + context: { + ...this.state.context, + me: undefined + } + }); + this.props.enqueueSnackbar("You have signed out.", { variant: 'success', }); + history.push('/'); + } + +} + +export default withFeatures(withSnackbar(AuthenticationWrapper)) diff --git a/interface/src/authentication/UnauthenticatedRoute.tsx b/interface/src/authentication/UnauthenticatedRoute.tsx new file mode 100644 index 0000000..25689fd --- /dev/null +++ b/interface/src/authentication/UnauthenticatedRoute.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { Redirect, Route, RouteProps, RouteComponentProps } from "react-router-dom"; + +import { withAuthenticationContext, AuthenticationContextProps } from './AuthenticationContext'; +import * as Authentication from './Authentication'; +import { WithFeaturesProps, withFeatures } from '../features/FeaturesContext'; + +interface UnauthenticatedRouteProps extends RouteProps, AuthenticationContextProps, WithFeaturesProps { + component: React.ComponentType> | React.ComponentType; +} + +type RenderComponent = (props: RouteComponentProps) => React.ReactNode; + +class UnauthenticatedRoute extends Route { + + public render() { + const { authenticationContext, component: Component, features, ...rest } = this.props; + const renderComponent: RenderComponent = (props) => { + if (authenticationContext.me) { + return (); + } + return (); + } + return ( + + ); + } +} + +export default withFeatures(withAuthenticationContext(UnauthenticatedRoute)); diff --git a/interface/src/authentication/index.ts b/interface/src/authentication/index.ts new file mode 100644 index 0000000..fa528ff --- /dev/null +++ b/interface/src/authentication/index.ts @@ -0,0 +1,6 @@ +export { default as AuthenticatedRoute } from './AuthenticatedRoute'; +export { default as AuthenticationWrapper } from './AuthenticationWrapper'; +export { default as UnauthenticatedRoute } from './UnauthenticatedRoute'; + +export * from './Authentication'; +export * from './AuthenticationContext'; \ No newline at end of file diff --git a/interface/src/components/ApplicationError.tsx b/interface/src/components/ApplicationError.tsx new file mode 100644 index 0000000..7fbe0fc --- /dev/null +++ b/interface/src/components/ApplicationError.tsx @@ -0,0 +1,59 @@ +import React, { FC } from 'react'; +import { makeStyles } from '@material-ui/styles'; +import { Paper, Typography, Box, CssBaseline } from "@material-ui/core"; +import WarningIcon from "@material-ui/icons/Warning" + +const styles = makeStyles( + { + siteErrorPage: { + display: "flex", + height: "100vh", + justifyContent: "center", + flexDirection: "column" + }, + siteErrorPagePanel: { + textAlign: "center", + padding: "280px 0 40px 0", + backgroundImage: 'url("/app/icon.png")', + backgroundRepeat: "no-repeat", + backgroundPosition: "50% 40px", + backgroundSize: "200px auto", + width: "100%", + } + } +); + +interface ApplicationErrorProps { + error?: string; +} + +const ApplicationError: FC = ({ error }) => { + const classes = styles(); + return ( +
+ + + + + + + Application error + + + + + Failed to configure the application, please refresh to try again. + + {error && + ( + + Error: {error} + + ) + } + +
+ ); +} + +export default ApplicationError; diff --git a/interface/src/components/BlockFormControlLabel.tsx b/interface/src/components/BlockFormControlLabel.tsx new file mode 100644 index 0000000..2ea2eba --- /dev/null +++ b/interface/src/components/BlockFormControlLabel.tsx @@ -0,0 +1,10 @@ +import React, { FC } from "react"; +import { FormControlLabel, FormControlLabelProps } from "@material-ui/core"; + +const BlockFormControlLabel: FC = (props) => ( +
+ +
+) + +export default BlockFormControlLabel; diff --git a/interface/src/components/ErrorButton.tsx b/interface/src/components/ErrorButton.tsx new file mode 100644 index 0000000..c93cddd --- /dev/null +++ b/interface/src/components/ErrorButton.tsx @@ -0,0 +1,11 @@ +import { Button, styled } from "@material-ui/core"; + +const ErrorButton = styled(Button)(({ theme }) => ({ + color: theme.palette.getContrastText(theme.palette.error.main), + backgroundColor: theme.palette.error.main, + '&:hover': { + backgroundColor: theme.palette.error.dark, + } +})); + +export default ErrorButton; diff --git a/interface/src/components/FormActions.tsx b/interface/src/components/FormActions.tsx new file mode 100644 index 0000000..8c6eb73 --- /dev/null +++ b/interface/src/components/FormActions.tsx @@ -0,0 +1,7 @@ +import { styled, Box } from "@material-ui/core"; + +const FormActions = styled(Box)(({ theme }) => ({ + marginTop: theme.spacing(1) +})); + +export default FormActions; diff --git a/interface/src/components/FormButton.tsx b/interface/src/components/FormButton.tsx new file mode 100644 index 0000000..f14ef06 --- /dev/null +++ b/interface/src/components/FormButton.tsx @@ -0,0 +1,13 @@ +import { Button, styled } from "@material-ui/core"; + +const FormButton = styled(Button)(({ theme }) => ({ + margin: theme.spacing(0, 1), + '&:last-child': { + marginRight: 0, + }, + '&:first-child': { + marginLeft: 0, + } +})); + +export default FormButton; diff --git a/interface/src/components/FullScreenLoading.tsx b/interface/src/components/FullScreenLoading.tsx new file mode 100644 index 0000000..d08d904 --- /dev/null +++ b/interface/src/components/FullScreenLoading.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import { Typography, Theme } from '@material-ui/core'; +import { makeStyles, createStyles } from '@material-ui/styles'; + +const useStyles = makeStyles((theme: Theme) => createStyles({ + fullScreenLoading: { + padding: theme.spacing(2), + display: "flex", + alignItems: "center", + justifyContent: "center", + height: "100vh", + flexDirection: "column" + }, + progress: { + margin: theme.spacing(4), + } +})); + +const FullScreenLoading = () => { + const classes = useStyles(); + return ( +
+ + + Loading… + +
+ ) +} + +export default FullScreenLoading; diff --git a/interface/src/components/HighlightAvatar.tsx b/interface/src/components/HighlightAvatar.tsx new file mode 100644 index 0000000..f7ce8c7 --- /dev/null +++ b/interface/src/components/HighlightAvatar.tsx @@ -0,0 +1,23 @@ +import { Avatar, makeStyles } from "@material-ui/core"; +import React, { FC } from "react"; + +interface HighlightAvatarProps { + color: string; +} + +const useStyles = makeStyles({ + root: (props: HighlightAvatarProps) => ({ + backgroundColor: props.color + }) +}); + +const HighlightAvatar: FC = (props) => { + const classes = useStyles(props); + return ( + + {props.children} + + ); +} + +export default HighlightAvatar; diff --git a/interface/src/components/MenuAppBar.tsx b/interface/src/components/MenuAppBar.tsx new file mode 100644 index 0000000..dfe5f22 --- /dev/null +++ b/interface/src/components/MenuAppBar.tsx @@ -0,0 +1,286 @@ +import React, { RefObject, Fragment } from 'react'; +import { Link, withRouter, RouteComponentProps } from 'react-router-dom'; + +import { Drawer, AppBar, Toolbar, Avatar, Divider, Button, Box, IconButton } from '@material-ui/core'; +import { ClickAwayListener, Popper, Hidden, Typography } from '@material-ui/core'; +import { List, ListItem, ListItemIcon, ListItemText, ListItemAvatar } from '@material-ui/core'; +import { Card, CardContent, CardActions } from '@material-ui/core'; + +import { withStyles, createStyles, Theme, WithTheme, WithStyles, withTheme } from '@material-ui/core/styles'; + +import WifiIcon from '@material-ui/icons/Wifi'; +import SettingsIcon from '@material-ui/icons/Settings'; +import AccessTimeIcon from '@material-ui/icons/AccessTime'; +import AccountCircleIcon from '@material-ui/icons/AccountCircle'; +import SettingsInputAntennaIcon from '@material-ui/icons/SettingsInputAntenna'; +import DeviceHubIcon from '@material-ui/icons/DeviceHub'; +import LockIcon from '@material-ui/icons/Lock'; +import MenuIcon from '@material-ui/icons/Menu'; + +import ProjectMenu from '../project/ProjectMenu'; +import { PROJECT_NAME } from '../api'; +import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication'; +import { withFeatures, WithFeaturesProps } from '../features/FeaturesContext'; + +const drawerWidth = 290; + +const styles = (theme: Theme) => createStyles({ + root: { + display: 'flex', + }, + drawer: { + [theme.breakpoints.up('md')]: { + width: drawerWidth, + flexShrink: 0, + }, + }, + title: { + flexGrow: 1 + }, + appBar: { + marginLeft: drawerWidth, + [theme.breakpoints.up('md')]: { + width: `calc(100% - ${drawerWidth}px)`, + }, + }, + toolbarImage: { + [theme.breakpoints.up('xs')]: { + height: 24, + marginRight: theme.spacing(2) + }, + [theme.breakpoints.up('sm')]: { + height: 36, + marginRight: theme.spacing(3) + }, + }, + menuButton: { + marginRight: theme.spacing(2), + [theme.breakpoints.up('md')]: { + display: 'none', + }, + }, + toolbar: theme.mixins.toolbar, + drawerPaper: { + width: drawerWidth, + }, + content: { + flexGrow: 1 + }, + authMenu: { + zIndex: theme.zIndex.tooltip, + maxWidth: 400, + }, + authMenuActions: { + padding: theme.spacing(2), + "& > * + *": { + marginLeft: theme.spacing(2), + } + }, +}); + +interface MenuAppBarState { + mobileOpen: boolean; + authMenuOpen: boolean; +} + +interface MenuAppBarProps extends WithFeaturesProps, AuthenticatedContextProps, WithTheme, WithStyles, RouteComponentProps { + sectionTitle: string; +} + +class MenuAppBar extends React.Component { + + constructor(props: MenuAppBarProps) { + super(props); + this.state = { + mobileOpen: false, + authMenuOpen: false + }; + } + + anchorRef: RefObject = React.createRef(); + + handleToggle = () => { + this.setState({ authMenuOpen: !this.state.authMenuOpen }); + } + + handleClose = (event: React.MouseEvent) => { + if (this.anchorRef.current && this.anchorRef.current.contains(event.currentTarget)) { + return; + } + this.setState({ authMenuOpen: false }); + } + + handleDrawerToggle = () => { + this.setState({ mobileOpen: !this.state.mobileOpen }); + }; + + render() { + const { classes, theme, children, sectionTitle, authenticatedContext, features } = this.props; + const { mobileOpen, authMenuOpen } = this.state; + const path = this.props.match.url; + const drawer = ( +
+ + + {PROJECT_NAME} + + + {PROJECT_NAME} + + + + {features.project && ( + + + + + )} + + + + + + + + + + + + + + {features.ntp && ( + + + + + + + )} + {features.mqtt && ( + + + + + + + )} + {features.security && ( + + + + + + + )} + + + + + + + +
+ ); + + const userMenu = ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); + + return ( +
+ + + + + + + {sectionTitle} + + {features.security && userMenu} + + + +
+
+ {children} +
+
+ ); + } +} + +export default withRouter( + withTheme( + withFeatures( + withAuthenticatedContext( + withStyles(styles)(MenuAppBar) + ) + ) + ) +); diff --git a/interface/src/components/PasswordValidator.tsx b/interface/src/components/PasswordValidator.tsx new file mode 100644 index 0000000..8ee0276 --- /dev/null +++ b/interface/src/components/PasswordValidator.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { TextValidator, ValidatorComponentProps } from 'react-material-ui-form-validator'; + +import { withStyles, WithStyles, createStyles } from '@material-ui/core/styles'; +import { InputAdornment, IconButton } from '@material-ui/core'; +import {Visibility,VisibilityOff } from '@material-ui/icons'; + +const styles = createStyles({ + input: { + "&::-ms-reveal": { + display: "none" + } + } +}); + +type PasswordValidatorProps = WithStyles & Exclude; + +interface PasswordValidatorState { + showPassword: boolean; +} + +class PasswordValidator extends React.Component { + + state = { + showPassword: false + }; + + toggleShowPassword = () => { + this.setState({ + showPassword: !this.state.showPassword + }); + } + + render() { + const { classes, ...rest } = this.props; + return ( + + + {this.state.showPassword ? : } + + + }} + /> + ); + } + +} + +export default withStyles(styles)(PasswordValidator); diff --git a/interface/src/components/RestController.tsx b/interface/src/components/RestController.tsx new file mode 100644 index 0000000..c9751c6 --- /dev/null +++ b/interface/src/components/RestController.tsx @@ -0,0 +1,113 @@ +import React from 'react'; +import { withSnackbar, WithSnackbarProps } from 'notistack'; + +import { redirectingAuthorizedFetch } from '../authentication'; + +export interface RestControllerProps extends WithSnackbarProps { + handleValueChange: (name: keyof D) => (event: React.ChangeEvent) => void; + + setData: (data: D, callback?: () => void) => void; + saveData: () => void; + loadData: () => void; + + data?: D; + loading: boolean; + errorMessage?: string; +} + +export const extractEventValue = (event: React.ChangeEvent) => { + switch (event.target.type) { + case "number": + return event.target.valueAsNumber; + case "checkbox": + return event.target.checked; + default: + return event.target.value + } +} + +interface RestControllerState { + data?: D; + loading: boolean; + errorMessage?: string; +} + +export function restController>(endpointUrl: string, RestController: React.ComponentType

>) { + return withSnackbar( + class extends React.Component> & WithSnackbarProps, RestControllerState> { + + state: RestControllerState = { + data: undefined, + loading: false, + errorMessage: undefined + }; + + setData = (data: D, callback?: () => void) => { + this.setState({ + data, + loading: false, + errorMessage: undefined + }, callback); + } + + loadData = () => { + this.setState({ + data: undefined, + loading: true, + errorMessage: undefined + }); + redirectingAuthorizedFetch(endpointUrl).then(response => { + if (response.status === 200) { + return response.json(); + } + throw Error("Invalid status code: " + response.status); + }).then(json => { + this.setState({ data: json, loading: false }) + }).catch(error => { + const errorMessage = error.message || "Unknown error"; + this.props.enqueueSnackbar("Problem fetching: " + errorMessage, { variant: 'error' }); + this.setState({ data: undefined, loading: false, errorMessage }); + }); + } + + saveData = () => { + this.setState({ loading: true }); + redirectingAuthorizedFetch(endpointUrl, { + method: 'POST', + body: JSON.stringify(this.state.data), + headers: { + 'Content-Type': 'application/json' + } + }).then(response => { + if (response.status === 200) { + return response.json(); + } + throw Error("Invalid status code: " + response.status); + }).then(json => { + this.props.enqueueSnackbar("Update successful.", { variant: 'success' }); + this.setState({ data: json, loading: false }); + }).catch(error => { + const errorMessage = error.message || "Unknown error"; + this.props.enqueueSnackbar("Problem updating: " + errorMessage, { variant: 'error' }); + this.setState({ data: undefined, loading: false, errorMessage }); + }); + } + + handleValueChange = (name: keyof D) => (event: React.ChangeEvent) => { + const data = { ...this.state.data!, [name]: extractEventValue(event) }; + this.setState({ data }); + } + + render() { + return ; + } + + }); +} diff --git a/interface/src/components/RestFormLoader.tsx b/interface/src/components/RestFormLoader.tsx new file mode 100644 index 0000000..29fb304 --- /dev/null +++ b/interface/src/components/RestFormLoader.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; +import { Button, LinearProgress, Typography } from '@material-ui/core'; + +import { RestControllerProps } from '.'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + loadingSettings: { + margin: theme.spacing(0.5), + }, + loadingSettingsDetails: { + margin: theme.spacing(4), + textAlign: "center" + }, + button: { + marginRight: theme.spacing(2), + marginTop: theme.spacing(2), + } + }) +); + +export type RestFormProps = Omit, "loading" | "errorMessage"> & { data: D }; + +interface RestFormLoaderProps extends RestControllerProps { + render: (props: RestFormProps) => JSX.Element; +} + +export default function RestFormLoader(props: RestFormLoaderProps) { + const { loading, errorMessage, loadData, render, data, ...rest } = props; + const classes = useStyles(); + if (loading || !data) { + return ( +

+ + + Loading… + +
+ ); + } + if (errorMessage) { + return ( +
+ + {errorMessage} + + +
+ ); + } + return render({ ...rest, loadData, data }); +} diff --git a/interface/src/components/SectionContent.tsx b/interface/src/components/SectionContent.tsx new file mode 100644 index 0000000..457014f --- /dev/null +++ b/interface/src/components/SectionContent.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import { Typography, Paper } from '@material-ui/core'; +import { createStyles, Theme, makeStyles } from '@material-ui/core/styles'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + content: { + padding: theme.spacing(2), + margin: theme.spacing(3), + } + }) +); + +interface SectionContentProps { + title: string; + titleGutter?: boolean; +} + +const SectionContent: React.FC = (props) => { + const { children, title, titleGutter } = props; + const classes = useStyles(); + return ( + + + {title} + + {children} + + ); +}; + +export default SectionContent; diff --git a/interface/src/components/SingleUpload.tsx b/interface/src/components/SingleUpload.tsx new file mode 100644 index 0000000..003c286 --- /dev/null +++ b/interface/src/components/SingleUpload.tsx @@ -0,0 +1,96 @@ +import React, { FC, Fragment } from 'react'; +import { useDropzone, DropzoneState } from 'react-dropzone'; + +import { makeStyles, createStyles } from '@material-ui/styles'; +import CloudUploadIcon from '@material-ui/icons/CloudUpload'; +import CancelIcon from '@material-ui/icons/Cancel'; +import { Theme, Box, Typography, LinearProgress, Button } from '@material-ui/core'; + +interface SingleUploadStyleProps extends DropzoneState { + uploading: boolean; +} + +const progressPercentage = (progress: ProgressEvent) => Math.round((progress.loaded * 100) / progress.total); + +const getBorderColor = (theme: Theme, props: SingleUploadStyleProps) => { + if (props.isDragAccept) { + return theme.palette.success.main; + } + if (props.isDragReject) { + return theme.palette.error.main; + } + if (props.isDragActive) { + return theme.palette.info.main; + } + return theme.palette.grey[700]; +} + +const useStyles = makeStyles((theme: Theme) => createStyles({ + dropzone: { + padding: theme.spacing(8, 2), + borderWidth: 2, + borderRadius: 2, + borderStyle: 'dashed', + color: theme.palette.grey[700], + transition: 'border .24s ease-in-out', + cursor: (props: SingleUploadStyleProps) => props.uploading ? 'default' : 'pointer', + width: '100%', + borderColor: (props: SingleUploadStyleProps) => getBorderColor(theme, props) + } +})); + +export interface SingleUploadProps { + onDrop: (acceptedFiles: File[]) => void; + onCancel: () => void; + accept?: string | string[]; + uploading: boolean; + progress?: ProgressEvent; +} + +const SingleUpload: FC = ({ onDrop, onCancel, accept, uploading, progress }) => { + const dropzoneState = useDropzone({ onDrop, accept, disabled: uploading, multiple: false }); + const { getRootProps, getInputProps } = dropzoneState; + const classes = useStyles({ ...dropzoneState, uploading }); + + + const renderProgressText = () => { + if (uploading) { + if (progress?.lengthComputable) { + return `Uploading: ${progressPercentage(progress)}%`; + } + return "Uploading\u2026"; + } + return "Drop file or click here"; + } + + const renderProgress = (progress?: ProgressEvent) => ( + + ); + + return ( +
+ + + + + {renderProgressText()} + + {uploading && ( + + + {renderProgress(progress)} + + + + )} + +
+ ); +} + +export default SingleUpload; diff --git a/interface/src/components/WebSocketController.tsx b/interface/src/components/WebSocketController.tsx new file mode 100644 index 0000000..5fe9fa3 --- /dev/null +++ b/interface/src/components/WebSocketController.tsx @@ -0,0 +1,133 @@ +import React from 'react'; +import Sockette from 'sockette'; +import throttle from 'lodash/throttle'; +import { withSnackbar, WithSnackbarProps } from 'notistack'; + +import { addAccessTokenParameter } from '../authentication'; +import { extractEventValue } from '.'; + +export interface WebSocketControllerProps extends WithSnackbarProps { + handleValueChange: (name: keyof D) => (event: React.ChangeEvent) => void; + + setData: (data: D, callback?: () => void) => void; + saveData: () => void; + saveDataAndClear(): () => void; + + connected: boolean; + data?: D; +} + +interface WebSocketControllerState { + ws: Sockette; + connected: boolean; + clientId?: string; + data?: D; +} + +enum WebSocketMessageType { + ID = "id", + PAYLOAD = "payload" +} + +interface WebSocketIdMessage { + type: typeof WebSocketMessageType.ID; + id: string; +} + +interface WebSocketPayloadMessage { + type: typeof WebSocketMessageType.PAYLOAD; + origin_id: string; + payload: D; +} + +export type WebSocketMessage = WebSocketIdMessage | WebSocketPayloadMessage; + +export function webSocketController>(wsUrl: string, wsThrottle: number, WebSocketController: React.ComponentType

>) { + return withSnackbar( + class extends React.Component> & WithSnackbarProps, WebSocketControllerState> { + constructor(props: Omit> & WithSnackbarProps) { + super(props); + this.state = { + ws: new Sockette(addAccessTokenParameter(wsUrl), { + onmessage: this.onMessage, + onopen: this.onOpen, + onclose: this.onClose, + }), + connected: false + } + } + + componentWillUnmount() { + this.state.ws.close(); + } + + onMessage = (event: MessageEvent) => { + const rawData = event.data; + if (typeof rawData === 'string' || rawData instanceof String) { + this.handleMessage(JSON.parse(rawData as string) as WebSocketMessage); + } + } + + handleMessage = (message: WebSocketMessage) => { + switch (message.type) { + case WebSocketMessageType.ID: + this.setState({ clientId: message.id }); + break; + case WebSocketMessageType.PAYLOAD: + const { clientId, data } = this.state; + if (clientId && (!data || clientId !== message.origin_id)) { + this.setState( + { data: message.payload } + ); + } + break; + } + } + + onOpen = () => { + this.setState({ connected: true }); + } + + onClose = () => { + this.setState({ connected: false, clientId: undefined, data: undefined }); + } + + setData = (data: D, callback?: () => void) => { + this.setState({ data }, callback); + } + + saveData = throttle(() => { + const { ws, connected, data } = this.state; + if (connected) { + ws.json(data); + } + }, wsThrottle); + + saveDataAndClear = throttle(() => { + const { ws, connected, data } = this.state; + if (connected) { + this.setState({ + data: undefined + }, () => ws.json(data)); + } + }, wsThrottle); + + handleValueChange = (name: keyof D) => (event: React.ChangeEvent) => { + const data = { ...this.state.data!, [name]: extractEventValue(event) }; + this.setState({ data }); + } + + render() { + return ; + } + + }); +} diff --git a/interface/src/components/WebSocketFormLoader.tsx b/interface/src/components/WebSocketFormLoader.tsx new file mode 100644 index 0000000..ee5f335 --- /dev/null +++ b/interface/src/components/WebSocketFormLoader.tsx @@ -0,0 +1,40 @@ +import React from 'react'; + +import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; +import { LinearProgress, Typography } from '@material-ui/core'; + +import { WebSocketControllerProps } from '.'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + loadingSettings: { + margin: theme.spacing(0.5), + }, + loadingSettingsDetails: { + margin: theme.spacing(4), + textAlign: "center" + } + }) +); + +export type WebSocketFormProps = Omit, "connected"> & { data: D }; + +interface WebSocketFormLoaderProps extends WebSocketControllerProps { + render: (props: WebSocketFormProps) => JSX.Element; +} + +export default function WebSocketFormLoader(props: WebSocketFormLoaderProps) { + const { connected, render, data, ...rest } = props; + const classes = useStyles(); + if (!connected || !data) { + return ( +

+ + + Connecting to WebSocket... + +
+ ); + } + return render({ ...rest, data }); +} diff --git a/interface/src/components/index.ts b/interface/src/components/index.ts new file mode 100644 index 0000000..4a6cc6a --- /dev/null +++ b/interface/src/components/index.ts @@ -0,0 +1,17 @@ +export { default as BlockFormControlLabel } from './BlockFormControlLabel'; +export { default as FormActions } from './FormActions'; +export { default as FormButton } from './FormButton'; +export { default as HighlightAvatar } from './HighlightAvatar'; +export { default as MenuAppBar } from './MenuAppBar'; +export { default as PasswordValidator } from './PasswordValidator'; +export { default as RestFormLoader } from './RestFormLoader'; +export { default as SectionContent } from './SectionContent'; +export { default as WebSocketFormLoader } from './WebSocketFormLoader'; +export { default as ErrorButton } from './ErrorButton'; +export { default as SingleUpload } from './SingleUpload'; + +export * from './RestFormLoader'; +export * from './RestController'; + +export * from './WebSocketFormLoader'; +export * from './WebSocketController'; diff --git a/interface/src/features/ApplicationContext.tsx b/interface/src/features/ApplicationContext.tsx new file mode 100644 index 0000000..fbc15f2 --- /dev/null +++ b/interface/src/features/ApplicationContext.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Features } from './types'; + +export interface ApplicationContext { + features: Features; +} + +const ApplicationContextDefaultValue = {} as ApplicationContext +export const ApplicationContext = React.createContext( + ApplicationContextDefaultValue +); + +export function withAuthenticatedContexApplicationContext(Component: React.ComponentType) { + return class extends React.Component> { + render() { + return ( + + {authenticatedContext => } + + ); + } + }; +} diff --git a/interface/src/features/FeaturesContext.tsx b/interface/src/features/FeaturesContext.tsx new file mode 100644 index 0000000..8c8f104 --- /dev/null +++ b/interface/src/features/FeaturesContext.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Features } from './types'; + +export interface FeaturesContext { + features: Features; +} + +const FeaturesContextDefaultValue = {} as FeaturesContext +export const FeaturesContext = React.createContext( + FeaturesContextDefaultValue +); + +export interface WithFeaturesProps { + features: Features; +} + +export function withFeatures(Component: React.ComponentType) { + return class extends React.Component> { + render() { + return ( + + {featuresContext => } + + ); + } + }; +} diff --git a/interface/src/features/FeaturesWrapper.tsx b/interface/src/features/FeaturesWrapper.tsx new file mode 100644 index 0000000..aac3533 --- /dev/null +++ b/interface/src/features/FeaturesWrapper.tsx @@ -0,0 +1,61 @@ +import React, { Component } from 'react'; + +import { Features } from './types'; +import { FeaturesContext } from './FeaturesContext'; +import FullScreenLoading from '../components/FullScreenLoading'; +import ApplicationError from '../components/ApplicationError'; +import { FEATURES_ENDPOINT } from '../api'; + +interface FeaturesWrapperState { + features?: Features; + error?: string; +}; + +class FeaturesWrapper extends Component<{}, FeaturesWrapperState> { + + state: FeaturesWrapperState = {}; + + componentDidMount() { + this.fetchFeaturesDetails(); + } + + fetchFeaturesDetails = () => { + fetch(FEATURES_ENDPOINT) + .then(response => { + if (response.status === 200) { + return response.json(); + } else { + throw Error("Unexpected status code: " + response.status); + } + }).then(features => { + this.setState({ features }); + }) + .catch(error => { + this.setState({ error: error.message }); + }); + } + + render() { + const { features, error } = this.state; + if (features) { + return ( + + {this.props.children} + + ); + } + if (error) { + return ( + + ); + } + return ( + + ); + } + +} + +export default FeaturesWrapper; diff --git a/interface/src/features/types.ts b/interface/src/features/types.ts new file mode 100644 index 0000000..1753d9a --- /dev/null +++ b/interface/src/features/types.ts @@ -0,0 +1,8 @@ +export interface Features { + project: boolean; + security: boolean; + mqtt: boolean; + ntp: boolean; + ota: boolean; + upload_firmware: boolean; +} diff --git a/interface/src/history.ts b/interface/src/history.ts new file mode 100644 index 0000000..eb70d7b --- /dev/null +++ b/interface/src/history.ts @@ -0,0 +1,5 @@ +import { createBrowserHistory } from 'history'; + +export default createBrowserHistory({ + /* pass a configuration object here if needed */ +}) diff --git a/interface/src/index.tsx b/interface/src/index.tsx new file mode 100644 index 0000000..a0801fc --- /dev/null +++ b/interface/src/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { render } from 'react-dom'; + +import history from './history'; +import { Router } from 'react-router'; + +import App from './App'; + +render(( + + + +), document.getElementById("root")) diff --git a/interface/src/mqtt/Mqtt.tsx b/interface/src/mqtt/Mqtt.tsx new file mode 100644 index 0000000..8daca77 --- /dev/null +++ b/interface/src/mqtt/Mqtt.tsx @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; +import { Redirect, Switch, RouteComponentProps } from 'react-router-dom' + +import { Tabs, Tab } from '@material-ui/core'; + +import { AuthenticatedContextProps, withAuthenticatedContext, AuthenticatedRoute } from '../authentication'; +import { MenuAppBar } from '../components'; +import MqttStatusController from './MqttStatusController'; +import MqttSettingsController from './MqttSettingsController'; + +type MqttProps = AuthenticatedContextProps & RouteComponentProps; + +class Mqtt extends Component { + + handleTabChange = (event: React.ChangeEvent<{}>, path: string) => { + this.props.history.push(path); + }; + + render() { + const { authenticatedContext } = this.props; + return ( + + + + + + + + + + + + ) + } +} + +export default withAuthenticatedContext(Mqtt); diff --git a/interface/src/mqtt/MqttSettingsController.tsx b/interface/src/mqtt/MqttSettingsController.tsx new file mode 100644 index 0000000..8cc9d16 --- /dev/null +++ b/interface/src/mqtt/MqttSettingsController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { MQTT_SETTINGS_ENDPOINT } from '../api'; + +import MqttSettingsForm from './MqttSettingsForm'; +import { MqttSettings } from './types'; + +type MqttSettingsControllerProps = RestControllerProps; + +class MqttSettingsController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ) + } + +} + +export default restController(MQTT_SETTINGS_ENDPOINT, MqttSettingsController); diff --git a/interface/src/mqtt/MqttSettingsForm.tsx b/interface/src/mqtt/MqttSettingsForm.tsx new file mode 100644 index 0000000..fb9c77e --- /dev/null +++ b/interface/src/mqtt/MqttSettingsForm.tsx @@ -0,0 +1,128 @@ +import React from 'react'; +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; + +import { Checkbox, TextField } from '@material-ui/core'; +import SaveIcon from '@material-ui/icons/Save'; + +import { RestFormProps, FormActions, FormButton, BlockFormControlLabel, PasswordValidator } from '../components'; +import { isIP, isHostname, or } from '../validators'; + +import { MqttSettings } from './types'; + +type MqttSettingsFormProps = RestFormProps; + +class MqttSettingsForm extends React.Component { + + componentDidMount() { + ValidatorForm.addValidationRule('isIPOrHostname', or(isIP, isHostname)); + } + + render() { + const { data, handleValueChange, saveData } = this.props; + return ( + + + } + label="Enable MQTT?" + /> + + + + + + + + } + label="Clean Session?" + /> + + + } variant="contained" color="primary" type="submit"> + Save + + + + ); + } +} + +export default MqttSettingsForm; diff --git a/interface/src/mqtt/MqttStatus.ts b/interface/src/mqtt/MqttStatus.ts new file mode 100644 index 0000000..b9bb80c --- /dev/null +++ b/interface/src/mqtt/MqttStatus.ts @@ -0,0 +1,45 @@ +import { Theme } from "@material-ui/core"; +import { MqttStatus, MqttDisconnectReason } from "./types"; + +export const mqttStatusHighlight = ({ enabled, connected }: MqttStatus, theme: Theme) => { + if (!enabled) { + return theme.palette.info.main; + } + if (connected) { + return theme.palette.success.main; + } + return theme.palette.error.main; +} + +export const mqttStatus = ({ enabled, connected }: MqttStatus) => { + if (!enabled) { + return "Not enabled"; + } + if (connected) { + return "Connected"; + } + return "Disconnected"; +} + +export const disconnectReason = ({ disconnect_reason }: MqttStatus) => { + switch (disconnect_reason) { + case MqttDisconnectReason.TCP_DISCONNECTED: + return "TCP disconnected"; + case MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION: + return "Unacceptable protocol version"; + case MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED: + return "Client ID rejected"; + case MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE: + return "Server unavailable"; + case MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS: + return "Malformed credentials"; + case MqttDisconnectReason.MQTT_NOT_AUTHORIZED: + return "Not authorized"; + case MqttDisconnectReason.ESP8266_NOT_ENOUGH_SPACE: + return "Device out of memory"; + case MqttDisconnectReason.TLS_BAD_FINGERPRINT: + return "Server fingerprint invalid"; + default: + return "Unknown" + } +} diff --git a/interface/src/mqtt/MqttStatusController.tsx b/interface/src/mqtt/MqttStatusController.tsx new file mode 100644 index 0000000..4dd5409 --- /dev/null +++ b/interface/src/mqtt/MqttStatusController.tsx @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { MQTT_STATUS_ENDPOINT } from '../api'; + +import MqttStatusForm from './MqttStatusForm'; +import { MqttStatus } from './types'; + +type MqttStatusControllerProps = RestControllerProps; + +class MqttStatusController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ) + } +} + +export default restController(MQTT_STATUS_ENDPOINT, MqttStatusController); diff --git a/interface/src/mqtt/MqttStatusForm.tsx b/interface/src/mqtt/MqttStatusForm.tsx new file mode 100644 index 0000000..5a80a41 --- /dev/null +++ b/interface/src/mqtt/MqttStatusForm.tsx @@ -0,0 +1,83 @@ +import React, { Component, Fragment } from 'react'; + +import { WithTheme, withTheme } from '@material-ui/core/styles'; +import { Avatar, Divider, List, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'; + +import DeviceHubIcon from '@material-ui/icons/DeviceHub'; +import RefreshIcon from '@material-ui/icons/Refresh'; +import ReportIcon from '@material-ui/icons/Report'; + +import { RestFormProps, FormActions, FormButton, HighlightAvatar } from '../components'; +import { mqttStatusHighlight, mqttStatus, disconnectReason } from './MqttStatus'; +import { MqttStatus } from './types'; + +type MqttStatusFormProps = RestFormProps & WithTheme; + +class MqttStatusForm extends Component { + + renderConnectionStatus() { + const { data } = this.props + if (data.connected) { + return ( + + + + # + + + + + + ); + } + return ( + + + + + + + + + + + + ); + } + + createListItems() { + const { data, theme } = this.props + return ( + + + + + + + + + + + {data.enabled && this.renderConnectionStatus()} + + ); + } + + render() { + return ( + + + {this.createListItems()} + + + } variant="contained" color="secondary" onClick={this.props.loadData}> + Refresh + + + + ); + } + +} + +export default withTheme(MqttStatusForm); diff --git a/interface/src/mqtt/types.ts b/interface/src/mqtt/types.ts new file mode 100644 index 0000000..04e20ca --- /dev/null +++ b/interface/src/mqtt/types.ts @@ -0,0 +1,29 @@ +export enum MqttDisconnectReason { + TCP_DISCONNECTED = 0, + MQTT_UNACCEPTABLE_PROTOCOL_VERSION = 1, + MQTT_IDENTIFIER_REJECTED = 2, + MQTT_SERVER_UNAVAILABLE = 3, + MQTT_MALFORMED_CREDENTIALS = 4, + MQTT_NOT_AUTHORIZED = 5, + ESP8266_NOT_ENOUGH_SPACE = 6, + TLS_BAD_FINGERPRINT = 7 +} + +export interface MqttStatus { + enabled: boolean; + connected: boolean; + client_id: string; + disconnect_reason: MqttDisconnectReason; +} + +export interface MqttSettings { + enabled: boolean; + host: string; + port: number; + username: string; + password: string; + client_id: string; + keep_alive: number; + clean_session: boolean; + max_topic_length: number; +} diff --git a/interface/src/ntp/NTPSettingsController.tsx b/interface/src/ntp/NTPSettingsController.tsx new file mode 100644 index 0000000..78f5f63 --- /dev/null +++ b/interface/src/ntp/NTPSettingsController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { NTP_SETTINGS_ENDPOINT } from '../api'; + +import NTPSettingsForm from './NTPSettingsForm'; +import { NTPSettings } from './types'; + +type NTPSettingsControllerProps = RestControllerProps; + +class NTPSettingsController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ) + } + +} + +export default restController(NTP_SETTINGS_ENDPOINT, NTPSettingsController); diff --git a/interface/src/ntp/NTPSettingsForm.tsx b/interface/src/ntp/NTPSettingsForm.tsx new file mode 100644 index 0000000..c3e4dab --- /dev/null +++ b/interface/src/ntp/NTPSettingsForm.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { TextValidator, ValidatorForm, SelectValidator } from 'react-material-ui-form-validator'; + +import { Checkbox, MenuItem } from '@material-ui/core'; +import SaveIcon from '@material-ui/icons/Save'; + +import { RestFormProps, FormActions, FormButton, BlockFormControlLabel } from '../components'; +import { isIP, isHostname, or } from '../validators'; + +import { TIME_ZONES, timeZoneSelectItems, selectedTimeZone } from './TZ'; +import { NTPSettings } from './types'; + +type NTPSettingsFormProps = RestFormProps; + +class NTPSettingsForm extends React.Component { + + componentDidMount() { + ValidatorForm.addValidationRule('isIPOrHostname', or(isIP, isHostname)); + } + + changeTimeZone = (event: React.ChangeEvent) => { + const { data, setData } = this.props; + setData({ + ...data, + tz_label: event.target.value, + tz_format: TIME_ZONES[event.target.value] + }); + } + + render() { + const { data, handleValueChange, saveData } = this.props; + return ( + + + } + label="Enable NTP?" + /> + + + Time zone... + {timeZoneSelectItems()} + + + } variant="contained" color="primary" type="submit"> + Save + + + + ); + } +} + +export default NTPSettingsForm; diff --git a/interface/src/ntp/NTPStatus.ts b/interface/src/ntp/NTPStatus.ts new file mode 100644 index 0000000..744b56d --- /dev/null +++ b/interface/src/ntp/NTPStatus.ts @@ -0,0 +1,26 @@ +import { Theme } from "@material-ui/core"; +import { NTPStatus, NTPSyncStatus } from "./types"; + +export const isNtpActive = ({ status }: NTPStatus) => status === NTPSyncStatus.NTP_ACTIVE; + +export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => { + switch (status) { + case NTPSyncStatus.NTP_INACTIVE: + return theme.palette.info.main; + case NTPSyncStatus.NTP_ACTIVE: + return theme.palette.success.main; + default: + return theme.palette.error.main; + } +} + +export const ntpStatus = ({ status }: NTPStatus) => { + switch (status) { + case NTPSyncStatus.NTP_INACTIVE: + return "Inactive"; + case NTPSyncStatus.NTP_ACTIVE: + return "Active"; + default: + return "Unknown"; + } +} diff --git a/interface/src/ntp/NTPStatusController.tsx b/interface/src/ntp/NTPStatusController.tsx new file mode 100644 index 0000000..25ea4de --- /dev/null +++ b/interface/src/ntp/NTPStatusController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { NTP_STATUS_ENDPOINT } from '../api'; + +import NTPStatusForm from './NTPStatusForm'; +import { NTPStatus } from './types'; + +type NTPStatusControllerProps = RestControllerProps; + +class NTPStatusController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ); + } + +} + +export default restController(NTP_STATUS_ENDPOINT, NTPStatusController); diff --git a/interface/src/ntp/NTPStatusForm.tsx b/interface/src/ntp/NTPStatusForm.tsx new file mode 100644 index 0000000..6b277dd --- /dev/null +++ b/interface/src/ntp/NTPStatusForm.tsx @@ -0,0 +1,198 @@ +import React, { Component, Fragment } from 'react'; +import moment from 'moment'; + +import { WithTheme, withTheme } from '@material-ui/core/styles'; +import { Avatar, Divider, List, ListItem, ListItemAvatar, ListItemText, Button } from '@material-ui/core'; +import { Dialog, DialogTitle, DialogContent, DialogActions, Box, TextField } from '@material-ui/core'; + +import SwapVerticalCircleIcon from '@material-ui/icons/SwapVerticalCircle'; +import AccessTimeIcon from '@material-ui/icons/AccessTime'; +import DNSIcon from '@material-ui/icons/Dns'; +import UpdateIcon from '@material-ui/icons/Update'; +import AvTimerIcon from '@material-ui/icons/AvTimer'; +import RefreshIcon from '@material-ui/icons/Refresh'; + +import { RestFormProps, FormButton, HighlightAvatar } from '../components'; +import { isNtpActive, ntpStatusHighlight, ntpStatus } from './NTPStatus'; +import { formatIsoDateTime, formatLocalDateTime } from './TimeFormat'; +import { NTPStatus, Time } from './types'; +import { redirectingAuthorizedFetch, withAuthenticatedContext, AuthenticatedContextProps } from '../authentication'; +import { TIME_ENDPOINT } from '../api'; + +type NTPStatusFormProps = RestFormProps & WithTheme & AuthenticatedContextProps; + +interface NTPStatusFormState { + settingTime: boolean; + localTime: string; + processing: boolean; +} + +class NTPStatusForm extends Component { + + constructor(props: NTPStatusFormProps) { + super(props); + this.state = { + settingTime: false, + localTime: '', + processing: false + }; + } + + updateLocalTime = (event: React.ChangeEvent) => { + this.setState({ localTime: event.target.value }); + } + + openSetTime = () => { + this.setState({ localTime: formatLocalDateTime(moment()), settingTime: true, }); + } + + closeSetTime = () => { + this.setState({ settingTime: false }); + } + + createAdjustedTime = (): Time => { + const currentLocalTime = moment(this.props.data.time_local); + const newLocalTime = moment(this.state.localTime); + newLocalTime.subtract(currentLocalTime.utcOffset()) + newLocalTime.milliseconds(0); + newLocalTime.utc(); + return { + time_utc: newLocalTime.format() + } + } + + configureTime = () => { + this.setState({ processing: true }); + redirectingAuthorizedFetch(TIME_ENDPOINT, + { + method: 'POST', + body: JSON.stringify(this.createAdjustedTime()), + headers: { + 'Content-Type': 'application/json' + } + }) + .then(response => { + if (response.status === 200) { + this.props.enqueueSnackbar("Time set successfully", { variant: 'success' }); + this.setState({ processing: false, settingTime: false }, this.props.loadData); + } else { + throw Error("Error setting time, status code: " + response.status); + } + }) + .catch(error => { + this.props.enqueueSnackbar(error.message || "Problem setting the time", { variant: 'error' }); + this.setState({ processing: false, settingTime: false }); + }); + } + + renderSetTimeDialog() { + return ( + + Set Time + + Enter local date and time below to set the device's time. + + + + + + + + ) + } + + render() { + const { data, theme } = this.props + const me = this.props.authenticatedContext.me; + return ( + + + + + + + + + + + + {isNtpActive(data) && ( + + + + + + + + + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } variant="contained" color="secondary" onClick={this.props.loadData}> + Refresh + + + {me.admin && !isNtpActive(data) && ( + + + + )} + + {this.renderSetTimeDialog()} + + ); + } +} + +export default withAuthenticatedContext(withTheme(NTPStatusForm)); diff --git a/interface/src/ntp/NetworkTime.tsx b/interface/src/ntp/NetworkTime.tsx new file mode 100644 index 0000000..ebefb6e --- /dev/null +++ b/interface/src/ntp/NetworkTime.tsx @@ -0,0 +1,39 @@ +import React, { Component } from 'react'; +import { Redirect, Switch, RouteComponentProps } from 'react-router-dom' + +import { Tabs, Tab } from '@material-ui/core'; + +import { withAuthenticatedContext, AuthenticatedContextProps, AuthenticatedRoute } from '../authentication'; +import { MenuAppBar } from '../components'; + +import NTPStatusController from './NTPStatusController'; +import NTPSettingsController from './NTPSettingsController'; + +type NetworkTimeProps = AuthenticatedContextProps & RouteComponentProps; + +class NetworkTime extends Component { + + handleTabChange = (event: React.ChangeEvent<{}>, path: string) => { + this.props.history.push(path); + }; + + render() { + const { authenticatedContext } = this.props; + return ( + + + + + + + + + + + + ) + } + +} + +export default withAuthenticatedContext(NetworkTime) diff --git a/interface/src/ntp/TZ.tsx b/interface/src/ntp/TZ.tsx new file mode 100644 index 0000000..4e56e9d --- /dev/null +++ b/interface/src/ntp/TZ.tsx @@ -0,0 +1,479 @@ +import React from 'react'; +import MenuItem from '@material-ui/core/MenuItem'; + +type TimeZones = { + [name: string]: string +}; + +export const TIME_ZONES: TimeZones = { + "Africa/Abidjan": "GMT0", + "Africa/Accra": "GMT0", + "Africa/Addis_Ababa": "EAT-3", + "Africa/Algiers": "CET-1", + "Africa/Asmara": "EAT-3", + "Africa/Bamako": "GMT0", + "Africa/Bangui": "WAT-1", + "Africa/Banjul": "GMT0", + "Africa/Bissau": "GMT0", + "Africa/Blantyre": "CAT-2", + "Africa/Brazzaville": "WAT-1", + "Africa/Bujumbura": "CAT-2", + "Africa/Cairo": "EET-2", + "Africa/Casablanca": "UNK-1", + "Africa/Ceuta": "CET-1CEST,M3.5.0,M10.5.0/3", + "Africa/Conakry": "GMT0", + "Africa/Dakar": "GMT0", + "Africa/Dar_es_Salaam": "EAT-3", + "Africa/Djibouti": "EAT-3", + "Africa/Douala": "WAT-1", + "Africa/El_Aaiun": "UNK-1", + "Africa/Freetown": "GMT0", + "Africa/Gaborone": "CAT-2", + "Africa/Harare": "CAT-2", + "Africa/Johannesburg": "SAST-2", + "Africa/Juba": "EAT-3", + "Africa/Kampala": "EAT-3", + "Africa/Khartoum": "CAT-2", + "Africa/Kigali": "CAT-2", + "Africa/Kinshasa": "WAT-1", + "Africa/Lagos": "WAT-1", + "Africa/Libreville": "WAT-1", + "Africa/Lome": "GMT0", + "Africa/Luanda": "WAT-1", + "Africa/Lubumbashi": "CAT-2", + "Africa/Lusaka": "CAT-2", + "Africa/Malabo": "WAT-1", + "Africa/Maputo": "CAT-2", + "Africa/Maseru": "SAST-2", + "Africa/Mbabane": "SAST-2", + "Africa/Mogadishu": "EAT-3", + "Africa/Monrovia": "GMT0", + "Africa/Nairobi": "EAT-3", + "Africa/Ndjamena": "WAT-1", + "Africa/Niamey": "WAT-1", + "Africa/Nouakchott": "GMT0", + "Africa/Ouagadougou": "GMT0", + "Africa/Porto-Novo": "WAT-1", + "Africa/Sao_Tome": "GMT0", + "Africa/Tripoli": "EET-2", + "Africa/Tunis": "CET-1", + "Africa/Windhoek": "CAT-2", + "America/Adak": "HST10HDT,M3.2.0,M11.1.0", + "America/Anchorage": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Anguilla": "AST4", + "America/Antigua": "AST4", + "America/Araguaina": "UNK3", + "America/Argentina/Buenos_Aires": "UNK3", + "America/Argentina/Catamarca": "UNK3", + "America/Argentina/Cordoba": "UNK3", + "America/Argentina/Jujuy": "UNK3", + "America/Argentina/La_Rioja": "UNK3", + "America/Argentina/Mendoza": "UNK3", + "America/Argentina/Rio_Gallegos": "UNK3", + "America/Argentina/Salta": "UNK3", + "America/Argentina/San_Juan": "UNK3", + "America/Argentina/San_Luis": "UNK3", + "America/Argentina/Tucuman": "UNK3", + "America/Argentina/Ushuaia": "UNK3", + "America/Aruba": "AST4", + "America/Asuncion": "UNK4UNK,M10.1.0/0,M3.4.0/0", + "America/Atikokan": "EST5", + "America/Bahia": "UNK3", + "America/Bahia_Banderas": "CST6CDT,M4.1.0,M10.5.0", + "America/Barbados": "AST4", + "America/Belem": "UNK3", + "America/Belize": "CST6", + "America/Blanc-Sablon": "AST4", + "America/Boa_Vista": "UNK4", + "America/Bogota": "UNK5", + "America/Boise": "MST7MDT,M3.2.0,M11.1.0", + "America/Cambridge_Bay": "MST7MDT,M3.2.0,M11.1.0", + "America/Campo_Grande": "UNK4", + "America/Cancun": "EST5", + "America/Caracas": "UNK4", + "America/Cayenne": "UNK3", + "America/Cayman": "EST5", + "America/Chicago": "CST6CDT,M3.2.0,M11.1.0", + "America/Chihuahua": "MST7MDT,M4.1.0,M10.5.0", + "America/Costa_Rica": "CST6", + "America/Creston": "MST7", + "America/Cuiaba": "UNK4", + "America/Curacao": "AST4", + "America/Danmarkshavn": "GMT0", + "America/Dawson": "MST7", + "America/Dawson_Creek": "MST7", + "America/Denver": "MST7MDT,M3.2.0,M11.1.0", + "America/Detroit": "EST5EDT,M3.2.0,M11.1.0", + "America/Dominica": "AST4", + "America/Edmonton": "MST7MDT,M3.2.0,M11.1.0", + "America/Eirunepe": "UNK5", + "America/El_Salvador": "CST6", + "America/Fort_Nelson": "MST7", + "America/Fortaleza": "UNK3", + "America/Glace_Bay": "AST4ADT,M3.2.0,M11.1.0", + "America/Godthab": "UNK3UNK,M3.5.0/-2,M10.5.0/-1", + "America/Goose_Bay": "AST4ADT,M3.2.0,M11.1.0", + "America/Grand_Turk": "EST5EDT,M3.2.0,M11.1.0", + "America/Grenada": "AST4", + "America/Guadeloupe": "AST4", + "America/Guatemala": "CST6", + "America/Guayaquil": "UNK5", + "America/Guyana": "UNK4", + "America/Halifax": "AST4ADT,M3.2.0,M11.1.0", + "America/Havana": "CST5CDT,M3.2.0/0,M11.1.0/1", + "America/Hermosillo": "MST7", + "America/Indiana/Indianapolis": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Knox": "CST6CDT,M3.2.0,M11.1.0", + "America/Indiana/Marengo": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Petersburg": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Tell_City": "CST6CDT,M3.2.0,M11.1.0", + "America/Indiana/Vevay": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Vincennes": "EST5EDT,M3.2.0,M11.1.0", + "America/Indiana/Winamac": "EST5EDT,M3.2.0,M11.1.0", + "America/Inuvik": "MST7MDT,M3.2.0,M11.1.0", + "America/Iqaluit": "EST5EDT,M3.2.0,M11.1.0", + "America/Jamaica": "EST5", + "America/Juneau": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Kentucky/Louisville": "EST5EDT,M3.2.0,M11.1.0", + "America/Kentucky/Monticello": "EST5EDT,M3.2.0,M11.1.0", + "America/Kralendijk": "AST4", + "America/La_Paz": "UNK4", + "America/Lima": "UNK5", + "America/Los_Angeles": "PST8PDT,M3.2.0,M11.1.0", + "America/Lower_Princes": "AST4", + "America/Maceio": "UNK3", + "America/Managua": "CST6", + "America/Manaus": "UNK4", + "America/Marigot": "AST4", + "America/Martinique": "AST4", + "America/Matamoros": "CST6CDT,M3.2.0,M11.1.0", + "America/Mazatlan": "MST7MDT,M4.1.0,M10.5.0", + "America/Menominee": "CST6CDT,M3.2.0,M11.1.0", + "America/Merida": "CST6CDT,M4.1.0,M10.5.0", + "America/Metlakatla": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Mexico_City": "CST6CDT,M4.1.0,M10.5.0", + "America/Miquelon": "UNK3UNK,M3.2.0,M11.1.0", + "America/Moncton": "AST4ADT,M3.2.0,M11.1.0", + "America/Monterrey": "CST6CDT,M4.1.0,M10.5.0", + "America/Montevideo": "UNK3", + "America/Montreal": "EST5EDT,M3.2.0,M11.1.0", + "America/Montserrat": "AST4", + "America/Nassau": "EST5EDT,M3.2.0,M11.1.0", + "America/New_York": "EST5EDT,M3.2.0,M11.1.0", + "America/Nipigon": "EST5EDT,M3.2.0,M11.1.0", + "America/Nome": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Noronha": "UNK2", + "America/North_Dakota/Beulah": "CST6CDT,M3.2.0,M11.1.0", + "America/North_Dakota/Center": "CST6CDT,M3.2.0,M11.1.0", + "America/North_Dakota/New_Salem": "CST6CDT,M3.2.0,M11.1.0", + "America/Ojinaga": "MST7MDT,M3.2.0,M11.1.0", + "America/Panama": "EST5", + "America/Pangnirtung": "EST5EDT,M3.2.0,M11.1.0", + "America/Paramaribo": "UNK3", + "America/Phoenix": "MST7", + "America/Port-au-Prince": "EST5EDT,M3.2.0,M11.1.0", + "America/Port_of_Spain": "AST4", + "America/Porto_Velho": "UNK4", + "America/Puerto_Rico": "AST4", + "America/Punta_Arenas": "UNK3", + "America/Rainy_River": "CST6CDT,M3.2.0,M11.1.0", + "America/Rankin_Inlet": "CST6CDT,M3.2.0,M11.1.0", + "America/Recife": "UNK3", + "America/Regina": "CST6", + "America/Resolute": "CST6CDT,M3.2.0,M11.1.0", + "America/Rio_Branco": "UNK5", + "America/Santarem": "UNK3", + "America/Santiago": "UNK4UNK,M9.1.6/24,M4.1.6/24", + "America/Santo_Domingo": "AST4", + "America/Sao_Paulo": "UNK3", + "America/Scoresbysund": "UNK1UNK,M3.5.0/0,M10.5.0/1", + "America/Sitka": "AKST9AKDT,M3.2.0,M11.1.0", + "America/St_Barthelemy": "AST4", + "America/St_Johns": "NST3:30NDT,M3.2.0,M11.1.0", + "America/St_Kitts": "AST4", + "America/St_Lucia": "AST4", + "America/St_Thomas": "AST4", + "America/St_Vincent": "AST4", + "America/Swift_Current": "CST6", + "America/Tegucigalpa": "CST6", + "America/Thule": "AST4ADT,M3.2.0,M11.1.0", + "America/Thunder_Bay": "EST5EDT,M3.2.0,M11.1.0", + "America/Tijuana": "PST8PDT,M3.2.0,M11.1.0", + "America/Toronto": "EST5EDT,M3.2.0,M11.1.0", + "America/Tortola": "AST4", + "America/Vancouver": "PST8PDT,M3.2.0,M11.1.0", + "America/Whitehorse": "MST7", + "America/Winnipeg": "CST6CDT,M3.2.0,M11.1.0", + "America/Yakutat": "AKST9AKDT,M3.2.0,M11.1.0", + "America/Yellowknife": "MST7MDT,M3.2.0,M11.1.0", + "Antarctica/Casey": "UNK-8", + "Antarctica/Davis": "UNK-7", + "Antarctica/DumontDUrville": "UNK-10", + "Antarctica/Macquarie": "UNK-11", + "Antarctica/Mawson": "UNK-5", + "Antarctica/McMurdo": "NZST-12NZDT,M9.5.0,M4.1.0/3", + "Antarctica/Palmer": "UNK3", + "Antarctica/Rothera": "UNK3", + "Antarctica/Syowa": "UNK-3", + "Antarctica/Troll": "UNK0UNK-2,M3.5.0/1,M10.5.0/3", + "Antarctica/Vostok": "UNK-6", + "Arctic/Longyearbyen": "CET-1CEST,M3.5.0,M10.5.0/3", + "Asia/Aden": "UNK-3", + "Asia/Almaty": "UNK-6", + "Asia/Amman": "EET-2EEST,M3.5.4/24,M10.5.5/1", + "Asia/Anadyr": "UNK-12", + "Asia/Aqtau": "UNK-5", + "Asia/Aqtobe": "UNK-5", + "Asia/Ashgabat": "UNK-5", + "Asia/Atyrau": "UNK-5", + "Asia/Baghdad": "UNK-3", + "Asia/Bahrain": "UNK-3", + "Asia/Baku": "UNK-4", + "Asia/Bangkok": "UNK-7", + "Asia/Barnaul": "UNK-7", + "Asia/Beirut": "EET-2EEST,M3.5.0/0,M10.5.0/0", + "Asia/Bishkek": "UNK-6", + "Asia/Brunei": "UNK-8", + "Asia/Chita": "UNK-9", + "Asia/Choibalsan": "UNK-8", + "Asia/Colombo": "UNK-5:30", + "Asia/Damascus": "EET-2EEST,M3.5.5/0,M10.5.5/0", + "Asia/Dhaka": "UNK-6", + "Asia/Dili": "UNK-9", + "Asia/Dubai": "UNK-4", + "Asia/Dushanbe": "UNK-5", + "Asia/Famagusta": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Asia/Gaza": "EET-2EEST,M3.5.5/0,M10.5.6/1", + "Asia/Hebron": "EET-2EEST,M3.5.5/0,M10.5.6/1", + "Asia/Ho_Chi_Minh": "UNK-7", + "Asia/Hong_Kong": "HKT-8", + "Asia/Hovd": "UNK-7", + "Asia/Irkutsk": "UNK-8", + "Asia/Jakarta": "WIB-7", + "Asia/Jayapura": "WIT-9", + "Asia/Jerusalem": "IST-2IDT,M3.4.4/26,M10.5.0", + "Asia/Kabul": "UNK-4:30", + "Asia/Kamchatka": "UNK-12", + "Asia/Karachi": "PKT-5", + "Asia/Kathmandu": "UNK-5:45", + "Asia/Khandyga": "UNK-9", + "Asia/Kolkata": "IST-5:30", + "Asia/Krasnoyarsk": "UNK-7", + "Asia/Kuala_Lumpur": "UNK-8", + "Asia/Kuching": "UNK-8", + "Asia/Kuwait": "UNK-3", + "Asia/Macau": "CST-8", + "Asia/Magadan": "UNK-11", + "Asia/Makassar": "WITA-8", + "Asia/Manila": "PST-8", + "Asia/Muscat": "UNK-4", + "Asia/Nicosia": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Asia/Novokuznetsk": "UNK-7", + "Asia/Novosibirsk": "UNK-7", + "Asia/Omsk": "UNK-6", + "Asia/Oral": "UNK-5", + "Asia/Phnom_Penh": "UNK-7", + "Asia/Pontianak": "WIB-7", + "Asia/Pyongyang": "KST-9", + "Asia/Qatar": "UNK-3", + "Asia/Qyzylorda": "UNK-5", + "Asia/Riyadh": "UNK-3", + "Asia/Sakhalin": "UNK-11", + "Asia/Samarkand": "UNK-5", + "Asia/Seoul": "KST-9", + "Asia/Shanghai": "CST-8", + "Asia/Singapore": "UNK-8", + "Asia/Srednekolymsk": "UNK-11", + "Asia/Taipei": "CST-8", + "Asia/Tashkent": "UNK-5", + "Asia/Tbilisi": "UNK-4", + "Asia/Tehran": "UNK-3:30UNK,J79/24,J263/24", + "Asia/Thimphu": "UNK-6", + "Asia/Tokyo": "JST-9", + "Asia/Tomsk": "UNK-7", + "Asia/Ulaanbaatar": "UNK-8", + "Asia/Urumqi": "UNK-6", + "Asia/Ust-Nera": "UNK-10", + "Asia/Vientiane": "UNK-7", + "Asia/Vladivostok": "UNK-10", + "Asia/Yakutsk": "UNK-9", + "Asia/Yangon": "UNK-6:30", + "Asia/Yekaterinburg": "UNK-5", + "Asia/Yerevan": "UNK-4", + "Atlantic/Azores": "UNK1UNK,M3.5.0/0,M10.5.0/1", + "Atlantic/Bermuda": "AST4ADT,M3.2.0,M11.1.0", + "Atlantic/Canary": "WET0WEST,M3.5.0/1,M10.5.0", + "Atlantic/Cape_Verde": "UNK1", + "Atlantic/Faroe": "WET0WEST,M3.5.0/1,M10.5.0", + "Atlantic/Madeira": "WET0WEST,M3.5.0/1,M10.5.0", + "Atlantic/Reykjavik": "GMT0", + "Atlantic/South_Georgia": "UNK2", + "Atlantic/St_Helena": "GMT0", + "Atlantic/Stanley": "UNK3", + "Australia/Adelaide": "ACST-9:30ACDT,M10.1.0,M4.1.0/3", + "Australia/Brisbane": "AEST-10", + "Australia/Broken_Hill": "ACST-9:30ACDT,M10.1.0,M4.1.0/3", + "Australia/Currie": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Australia/Darwin": "ACST-9:30", + "Australia/Eucla": "UNK-8:45", + "Australia/Hobart": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Australia/Lindeman": "AEST-10", + "Australia/Lord_Howe": "UNK-10:30UNK-11,M10.1.0,M4.1.0", + "Australia/Melbourne": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Australia/Perth": "AWST-8", + "Australia/Sydney": "AEST-10AEDT,M10.1.0,M4.1.0/3", + "Etc/GMT": "GMT0", + "Etc/GMT+0": "GMT0", + "Etc/GMT+1": "UNK1", + "Etc/GMT+10": "UNK10", + "Etc/GMT+11": "UNK11", + "Etc/GMT+12": "UNK12", + "Etc/GMT+2": "UNK2", + "Etc/GMT+3": "UNK3", + "Etc/GMT+4": "UNK4", + "Etc/GMT+5": "UNK5", + "Etc/GMT+6": "UNK6", + "Etc/GMT+7": "UNK7", + "Etc/GMT+8": "UNK8", + "Etc/GMT+9": "UNK9", + "Etc/GMT-0": "GMT0", + "Etc/GMT-1": "UNK-1", + "Etc/GMT-10": "UNK-10", + "Etc/GMT-11": "UNK-11", + "Etc/GMT-12": "UNK-12", + "Etc/GMT-13": "UNK-13", + "Etc/GMT-14": "UNK-14", + "Etc/GMT-2": "UNK-2", + "Etc/GMT-3": "UNK-3", + "Etc/GMT-4": "UNK-4", + "Etc/GMT-5": "UNK-5", + "Etc/GMT-6": "UNK-6", + "Etc/GMT-7": "UNK-7", + "Etc/GMT-8": "UNK-8", + "Etc/GMT-9": "UNK-9", + "Etc/GMT0": "GMT0", + "Etc/Greenwich": "GMT0", + "Etc/UCT": "UTC0", + "Etc/UTC": "UTC0", + "Etc/Universal": "UTC0", + "Etc/Zulu": "UTC0", + "Europe/Amsterdam": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Andorra": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Astrakhan": "UNK-4", + "Europe/Athens": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Belgrade": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Berlin": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Bratislava": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Brussels": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Bucharest": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Budapest": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Busingen": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Chisinau": "EET-2EEST,M3.5.0,M10.5.0/3", + "Europe/Copenhagen": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Dublin": "IST-1GMT0,M10.5.0,M3.5.0/1", + "Europe/Gibraltar": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Guernsey": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Helsinki": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Isle_of_Man": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Istanbul": "UNK-3", + "Europe/Jersey": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Kaliningrad": "EET-2", + "Europe/Kiev": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Kirov": "UNK-3", + "Europe/Lisbon": "WET0WEST,M3.5.0/1,M10.5.0", + "Europe/Ljubljana": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/London": "GMT0BST,M3.5.0/1,M10.5.0", + "Europe/Luxembourg": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Madrid": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Malta": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Mariehamn": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Minsk": "UNK-3", + "Europe/Monaco": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Moscow": "MSK-3", + "Europe/Oslo": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Paris": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Podgorica": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Prague": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Riga": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Rome": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Samara": "UNK-4", + "Europe/San_Marino": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Sarajevo": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Saratov": "UNK-4", + "Europe/Simferopol": "MSK-3", + "Europe/Skopje": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Sofia": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Stockholm": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Tallinn": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Tirane": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Ulyanovsk": "UNK-4", + "Europe/Uzhgorod": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Vaduz": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Vatican": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Vienna": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Vilnius": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Volgograd": "UNK-4", + "Europe/Warsaw": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Zagreb": "CET-1CEST,M3.5.0,M10.5.0/3", + "Europe/Zaporozhye": "EET-2EEST,M3.5.0/3,M10.5.0/4", + "Europe/Zurich": "CET-1CEST,M3.5.0,M10.5.0/3", + "Indian/Antananarivo": "EAT-3", + "Indian/Chagos": "UNK-6", + "Indian/Christmas": "UNK-7", + "Indian/Cocos": "UNK-6:30", + "Indian/Comoro": "EAT-3", + "Indian/Kerguelen": "UNK-5", + "Indian/Mahe": "UNK-4", + "Indian/Maldives": "UNK-5", + "Indian/Mauritius": "UNK-4", + "Indian/Mayotte": "EAT-3", + "Indian/Reunion": "UNK-4", + "Pacific/Apia": "UNK-13UNK,M9.5.0/3,M4.1.0/4", + "Pacific/Auckland": "NZST-12NZDT,M9.5.0,M4.1.0/3", + "Pacific/Bougainville": "UNK-11", + "Pacific/Chatham": "UNK-12:45UNK,M9.5.0/2:45,M4.1.0/3:45", + "Pacific/Chuuk": "UNK-10", + "Pacific/Easter": "UNK6UNK,M9.1.6/22,M4.1.6/22", + "Pacific/Efate": "UNK-11", + "Pacific/Enderbury": "UNK-13", + "Pacific/Fakaofo": "UNK-13", + "Pacific/Fiji": "UNK-12UNK,M11.2.0,M1.2.3/99", + "Pacific/Funafuti": "UNK-12", + "Pacific/Galapagos": "UNK6", + "Pacific/Gambier": "UNK9", + "Pacific/Guadalcanal": "UNK-11", + "Pacific/Guam": "ChST-10", + "Pacific/Honolulu": "HST10", + "Pacific/Kiritimati": "UNK-14", + "Pacific/Kosrae": "UNK-11", + "Pacific/Kwajalein": "UNK-12", + "Pacific/Majuro": "UNK-12", + "Pacific/Marquesas": "UNK9:30", + "Pacific/Midway": "SST11", + "Pacific/Nauru": "UNK-12", + "Pacific/Niue": "UNK11", + "Pacific/Norfolk": "UNK-11UNK,M10.1.0,M4.1.0/3", + "Pacific/Noumea": "UNK-11", + "Pacific/Pago_Pago": "SST11", + "Pacific/Palau": "UNK-9", + "Pacific/Pitcairn": "UNK8", + "Pacific/Pohnpei": "UNK-11", + "Pacific/Port_Moresby": "UNK-10", + "Pacific/Rarotonga": "UNK10", + "Pacific/Saipan": "ChST-10", + "Pacific/Tahiti": "UNK10", + "Pacific/Tarawa": "UNK-12", + "Pacific/Tongatapu": "UNK-13", + "Pacific/Wake": "UNK-12", + "Pacific/Wallis": "UNK-12" +} + +export function selectedTimeZone(label: string, format: string) { + return TIME_ZONES[label] === format ? label : undefined; +} + +export function timeZoneSelectItems() { + return Object.keys(TIME_ZONES).map(label => ( + {label} + )); +} diff --git a/interface/src/ntp/TimeFormat.ts b/interface/src/ntp/TimeFormat.ts new file mode 100644 index 0000000..7e0bb82 --- /dev/null +++ b/interface/src/ntp/TimeFormat.ts @@ -0,0 +1,5 @@ +import moment, { Moment } from 'moment'; + +export const formatIsoDateTime = (isoDateString: string) => moment.parseZone(isoDateString).format('ll @ HH:mm:ss'); + +export const formatLocalDateTime = (moment: Moment) => moment.format('YYYY-MM-DDTHH:mm'); diff --git a/interface/src/ntp/types.ts b/interface/src/ntp/types.ts new file mode 100644 index 0000000..a266d12 --- /dev/null +++ b/interface/src/ntp/types.ts @@ -0,0 +1,23 @@ +export enum NTPSyncStatus { + NTP_INACTIVE = 0, + NTP_ACTIVE = 1 +} + +export interface NTPStatus { + status: NTPSyncStatus; + time_utc: string; + time_local: string; + server: string; + uptime: number; +} + +export interface NTPSettings { + enabled: boolean; + server: string; + tz_label: string; + tz_format: string; +} + +export interface Time { + time_utc: string; +} diff --git a/interface/src/project/GeneralInformation.tsx b/interface/src/project/GeneralInformation.tsx new file mode 100644 index 0000000..ccd0735 --- /dev/null +++ b/interface/src/project/GeneralInformation.tsx @@ -0,0 +1,120 @@ +import React, {Component} from 'react'; +import {Box, List, ListItem, ListItemText} from '@material-ui/core'; +import { + FormButton, + restController, + RestControllerProps, + RestFormLoader, + SectionContent +} from '../components'; +import {ENDPOINT_ROOT} from "../api"; +import {GeneralInformaitonState} from "./types"; +import RefreshIcon from "@material-ui/icons/Refresh"; + +// define api endpoint +export const GENERALINFORMATION_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "generalinfo"; + +type GeneralInformationRestControllerProps = RestControllerProps; + +class GeneralInformation extends Component { + intervalhandler: number | undefined; + + componentDidMount() { + this.props.loadData(); + + // this.intervalhandler = window.setInterval(() => { + // this.props.loadData(); + // console.log("refreshing data"); + // console.log(this.props.data) + // }, 10000); + } + + componentWillUnmount() { + clearInterval(this.intervalhandler); + } + + render() { + return ( + + ( + <> + + + + + + + + + + + + + + + + + + + + + + + } variant="contained" color="secondary" + onClick={this.props.loadData}> + Refresh + + + + Version: {props.data.version} + + + + )} + /> + + ); + } + + /** + * stringify seconds to a pretty format + * @param sec number of seconds + */ + stringifyTime(sec: number): string { + if (sec >= 86400) { + // display days + return (Math.trunc(sec / 86400) + "d " + Math.trunc((sec % 86400) / 3600) + "h " + Math.trunc((sec % 3600) / 60) + "min " + sec % 60 + "sec"); + } else if (sec >= 3600) { + // display hours + return (Math.trunc(sec / 3600) + "h " + Math.trunc((sec % 3600) / 60) + "min " + sec % 60 + "sec"); + } else if (sec >= 60) { + // only seconds and minutes + return (Math.trunc(sec / 60) + "min " + sec % 60 + "sec"); + } else { + // only seconds + return (sec + "sec"); + } + } +} + +export default restController(GENERALINFORMATION_SETTINGS_ENDPOINT, GeneralInformation); diff --git a/interface/src/project/ProjectMenu.tsx b/interface/src/project/ProjectMenu.tsx new file mode 100644 index 0000000..452a7c5 --- /dev/null +++ b/interface/src/project/ProjectMenu.tsx @@ -0,0 +1,27 @@ +import React, { Component } from 'react'; +import { Link, withRouter, RouteComponentProps } from 'react-router-dom'; + +import {List, ListItem, ListItemIcon, ListItemText} from '@material-ui/core'; +import SettingsRemoteIcon from '@material-ui/icons/SettingsRemote'; + +import { PROJECT_PATH } from '../api'; + +class ProjectMenu extends Component { + + render() { + const path = this.props.match.url; + return ( + + + + + + + + + ) + } + +} + +export default withRouter(ProjectMenu); diff --git a/interface/src/project/ProjectRouting.tsx b/interface/src/project/ProjectRouting.tsx new file mode 100644 index 0000000..e6cbe33 --- /dev/null +++ b/interface/src/project/ProjectRouting.tsx @@ -0,0 +1,33 @@ +import React, { Component } from 'react'; +import { Redirect, Switch } from 'react-router'; + +import { PROJECT_PATH } from '../api'; +import { AuthenticatedRoute } from '../authentication'; + +import PumpControl from './PumpControl'; + +class ProjectRouting extends Component { + + render() { + return ( + + { + /* + * Add your project page routing below. + */ + } + + { + /* + * The redirect below caters for the default project route and redirecting invalid paths. + * The "to" property must match one of the routes above for this to work correctly. + */ + } + + + ) + } + +} + +export default ProjectRouting; diff --git a/interface/src/project/PumpControl.tsx b/interface/src/project/PumpControl.tsx new file mode 100644 index 0000000..204e812 --- /dev/null +++ b/interface/src/project/PumpControl.tsx @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; +import { Redirect, Switch, RouteComponentProps } from 'react-router-dom' + +import { Tabs, Tab } from '@material-ui/core'; + +import { PROJECT_PATH } from '../api'; +import { MenuAppBar } from '../components'; +import { AuthenticatedRoute } from '../authentication'; + +import GeneralInformation from './GeneralInformation'; +import SettingsController from "./SettingsController"; + +class PumpControl extends Component { + + handleTabChange = (event: React.ChangeEvent<{}>, path: string) => { + this.props.history.push(path); + }; + + render() { + return ( + + + + + + + + + + + + ) + } + +} + +export default PumpControl; diff --git a/interface/src/project/SettingsController.tsx b/interface/src/project/SettingsController.tsx new file mode 100644 index 0000000..5508bb6 --- /dev/null +++ b/interface/src/project/SettingsController.tsx @@ -0,0 +1,84 @@ +import React, {Component} from 'react'; +import {ValidatorForm} from 'react-material-ui-form-validator'; + +import {Typography, Box, TextField} from '@material-ui/core'; +import SaveIcon from '@material-ui/icons/Save'; + +import {ENDPOINT_ROOT} from '../api'; +import { + restController, + RestControllerProps, + RestFormLoader, + FormActions, + FormButton, + SectionContent, +} from '../components'; + +import {SettingsState} from './types'; + +export const LIGHT_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "settings"; + +type LightStateRestControllerProps = RestControllerProps; + +class SettingsController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + { + const {data, saveData, handleValueChange} = props; + return ( + + + + Die unten eingegebenen Werte werden nach klick des 'SAVE' Buttons übernommen und überleben einen Neustart. + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ + + } variant="contained" color="primary" + type="submit">Save + + +
+ ) + }} + /> +
+ ) + } + +} + +export default restController(LIGHT_SETTINGS_ENDPOINT, SettingsController); diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts new file mode 100644 index 0000000..460dd62 --- /dev/null +++ b/interface/src/project/types.ts @@ -0,0 +1,19 @@ +export interface SettingsState { + maxpumpduration: number; + waterOutageWaitDuration: number; + heatUp: number; + heatLow: number; + fanRuntime: number; +} + +export interface GeneralInformaitonState { + hum: number; + temp: number; + lastpumptime: number; + lastWaterOutage: number; + lastPumpDuration: number; + runtime: number; + watersensor: boolean; + pressuresensor: boolean; + version: string; +} diff --git a/interface/src/react-app-env.d.ts b/interface/src/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/interface/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/interface/src/security/ManageUsersController.tsx b/interface/src/security/ManageUsersController.tsx new file mode 100644 index 0000000..ccd3cde --- /dev/null +++ b/interface/src/security/ManageUsersController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { SECURITY_SETTINGS_ENDPOINT } from '../api'; + +import ManageUsersForm from './ManageUsersForm'; +import { SecuritySettings } from './types'; + +type ManageUsersControllerProps = RestControllerProps; + +class ManageUsersController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ) + } + +} + +export default restController(SECURITY_SETTINGS_ENDPOINT, ManageUsersController); diff --git a/interface/src/security/ManageUsersForm.tsx b/interface/src/security/ManageUsersForm.tsx new file mode 100644 index 0000000..b8c63b7 --- /dev/null +++ b/interface/src/security/ManageUsersForm.tsx @@ -0,0 +1,184 @@ +import React, { Fragment } from 'react'; +import { ValidatorForm } from 'react-material-ui-form-validator'; + +import { Table, TableBody, TableCell, TableHead, TableFooter, TableRow, withWidth, WithWidthProps, isWidthDown } from '@material-ui/core'; +import { Box, Button, Typography, } from '@material-ui/core'; + +import EditIcon from '@material-ui/icons/Edit'; +import DeleteIcon from '@material-ui/icons/Delete'; +import CloseIcon from '@material-ui/icons/Close'; +import CheckIcon from '@material-ui/icons/Check'; +import IconButton from '@material-ui/core/IconButton'; +import SaveIcon from '@material-ui/icons/Save'; +import PersonAddIcon from '@material-ui/icons/PersonAdd'; + +import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication'; +import { RestFormProps, FormActions, FormButton, extractEventValue } from '../components'; + +import UserForm from './UserForm'; +import { SecuritySettings, User } from './types'; + +function compareUsers(a: User, b: User) { + if (a.username < b.username) { + return -1; + } + if (a.username > b.username) { + return 1; + } + return 0; +} + +type ManageUsersFormProps = RestFormProps & AuthenticatedContextProps & WithWidthProps; + +type ManageUsersFormState = { + creating: boolean; + user?: User; +} + +class ManageUsersForm extends React.Component { + + state: ManageUsersFormState = { + creating: false + }; + + createUser = () => { + this.setState({ + creating: true, + user: { + username: "", + password: "", + admin: true + } + }); + }; + + uniqueUsername = (username: string) => { + return !this.props.data.users.find(u => u.username === username); + } + + noAdminConfigured = () => { + return !this.props.data.users.find(u => u.admin); + } + + removeUser = (user: User) => { + const { data } = this.props; + const users = data.users.filter(u => u.username !== user.username); + this.props.setData({ ...data, users }); + } + + startEditingUser = (user: User) => { + this.setState({ + creating: false, + user + }); + }; + + cancelEditingUser = () => { + this.setState({ + user: undefined + }); + } + + doneEditingUser = () => { + const { user } = this.state; + if (user) { + const { data } = this.props; + const users = data.users.filter(u => u.username !== user.username); + users.push(user); + this.props.setData({ ...data, users }); + this.setState({ + user: undefined + }); + } + }; + + handleUserValueChange = (name: keyof User) => (event: React.ChangeEvent) => { + this.setState({ user: { ...this.state.user!, [name]: extractEventValue(event) } }); + }; + + onSubmit = () => { + this.props.saveData(); + this.props.authenticatedContext.refresh(); + } + + render() { + const { width, data } = this.props; + const { user, creating } = this.state; + return ( + + + + + + Username + Admin? + + + + + {data.users.sort(compareUsers).map(user => ( + + + {user.username} + + + { + user.admin ? : + } + + + this.removeUser(user)}> + + + this.startEditingUser(user)}> + + + + + ))} + + + + + + + + + +
+ { + this.noAdminConfigured() && + ( + + + You must have at least one admin user configured. + + + ) + } + + } variant="contained" color="primary" type="submit" disabled={this.noAdminConfigured()}> + Save + + +
+ { + user && + + } +
+ ); + } + +} + +export default withAuthenticatedContext(withWidth()(ManageUsersForm)); diff --git a/interface/src/security/Security.tsx b/interface/src/security/Security.tsx new file mode 100644 index 0000000..4e99769 --- /dev/null +++ b/interface/src/security/Security.tsx @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; +import { Redirect, Switch, RouteComponentProps } from 'react-router-dom' + +import { Tabs, Tab } from '@material-ui/core'; + +import { AuthenticatedContextProps, AuthenticatedRoute } from '../authentication'; +import { MenuAppBar } from '../components'; + +import ManageUsersController from './ManageUsersController'; +import SecuritySettingsController from './SecuritySettingsController'; + +type SecurityProps = AuthenticatedContextProps & RouteComponentProps; + +class Security extends Component { + + handleTabChange = (event: React.ChangeEvent<{}>, path: string) => { + this.props.history.push(path); + }; + + render() { + return ( + + + + + + + + + + + + ) + } +} + +export default Security; diff --git a/interface/src/security/SecuritySettingsController.tsx b/interface/src/security/SecuritySettingsController.tsx new file mode 100644 index 0000000..d42328a --- /dev/null +++ b/interface/src/security/SecuritySettingsController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { SECURITY_SETTINGS_ENDPOINT } from '../api'; + +import SecuritySettingsForm from './SecuritySettingsForm'; +import { SecuritySettings } from './types'; + +type SecuritySettingsControllerProps = RestControllerProps; + +class SecuritySettingsController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ); + } + +} + +export default restController(SECURITY_SETTINGS_ENDPOINT, SecuritySettingsController); diff --git a/interface/src/security/SecuritySettingsForm.tsx b/interface/src/security/SecuritySettingsForm.tsx new file mode 100644 index 0000000..6407f5f --- /dev/null +++ b/interface/src/security/SecuritySettingsForm.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { ValidatorForm } from 'react-material-ui-form-validator'; + +import { Box, Typography } from '@material-ui/core'; +import SaveIcon from '@material-ui/icons/Save'; + +import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication'; +import { RestFormProps, PasswordValidator, FormActions, FormButton } from '../components'; + +import { SecuritySettings } from './types'; + +type SecuritySettingsFormProps = RestFormProps & AuthenticatedContextProps; + +class SecuritySettingsForm extends React.Component { + + onSubmit = () => { + this.props.saveData(); + this.props.authenticatedContext.refresh(); + } + + render() { + const { data, handleValueChange } = this.props; + return ( + + + + + The JWT secret is used to sign authentication tokens. If you modify the JWT Secret, all users will be signed out. + + + + } variant="contained" color="primary" type="submit"> + Save + + + + ); + } + +} + +export default withAuthenticatedContext(SecuritySettingsForm); diff --git a/interface/src/security/UserForm.tsx b/interface/src/security/UserForm.tsx new file mode 100644 index 0000000..8eefa7d --- /dev/null +++ b/interface/src/security/UserForm.tsx @@ -0,0 +1,86 @@ +import React, { RefObject } from 'react'; +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; + +import { Dialog, DialogTitle, DialogContent, DialogActions, Checkbox } from '@material-ui/core'; + +import { PasswordValidator, BlockFormControlLabel, FormButton } from '../components'; + +import { User } from './types'; + +interface UserFormProps { + creating: boolean; + user: User; + uniqueUsername: (value: any) => boolean; + handleValueChange: (name: keyof User) => (event: React.ChangeEvent) => void; + onDoneEditing: () => void; + onCancelEditing: () => void; +} + +class UserForm extends React.Component { + + formRef: RefObject = React.createRef(); + + componentDidMount() { + ValidatorForm.addValidationRule('uniqueUsername', this.props.uniqueUsername); + } + + submit = () => { + this.formRef.current.submit(); + } + + render() { + const { user, creating, handleValueChange, onDoneEditing, onCancelEditing } = this.props; + return ( + + + {creating ? 'Add' : 'Modify'} User + + + + + } + label="Admin?" + /> + + + + Cancel + + + Done + + + + + ); + } +} + +export default UserForm; diff --git a/interface/src/security/types.ts b/interface/src/security/types.ts new file mode 100644 index 0000000..99d54de --- /dev/null +++ b/interface/src/security/types.ts @@ -0,0 +1,11 @@ +export interface User { + username: string; + password: string; + admin: boolean; +} + +export interface SecuritySettings { + users: User[]; + jwt_secret: string; +} + diff --git a/interface/src/serviceWorker.ts b/interface/src/serviceWorker.ts new file mode 100644 index 0000000..d5f0275 --- /dev/null +++ b/interface/src/serviceWorker.ts @@ -0,0 +1,145 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +type Config = { + onSuccess?: (registration: ServiceWorkerRegistration) => void; + onUpdate?: (registration: ServiceWorkerRegistration) => void; +}; + +export function register(config?: Config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL( + process.env.PUBLIC_URL, + window.location.href + ); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl: string, config?: Config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl: string, config?: Config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl, { + headers: { 'Service-Worker': 'script' } + }) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister(); + }); + } +} diff --git a/interface/src/system/OTASettingsController.tsx b/interface/src/system/OTASettingsController.tsx new file mode 100644 index 0000000..2f683b3 --- /dev/null +++ b/interface/src/system/OTASettingsController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { OTA_SETTINGS_ENDPOINT } from '../api'; + +import OTASettingsForm from './OTASettingsForm'; +import { OTASettings } from './types'; + +type OTASettingsControllerProps = RestControllerProps; + +class OTASettingsController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ); + } + +} + +export default restController(OTA_SETTINGS_ENDPOINT, OTASettingsController); diff --git a/interface/src/system/OTASettingsForm.tsx b/interface/src/system/OTASettingsForm.tsx new file mode 100644 index 0000000..c518995 --- /dev/null +++ b/interface/src/system/OTASettingsForm.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; + +import { Checkbox } from '@material-ui/core'; +import SaveIcon from '@material-ui/icons/Save'; + +import { RestFormProps, BlockFormControlLabel, PasswordValidator, FormButton, FormActions } from '../components'; +import {isIP,isHostname,or} from '../validators'; + +import { OTASettings } from './types'; + +type OTASettingsFormProps = RestFormProps; + +class OTASettingsForm extends React.Component { + + componentDidMount() { + ValidatorForm.addValidationRule('isIPOrHostname', or(isIP, isHostname)); + } + + render() { + const { data, handleValueChange, saveData } = this.props; + return ( + + + } + label="Enable OTA Updates?" + /> + + + + } variant="contained" color="primary" type="submit"> + Save + + + + ); + } +} + +export default OTASettingsForm; diff --git a/interface/src/system/System.tsx b/interface/src/system/System.tsx new file mode 100644 index 0000000..671d5e0 --- /dev/null +++ b/interface/src/system/System.tsx @@ -0,0 +1,51 @@ +import React, { Component } from 'react'; +import { Redirect, Switch, RouteComponentProps } from 'react-router-dom' + +import { Tabs, Tab } from '@material-ui/core'; + +import { WithFeaturesProps, withFeatures } from '../features/FeaturesContext'; + +import { withAuthenticatedContext, AuthenticatedContextProps, AuthenticatedRoute } from '../authentication'; +import { MenuAppBar } from '../components'; + +import SystemStatusController from './SystemStatusController'; +import OTASettingsController from './OTASettingsController'; +import UploadFirmwareController from './UploadFirmwareController'; + +type SystemProps = AuthenticatedContextProps & RouteComponentProps & WithFeaturesProps; + +class System extends Component { + + handleTabChange = (event: React.ChangeEvent<{}>, path: string) => { + this.props.history.push(path); + }; + + render() { + const { authenticatedContext, features } = this.props; + return ( + + + + {features.ota && ( + + )} + {features.upload_firmware && ( + + )} + + + + {features.ota && ( + + )} + {features.upload_firmware && ( + + )} + + + + ) + } +} + +export default withFeatures(withAuthenticatedContext(System)); diff --git a/interface/src/system/SystemStatusController.tsx b/interface/src/system/SystemStatusController.tsx new file mode 100644 index 0000000..abee0b5 --- /dev/null +++ b/interface/src/system/SystemStatusController.tsx @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import { SYSTEM_STATUS_ENDPOINT } from '../api'; + +import SystemStatusForm from './SystemStatusForm'; +import { SystemStatus } from './types'; + +type SystemStatusControllerProps = RestControllerProps; + +class SystemStatusController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ); + } + +} + +export default restController(SYSTEM_STATUS_ENDPOINT, SystemStatusController); diff --git a/interface/src/system/SystemStatusForm.tsx b/interface/src/system/SystemStatusForm.tsx new file mode 100644 index 0000000..751946e --- /dev/null +++ b/interface/src/system/SystemStatusForm.tsx @@ -0,0 +1,245 @@ +import React, { Component, Fragment } from 'react'; + +import { Avatar, Button, Divider, Dialog, DialogTitle, DialogContent, DialogActions, Box } from '@material-ui/core'; +import { List, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'; + +import DevicesIcon from '@material-ui/icons/Devices'; +import MemoryIcon from '@material-ui/icons/Memory'; +import ShowChartIcon from '@material-ui/icons/ShowChart'; +import SdStorageIcon from '@material-ui/icons/SdStorage'; +import FolderIcon from '@material-ui/icons/Folder'; +import DataUsageIcon from '@material-ui/icons/DataUsage'; +import AppsIcon from '@material-ui/icons/Apps'; +import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew'; +import RefreshIcon from '@material-ui/icons/Refresh'; +import SettingsBackupRestoreIcon from '@material-ui/icons/SettingsBackupRestore'; + +import { redirectingAuthorizedFetch, AuthenticatedContextProps, withAuthenticatedContext } from '../authentication'; +import { RestFormProps, FormButton, ErrorButton } from '../components'; +import { FACTORY_RESET_ENDPOINT, RESTART_ENDPOINT } from '../api'; + +import { SystemStatus, EspPlatform } from './types'; + +interface SystemStatusFormState { + confirmRestart: boolean; + confirmFactoryReset: boolean; + processing: boolean; +} + +type SystemStatusFormProps = AuthenticatedContextProps & RestFormProps; + +function formatNumber(num: number) { + return new Intl.NumberFormat().format(num); +} + +class SystemStatusForm extends Component { + + state: SystemStatusFormState = { + confirmRestart: false, + confirmFactoryReset: false, + processing: false + } + + createListItems() { + const { data } = this.props + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + (data.esp_platform === EspPlatform.ESP32 && data.psram_size > 0) && ( + + + + + + + + + + + ) + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } + + renderRestartDialog() { + return ( + + Confirm Restart + + Are you sure you want to restart the device? + + + + + + + ) + } + + onRestart = () => { + this.setState({ confirmRestart: true }); + } + + onRestartRejected = () => { + this.setState({ confirmRestart: false }); + } + + onRestartConfirmed = () => { + this.setState({ processing: true }); + redirectingAuthorizedFetch(RESTART_ENDPOINT, { method: 'POST' }) + .then(response => { + if (response.status === 200) { + this.props.enqueueSnackbar("Device is restarting", { variant: 'info' }); + this.setState({ processing: false, confirmRestart: false }); + } else { + throw Error("Invalid status code: " + response.status); + } + }) + .catch(error => { + this.props.enqueueSnackbar(error.message || "Problem restarting device", { variant: 'error' }); + this.setState({ processing: false, confirmRestart: false }); + }); + } + + renderFactoryResetDialog() { + return ( + + Confirm Factory Reset + + Are you sure you want to reset the device to its factory defaults? + + + + } variant="contained" onClick={this.onFactoryResetConfirmed} disabled={this.state.processing} autoFocus> + Factory Reset + + + + ) + } + + onFactoryReset = () => { + this.setState({ confirmFactoryReset: true }); + } + + onFactoryResetRejected = () => { + this.setState({ confirmFactoryReset: false }); + } + + onFactoryResetConfirmed = () => { + this.setState({ processing: true }); + redirectingAuthorizedFetch(FACTORY_RESET_ENDPOINT, { method: 'POST' }) + .then(response => { + if (response.status === 200) { + this.props.enqueueSnackbar("Factory reset in progress.", { variant: 'error' }); + this.setState({ processing: false, confirmFactoryReset: false }); + } else { + throw Error("Invalid status code: " + response.status); + } + }) + .catch(error => { + this.props.enqueueSnackbar(error.message || "Problem factory resetting device", { variant: 'error' }); + this.setState({ processing: false, confirmRestart: false }); + }); + } + + render() { + const me = this.props.authenticatedContext.me; + return ( + + + {this.createListItems()} + + + + } variant="contained" color="secondary" onClick={this.props.loadData}> + Refresh + + + {me.admin && + + } variant="contained" color="primary" onClick={this.onRestart}> + Restart + + } variant="contained" onClick={this.onFactoryReset}> + Factory reset + + + } + + {this.renderRestartDialog()} + {this.renderFactoryResetDialog()} + + ); + } + +} + +export default withAuthenticatedContext(SystemStatusForm); diff --git a/interface/src/system/UploadFirmwareController.tsx b/interface/src/system/UploadFirmwareController.tsx new file mode 100644 index 0000000..16d21ff --- /dev/null +++ b/interface/src/system/UploadFirmwareController.tsx @@ -0,0 +1,71 @@ +import React, { Component } from 'react'; + +import { SectionContent } from '../components'; +import { UPLOAD_FIRMWARE_ENDPOINT } from '../api'; + +import UploadFirmwareForm from './UploadFirmwareForm'; +import { redirectingAuthorizedUpload } from '../authentication'; +import { withSnackbar, WithSnackbarProps } from 'notistack'; + +interface UploadFirmwareControllerState { + xhr?: XMLHttpRequest; + progress?: ProgressEvent; +} + +class UploadFirmwareController extends Component { + + state: UploadFirmwareControllerState = { + xhr: undefined, + progress: undefined + }; + + componentWillUnmount() { + this.state.xhr?.abort(); + } + + updateProgress = (progress: ProgressEvent) => { + this.setState({ progress }); + } + + uploadFile = (file: File) => { + if (this.state.xhr) { + return; + } + var xhr = new XMLHttpRequest(); + this.setState({ xhr }); + redirectingAuthorizedUpload(xhr, UPLOAD_FIRMWARE_ENDPOINT, file, this.updateProgress).then(() => { + if (xhr.status !== 200) { + throw Error("Invalid status code: " + xhr.status); + } + this.props.enqueueSnackbar("Activating new firmware", { variant: 'success' }); + this.setState({ xhr: undefined, progress: undefined }); + }).catch((error: Error) => { + if (error.name === 'AbortError') { + this.props.enqueueSnackbar("Upload cancelled by user", { variant: 'warning' }); + } else { + const errorMessage = error.name === 'UploadError' ? "Error during upload" : (error.message || "Unknown error"); + this.props.enqueueSnackbar("Problem uploading: " + errorMessage, { variant: 'error' }); + this.setState({ xhr: undefined, progress: undefined }); + } + }); + } + + cancelUpload = () => { + if (this.state.xhr) { + this.state.xhr.abort(); + this.setState({ xhr: undefined, progress: undefined }); + } + } + + render() { + const { xhr, progress } = this.state; + return ( + + + + ); + } + +} + +export default withSnackbar(UploadFirmwareController); diff --git a/interface/src/system/UploadFirmwareForm.tsx b/interface/src/system/UploadFirmwareForm.tsx new file mode 100644 index 0000000..2c40be3 --- /dev/null +++ b/interface/src/system/UploadFirmwareForm.tsx @@ -0,0 +1,35 @@ +import React, { Fragment } from 'react'; +import { SingleUpload } from '../components'; +import { Box } from '@material-ui/core'; + +interface UploadFirmwareFormProps { + uploading: boolean; + progress?: ProgressEvent; + onFileSelected: (file: File) => void; + onCancel: () => void; +} + +class UploadFirmwareForm extends React.Component { + + handleDrop = (files: File[]) => { + const file = files[0]; + if (file) { + this.props.onFileSelected(files[0]); + } + }; + + render() { + const { uploading, progress, onCancel } = this.props; + return ( + + + Upload a new firmware (.bin) file below to replace the existing firmware. + + + + ); + } + +} + +export default UploadFirmwareForm; diff --git a/interface/src/system/types.ts b/interface/src/system/types.ts new file mode 100644 index 0000000..67b15e2 --- /dev/null +++ b/interface/src/system/types.ts @@ -0,0 +1,37 @@ +export enum EspPlatform { + ESP8266 = "esp8266", + ESP32 = "esp32" +} + +interface ESPSystemStatus { + esp_platform: EspPlatform; + max_alloc_heap: number; + cpu_freq_mhz: number; + free_heap: number; + sketch_size: number; + free_sketch_space: number; + sdk_version: string; + flash_chip_size: number; + flash_chip_speed: number; + fs_used: number; + fs_total: number; +} + +export interface ESP32SystemStatus extends ESPSystemStatus { + esp_platform: EspPlatform.ESP32; + psram_size: number; + free_psram: number; +} + +export interface ESP8266SystemStatus extends ESPSystemStatus { + esp_platform: EspPlatform.ESP8266; + heap_fragmentation: number; +} + +export type SystemStatus = ESP8266SystemStatus | ESP32SystemStatus; + +export interface OTASettings { + enabled: boolean; + port: number; + password: string; +} diff --git a/interface/src/validators/index.ts b/interface/src/validators/index.ts new file mode 100644 index 0000000..82aafa8 --- /dev/null +++ b/interface/src/validators/index.ts @@ -0,0 +1,4 @@ +export { default as isHostname } from './isHostname'; +export { default as isIP } from './isIP'; +export { default as optional } from './optional'; +export { default as or } from './or'; diff --git a/interface/src/validators/isHostname.ts b/interface/src/validators/isHostname.ts new file mode 100644 index 0000000..7c1ca25 --- /dev/null +++ b/interface/src/validators/isHostname.ts @@ -0,0 +1,6 @@ +const hostnameLengthRegex = /^.{0,32}$/ +const hostnamePatternRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/ + +export default function isHostname(hostname: string) { + return hostnameLengthRegex.test(hostname) && hostnamePatternRegex.test(hostname); +} diff --git a/interface/src/validators/isIP.ts b/interface/src/validators/isIP.ts new file mode 100644 index 0000000..439c57c --- /dev/null +++ b/interface/src/validators/isIP.ts @@ -0,0 +1,5 @@ +const ipAddressRegexp = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ + +export default function isIp(ipAddress: string) { + return ipAddressRegexp.test(ipAddress); +} \ No newline at end of file diff --git a/interface/src/validators/optional.ts b/interface/src/validators/optional.ts new file mode 100644 index 0000000..841c57b --- /dev/null +++ b/interface/src/validators/optional.ts @@ -0,0 +1 @@ +export default (validator: (value: any) => boolean) => (value: any) => !value || validator(value); diff --git a/interface/src/validators/or.ts b/interface/src/validators/or.ts new file mode 100644 index 0000000..047ecf0 --- /dev/null +++ b/interface/src/validators/or.ts @@ -0,0 +1,3 @@ +export default (validator1: (value: any) => boolean, validator2: (value: any) => boolean) => { + return (value: any) => validator1(value) || validator2(value); +} diff --git a/interface/src/wifi/WiFiConnection.tsx b/interface/src/wifi/WiFiConnection.tsx new file mode 100644 index 0000000..c6cef06 --- /dev/null +++ b/interface/src/wifi/WiFiConnection.tsx @@ -0,0 +1,62 @@ +import React, { Component } from 'react'; +import { Redirect, Switch, RouteComponentProps } from 'react-router-dom' + +import { Tabs, Tab } from '@material-ui/core'; + +import { withAuthenticatedContext, AuthenticatedContextProps, AuthenticatedRoute } from '../authentication'; +import { MenuAppBar } from '../components'; + +import WiFiStatusController from './WiFiStatusController'; +import WiFiSettingsController from './WiFiSettingsController'; +import WiFiNetworkScanner from './WiFiNetworkScanner'; +import { WiFiConnectionContext } from './WiFiConnectionContext'; +import { WiFiNetwork } from './types'; + +type WiFiConnectionProps = AuthenticatedContextProps & RouteComponentProps; + +class WiFiConnection extends Component { + + constructor(props: WiFiConnectionProps) { + super(props); + this.state = { + selectNetwork: this.selectNetwork, + deselectNetwork: this.deselectNetwork + }; + } + + selectNetwork = (network: WiFiNetwork) => { + this.setState({ selectedNetwork: network }); + this.props.history.push('/wifi/settings'); + } + + deselectNetwork = () => { + this.setState({ selectedNetwork: undefined }); + } + + handleTabChange = (event: React.ChangeEvent<{}>, path: string) => { + this.props.history.push(path); + }; + + render() { + const { authenticatedContext } = this.props; + return ( + + + + + + + + + + + + + + + + ) + } +} + +export default withAuthenticatedContext(WiFiConnection); diff --git a/interface/src/wifi/WiFiConnectionContext.tsx b/interface/src/wifi/WiFiConnectionContext.tsx new file mode 100644 index 0000000..85b0c17 --- /dev/null +++ b/interface/src/wifi/WiFiConnectionContext.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { WiFiNetwork } from './types'; + +export interface WiFiConnectionContext { + selectedNetwork?: WiFiNetwork; + selectNetwork: (network: WiFiNetwork) => void; + deselectNetwork: () => void; +} + +const WiFiConnectionContextDefaultValue = {} as WiFiConnectionContext +export const WiFiConnectionContext = React.createContext( + WiFiConnectionContextDefaultValue +); diff --git a/interface/src/wifi/WiFiNetworkScanner.tsx b/interface/src/wifi/WiFiNetworkScanner.tsx new file mode 100644 index 0000000..744f515 --- /dev/null +++ b/interface/src/wifi/WiFiNetworkScanner.tsx @@ -0,0 +1,168 @@ +import React, { Component } from 'react'; +import { withSnackbar, WithSnackbarProps } from 'notistack'; + +import { createStyles, WithStyles, Theme, withStyles, Typography, LinearProgress } from '@material-ui/core'; +import PermScanWifiIcon from '@material-ui/icons/PermScanWifi'; + +import { FormActions, FormButton, SectionContent } from '../components'; +import { redirectingAuthorizedFetch } from '../authentication'; +import { SCAN_NETWORKS_ENDPOINT, LIST_NETWORKS_ENDPOINT } from '../api'; + +import WiFiNetworkSelector from './WiFiNetworkSelector'; +import { WiFiNetworkList, WiFiNetwork } from './types'; + +const NUM_POLLS = 10 +const POLLING_FREQUENCY = 500 +const RETRY_EXCEPTION_TYPE = "retry" + +interface WiFiNetworkScannerState { + scanningForNetworks: boolean; + errorMessage?: string; + networkList?: WiFiNetworkList; +} + +const styles = (theme: Theme) => createStyles({ + scanningSettings: { + margin: theme.spacing(0.5), + }, + scanningSettingsDetails: { + margin: theme.spacing(4), + textAlign: "center" + }, + scanningProgress: { + margin: theme.spacing(4), + textAlign: "center" + } +}); + +type WiFiNetworkScannerProps = WithSnackbarProps & WithStyles; + +class WiFiNetworkScanner extends Component { + + pollCount: number = 0; + + state: WiFiNetworkScannerState = { + scanningForNetworks: false, + }; + + componentDidMount() { + this.scanNetworks(); + } + + requestNetworkScan = () => { + const { scanningForNetworks } = this.state; + if (!scanningForNetworks) { + this.scanNetworks(); + } + } + + scanNetworks() { + this.pollCount = 0; + this.setState({ scanningForNetworks: true, networkList: undefined, errorMessage: undefined }); + redirectingAuthorizedFetch(SCAN_NETWORKS_ENDPOINT).then(response => { + if (response.status === 202) { + this.schedulePollTimeout(); + return; + } + throw Error("Scanning for networks returned unexpected response code: " + response.status); + }).catch(error => { + this.props.enqueueSnackbar("Problem scanning: " + error.message, { + variant: 'error', + }); + this.setState({ scanningForNetworks: false, networkList: undefined, errorMessage: error.message }); + }); + } + + schedulePollTimeout() { + setTimeout(this.pollNetworkList, POLLING_FREQUENCY); + } + + retryError() { + return { + name: RETRY_EXCEPTION_TYPE, + message: "Network list not ready, will retry in " + POLLING_FREQUENCY + "ms." + }; + } + + compareNetworks(network1: WiFiNetwork, network2: WiFiNetwork) { + if (network1.rssi < network2.rssi) + return 1; + if (network1.rssi > network2.rssi) + return -1; + return 0; + } + + pollNetworkList = () => { + redirectingAuthorizedFetch(LIST_NETWORKS_ENDPOINT) + .then(response => { + if (response.status === 200) { + return response.json(); + } + if (response.status === 202) { + if (++this.pollCount < NUM_POLLS) { + this.schedulePollTimeout(); + throw this.retryError(); + } else { + throw Error("Device did not return network list in timely manner."); + } + } + throw Error("Device returned unexpected response code: " + response.status); + }) + .then(json => { + json.networks.sort(this.compareNetworks) + this.setState({ scanningForNetworks: false, networkList: json, errorMessage: undefined }) + }) + .catch(error => { + if (error.name !== RETRY_EXCEPTION_TYPE) { + this.props.enqueueSnackbar("Problem scanning: " + error.message, { + variant: 'error', + }); + this.setState({ scanningForNetworks: false, networkList: undefined, errorMessage: error.message }); + } + }); + } + + renderNetworkScanner() { + const { classes } = this.props; + const { scanningForNetworks, networkList, errorMessage } = this.state; + if (scanningForNetworks || !networkList) { + return ( +
+ + + Scanning… + +
+ ); + } + if (errorMessage) { + return ( +
+ + {errorMessage} + +
+ ); + } + return ( + + ); + } + + render() { + const { scanningForNetworks } = this.state; + return ( + + {this.renderNetworkScanner()} + + } variant="contained" color="secondary" onClick={this.requestNetworkScan} disabled={scanningForNetworks}> + Scan again… + + + + ); + } + +} + +export default withSnackbar(withStyles(styles)(WiFiNetworkScanner)); diff --git a/interface/src/wifi/WiFiNetworkSelector.tsx b/interface/src/wifi/WiFiNetworkSelector.tsx new file mode 100644 index 0000000..2043651 --- /dev/null +++ b/interface/src/wifi/WiFiNetworkSelector.tsx @@ -0,0 +1,54 @@ +import React, { Component } from 'react'; + +import { Avatar, Badge } from '@material-ui/core'; +import { List, ListItem, ListItemIcon, ListItemText, ListItemAvatar } from '@material-ui/core'; + +import WifiIcon from '@material-ui/icons/Wifi'; +import LockIcon from '@material-ui/icons/Lock'; +import LockOpenIcon from '@material-ui/icons/LockOpen'; + +import { isNetworkOpen, networkSecurityMode } from './WiFiSecurityModes'; +import { WiFiConnectionContext } from './WiFiConnectionContext'; +import { WiFiNetwork, WiFiNetworkList } from './types'; + +interface WiFiNetworkSelectorProps { + networkList: WiFiNetworkList; +} + +class WiFiNetworkSelector extends Component { + + static contextType = WiFiConnectionContext; + context!: React.ContextType; + + renderNetwork = (network: WiFiNetwork) => { + return ( + this.context.selectNetwork(network)}> + + + {isNetworkOpen(network) ? : } + + + + + + + + + + ); + } + + render() { + return ( + + {this.props.networkList.networks.map(this.renderNetwork)} + + ); + } + +} + +export default WiFiNetworkSelector; diff --git a/interface/src/wifi/WiFiSecurityModes.ts b/interface/src/wifi/WiFiSecurityModes.ts new file mode 100644 index 0000000..b65c69a --- /dev/null +++ b/interface/src/wifi/WiFiSecurityModes.ts @@ -0,0 +1,21 @@ +import { WiFiNetwork, WiFiEncryptionType } from "./types"; + +export const isNetworkOpen = ({ encryption_type }: WiFiNetwork) => encryption_type === WiFiEncryptionType.WIFI_AUTH_OPEN; + +export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => { + switch (encryption_type) { + case WiFiEncryptionType.WIFI_AUTH_WEP: + case WiFiEncryptionType.WIFI_AUTH_WEP_PSK: + return "WEP"; + case WiFiEncryptionType.WIFI_AUTH_WEP2_PSK: + return "WEP2"; + case WiFiEncryptionType.WIFI_AUTH_WPA_WPA2_PSK: + return "WPA/WEP2"; + case WiFiEncryptionType.WIFI_AUTH_WPA2_ENTERPRISE: + return "WEP2 Enterprise"; + case WiFiEncryptionType.WIFI_AUTH_OPEN: + return "None"; + default: + return "Unknown"; + } +} diff --git a/interface/src/wifi/WiFiSettingsController.tsx b/interface/src/wifi/WiFiSettingsController.tsx new file mode 100644 index 0000000..d0613f8 --- /dev/null +++ b/interface/src/wifi/WiFiSettingsController.tsx @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; + +import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import WiFiSettingsForm from './WiFiSettingsForm'; +import { WIFI_SETTINGS_ENDPOINT } from '../api'; +import { WiFiSettings } from './types'; + +type WiFiSettingsControllerProps = RestControllerProps; + +class WiFiSettingsController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ); + } + +} + +export default restController(WIFI_SETTINGS_ENDPOINT, WiFiSettingsController); diff --git a/interface/src/wifi/WiFiSettingsForm.tsx b/interface/src/wifi/WiFiSettingsForm.tsx new file mode 100644 index 0000000..04aea28 --- /dev/null +++ b/interface/src/wifi/WiFiSettingsForm.tsx @@ -0,0 +1,200 @@ +import React, { Fragment } from 'react'; +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; + +import { Checkbox, List, ListItem, ListItemText, ListItemAvatar, ListItemSecondaryAction } from '@material-ui/core'; + +import Avatar from '@material-ui/core/Avatar'; +import IconButton from '@material-ui/core/IconButton'; +import LockIcon from '@material-ui/icons/Lock'; +import LockOpenIcon from '@material-ui/icons/LockOpen'; +import DeleteIcon from '@material-ui/icons/Delete'; +import SaveIcon from '@material-ui/icons/Save'; + +import { RestFormProps, PasswordValidator, BlockFormControlLabel, FormActions, FormButton } from '../components'; +import { isIP, isHostname, optional } from '../validators'; + +import { WiFiConnectionContext } from './WiFiConnectionContext'; +import { isNetworkOpen, networkSecurityMode } from './WiFiSecurityModes'; +import { WiFiSettings } from './types'; + +type WiFiStatusFormProps = RestFormProps; + +class WiFiSettingsForm extends React.Component { + + static contextType = WiFiConnectionContext; + context!: React.ContextType; + + constructor(props: WiFiStatusFormProps, context: WiFiConnectionContext) { + super(props); + + const { selectedNetwork } = context; + if (selectedNetwork) { + const wifiSettings: WiFiSettings = { + ssid: selectedNetwork.ssid, + password: "", + hostname: props.data.hostname, + static_ip_config: false, + } + props.setData(wifiSettings); + } + } + + componentWillMount() { + ValidatorForm.addValidationRule('isIP', isIP); + ValidatorForm.addValidationRule('isHostname', isHostname); + ValidatorForm.addValidationRule('isOptionalIP', optional(isIP)); + } + + deselectNetworkAndLoadData = () => { + this.context.deselectNetwork(); + this.props.loadData(); + } + + componentWillUnmount() { + this.context.deselectNetwork(); + } + + render() { + const { selectedNetwork, deselectNetwork } = this.context; + const { data, handleValueChange, saveData } = this.props; + return ( + + { + selectedNetwork ? + + + + + {isNetworkOpen(selectedNetwork) ? : } + + + + + + + + + + + : + + } + { + (!selectedNetwork || !isNetworkOpen(selectedNetwork)) && + + } + + + } + label="Static IP Config?" + /> + { + data.static_ip_config && + + + + + + + + } + + } variant="contained" color="primary" type="submit"> + Save + + + + ); + } +} + +export default WiFiSettingsForm; diff --git a/interface/src/wifi/WiFiStatus.ts b/interface/src/wifi/WiFiStatus.ts new file mode 100644 index 0000000..2d3574f --- /dev/null +++ b/interface/src/wifi/WiFiStatus.ts @@ -0,0 +1,41 @@ +import { Theme } from '@material-ui/core'; +import { WiFiStatus, WiFiConnectionStatus } from './types'; + +export const isConnected = ({ status }: WiFiStatus) => status === WiFiConnectionStatus.WIFI_STATUS_CONNECTED; + +export const wifiStatusHighlight = ({ status }: WiFiStatus, theme: Theme) => { + switch (status) { + case WiFiConnectionStatus.WIFI_STATUS_IDLE: + case WiFiConnectionStatus.WIFI_STATUS_DISCONNECTED: + case WiFiConnectionStatus.WIFI_STATUS_NO_SHIELD: + return theme.palette.info.main; + case WiFiConnectionStatus.WIFI_STATUS_CONNECTED: + return theme.palette.success.main; + case WiFiConnectionStatus.WIFI_STATUS_CONNECT_FAILED: + case WiFiConnectionStatus.WIFI_STATUS_CONNECTION_LOST: + return theme.palette.error.main; + default: + return theme.palette.warning.main; + } +} + +export const wifiStatus = ({ status }: WiFiStatus) => { + switch (status) { + case WiFiConnectionStatus.WIFI_STATUS_NO_SHIELD: + return "Inactive"; + case WiFiConnectionStatus.WIFI_STATUS_IDLE: + return "Idle"; + case WiFiConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: + return "No SSID Available"; + case WiFiConnectionStatus.WIFI_STATUS_CONNECTED: + return "Connected"; + case WiFiConnectionStatus.WIFI_STATUS_CONNECT_FAILED: + return "Connection Failed"; + case WiFiConnectionStatus.WIFI_STATUS_CONNECTION_LOST: + return "Connection Lost"; + case WiFiConnectionStatus.WIFI_STATUS_DISCONNECTED: + return "Disconnected"; + default: + return "Unknown"; + } +} diff --git a/interface/src/wifi/WiFiStatusController.tsx b/interface/src/wifi/WiFiStatusController.tsx new file mode 100644 index 0000000..2220595 --- /dev/null +++ b/interface/src/wifi/WiFiStatusController.tsx @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; + +import {restController, RestControllerProps, RestFormLoader, SectionContent } from '../components'; +import WiFiStatusForm from './WiFiStatusForm'; +import { WIFI_STATUS_ENDPOINT } from '../api'; +import { WiFiStatus } from './types'; + +type WiFiStatusControllerProps = RestControllerProps; + +class WiFiStatusController extends Component { + + componentDidMount() { + this.props.loadData(); + } + + render() { + return ( + + } + /> + + ); + } + +} + +export default restController(WIFI_STATUS_ENDPOINT, WiFiStatusController); diff --git a/interface/src/wifi/WiFiStatusForm.tsx b/interface/src/wifi/WiFiStatusForm.tsx new file mode 100644 index 0000000..7d5307c --- /dev/null +++ b/interface/src/wifi/WiFiStatusForm.tsx @@ -0,0 +1,117 @@ +import React, { Component, Fragment } from 'react'; + +import { WithTheme, withTheme } from '@material-ui/core/styles'; +import { Avatar, Divider, List, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'; + +import DNSIcon from '@material-ui/icons/Dns'; +import WifiIcon from '@material-ui/icons/Wifi'; +import SettingsInputComponentIcon from '@material-ui/icons/SettingsInputComponent'; +import SettingsInputAntennaIcon from '@material-ui/icons/SettingsInputAntenna'; +import DeviceHubIcon from '@material-ui/icons/DeviceHub'; +import RefreshIcon from '@material-ui/icons/Refresh'; + +import { RestFormProps, FormActions, FormButton, HighlightAvatar } from '../components'; +import { wifiStatus, wifiStatusHighlight, isConnected } from './WiFiStatus'; +import { WiFiStatus } from './types'; + +type WiFiStatusFormProps = RestFormProps & WithTheme; + +class WiFiStatusForm extends Component { + + dnsServers(status: WiFiStatus) { + if (!status.dns_ip_1) { + return "none"; + } + return status.dns_ip_1 + (status.dns_ip_2 ? ',' + status.dns_ip_2 : ''); + } + + createListItems() { + const { data, theme } = this.props + return ( + + + + + + + + + + + { + isConnected(data) && + + + + + + + + + + + + + IP + + + + + + + + + + + + + + + + # + + + + + + + + + + + + + + + + + + + + + + + + } + + ); + } + + render() { + return ( + + + {this.createListItems()} + + + } variant="contained" color="secondary" onClick={this.props.loadData}> + Refresh + + + + ); + } + +} + +export default withTheme(WiFiStatusForm); diff --git a/interface/src/wifi/types.ts b/interface/src/wifi/types.ts new file mode 100644 index 0000000..d631051 --- /dev/null +++ b/interface/src/wifi/types.ts @@ -0,0 +1,56 @@ +export enum WiFiConnectionStatus { + WIFI_STATUS_IDLE = 0, + WIFI_STATUS_NO_SSID_AVAIL = 1, + WIFI_STATUS_CONNECTED = 3, + WIFI_STATUS_CONNECT_FAILED = 4, + WIFI_STATUS_CONNECTION_LOST = 5, + WIFI_STATUS_DISCONNECTED = 6, + WIFI_STATUS_NO_SHIELD = 255 +} + +export enum WiFiEncryptionType { + WIFI_AUTH_OPEN = 0, + WIFI_AUTH_WEP = 1, + WIFI_AUTH_WEP_PSK = 2, + WIFI_AUTH_WEP2_PSK = 3, + WIFI_AUTH_WPA_WPA2_PSK = 4, + WIFI_AUTH_WPA2_ENTERPRISE = 5 +} + +export interface WiFiStatus { + status: WiFiConnectionStatus; + local_ip: string; + mac_address: string; + rssi: number; + ssid: string; + bssid: string; + channel: number; + subnet_mask: string; + gateway_ip: string; + dns_ip_1: string; + dns_ip_2: string; +} + +export interface WiFiSettings { + ssid: string; + password: string; + hostname: string; + static_ip_config: boolean; + local_ip?: string; + gateway_ip?: string; + subnet_mask?: string; + dns_ip_1?: string; + dns_ip_2?: string; +} + +export interface WiFiNetworkList { + networks: WiFiNetwork[]; +} + +export interface WiFiNetwork { + rssi: number; + ssid: string; + bssid: string; + channel: number; + encryption_type: WiFiEncryptionType; +} diff --git a/interface/tsconfig.json b/interface/tsconfig.json new file mode 100644 index 0000000..f2850b7 --- /dev/null +++ b/interface/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react" + }, + "include": [ + "src" + ] +} diff --git a/lib/framework/APSettingsService.cpp b/lib/framework/APSettingsService.cpp new file mode 100644 index 0000000..42732f0 --- /dev/null +++ b/lib/framework/APSettingsService.cpp @@ -0,0 +1,83 @@ +#include + +APSettingsService::APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : + _httpEndpoint(APSettings::read, APSettings::update, this, server, AP_SETTINGS_SERVICE_PATH, securityManager), + _fsPersistence(APSettings::read, APSettings::update, this, fs, AP_SETTINGS_FILE), + _dnsServer(nullptr), + _lastManaged(0), + _reconfigureAp(false) { + addUpdateHandler([&](const String& originId) { reconfigureAP(); }, false); +} + +void APSettingsService::begin() { + _fsPersistence.readFromFS(); + reconfigureAP(); +} + +void APSettingsService::reconfigureAP() { + _lastManaged = millis() - MANAGE_NETWORK_DELAY; + _reconfigureAp = true; +} + +void APSettingsService::loop() { + unsigned long currentMillis = millis(); + unsigned long manageElapsed = (unsigned long)(currentMillis - _lastManaged); + if (manageElapsed >= MANAGE_NETWORK_DELAY) { + _lastManaged = currentMillis; + manageAP(); + } + handleDNS(); +} + +void APSettingsService::manageAP() { + WiFiMode_t currentWiFiMode = WiFi.getMode(); + if (_state.provisionMode == AP_MODE_ALWAYS || + (_state.provisionMode == AP_MODE_DISCONNECTED && WiFi.status() != WL_CONNECTED)) { + if (_reconfigureAp || currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) { + startAP(); + } + } else if ((currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA) && + (_reconfigureAp || !WiFi.softAPgetStationNum())) { + stopAP(); + } + _reconfigureAp = false; +} + +void APSettingsService::startAP() { + Serial.println(F("Starting software access point")); + WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask); + WiFi.softAP(_state.ssid.c_str(), _state.password.c_str()); + if (!_dnsServer) { + IPAddress apIp = WiFi.softAPIP(); + Serial.print(F("Starting captive portal on ")); + Serial.println(apIp); + _dnsServer = new DNSServer; + _dnsServer->start(DNS_PORT, "*", apIp); + } +} + +void APSettingsService::stopAP() { + if (_dnsServer) { + Serial.println(F("Stopping captive portal")); + _dnsServer->stop(); + delete _dnsServer; + _dnsServer = nullptr; + } + Serial.println(F("Stopping software access point")); + WiFi.softAPdisconnect(true); +} + +void APSettingsService::handleDNS() { + if (_dnsServer) { + _dnsServer->processNextRequest(); + } +} + +APNetworkStatus APSettingsService::getAPNetworkStatus() { + WiFiMode_t currentWiFiMode = WiFi.getMode(); + bool apActive = currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA; + if (apActive && _state.provisionMode != AP_MODE_ALWAYS && WiFi.status() == WL_CONNECTED) { + return APNetworkStatus::LINGERING; + } + return apActive ? APNetworkStatus::ACTIVE : APNetworkStatus::INACTIVE; +} diff --git a/lib/framework/APSettingsService.h b/lib/framework/APSettingsService.h new file mode 100644 index 0000000..9104615 --- /dev/null +++ b/lib/framework/APSettingsService.h @@ -0,0 +1,123 @@ +#ifndef APSettingsConfig_h +#define APSettingsConfig_h + +#include +#include +#include + +#include +#include + +#define MANAGE_NETWORK_DELAY 10000 + +#define AP_MODE_ALWAYS 0 +#define AP_MODE_DISCONNECTED 1 +#define AP_MODE_NEVER 2 + +#define DNS_PORT 53 + +#ifndef FACTORY_AP_PROVISION_MODE +#define FACTORY_AP_PROVISION_MODE AP_MODE_DISCONNECTED +#endif + +#ifndef FACTORY_AP_SSID +#define FACTORY_AP_SSID "ESP8266-React" +#endif + +#ifndef FACTORY_AP_PASSWORD +#define FACTORY_AP_PASSWORD "esp-react" +#endif + +#ifndef FACTORY_AP_LOCAL_IP +#define FACTORY_AP_LOCAL_IP "192.168.4.1" +#endif + +#ifndef FACTORY_AP_GATEWAY_IP +#define FACTORY_AP_GATEWAY_IP "192.168.4.1" +#endif + +#ifndef FACTORY_AP_SUBNET_MASK +#define FACTORY_AP_SUBNET_MASK "255.255.255.0" +#endif + +#define AP_SETTINGS_FILE "/config/apSettings.json" +#define AP_SETTINGS_SERVICE_PATH "/rest/apSettings" + +enum APNetworkStatus { ACTIVE = 0, INACTIVE, LINGERING }; + +class APSettings { + public: + uint8_t provisionMode; + String ssid; + String password; + IPAddress localIP; + IPAddress gatewayIP; + IPAddress subnetMask; + + bool operator==(const APSettings& settings) const { + return provisionMode == settings.provisionMode && ssid == settings.ssid && password == settings.password && + localIP == settings.localIP && gatewayIP == settings.gatewayIP && subnetMask == settings.subnetMask; + } + + static void read(APSettings& settings, JsonObject& root) { + root["provision_mode"] = settings.provisionMode; + root["ssid"] = settings.ssid; + root["password"] = settings.password; + root["local_ip"] = settings.localIP.toString(); + root["gateway_ip"] = settings.gatewayIP.toString(); + root["subnet_mask"] = settings.subnetMask.toString(); + } + + static StateUpdateResult update(JsonObject& root, APSettings& settings) { + APSettings newSettings = {}; + newSettings.provisionMode = root["provision_mode"] | FACTORY_AP_PROVISION_MODE; + switch (settings.provisionMode) { + case AP_MODE_ALWAYS: + case AP_MODE_DISCONNECTED: + case AP_MODE_NEVER: + break; + default: + newSettings.provisionMode = AP_MODE_ALWAYS; + } + newSettings.ssid = root["ssid"] | FACTORY_AP_SSID; + newSettings.password = root["password"] | FACTORY_AP_PASSWORD; + + JsonUtils::readIP(root, "local_ip", newSettings.localIP, FACTORY_AP_LOCAL_IP); + JsonUtils::readIP(root, "gateway_ip", newSettings.gatewayIP, FACTORY_AP_GATEWAY_IP); + JsonUtils::readIP(root, "subnet_mask", newSettings.subnetMask, FACTORY_AP_SUBNET_MASK); + + if (newSettings == settings) { + return StateUpdateResult::UNCHANGED; + } + settings = newSettings; + return StateUpdateResult::CHANGED; + } +}; + +class APSettingsService : public StatefulService { + public: + APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); + + void begin(); + void loop(); + APNetworkStatus getAPNetworkStatus(); + + private: + HttpEndpoint _httpEndpoint; + FSPersistence _fsPersistence; + + // for the captive portal + DNSServer* _dnsServer; + + // for the mangement delay loop + volatile unsigned long _lastManaged; + volatile boolean _reconfigureAp; + + void reconfigureAP(); + void manageAP(); + void startAP(); + void stopAP(); + void handleDNS(); +}; + +#endif // end APSettingsConfig_h diff --git a/lib/framework/APStatus.cpp b/lib/framework/APStatus.cpp new file mode 100644 index 0000000..5bfe300 --- /dev/null +++ b/lib/framework/APStatus.cpp @@ -0,0 +1,22 @@ +#include + +APStatus::APStatus(AsyncWebServer* server, SecurityManager* securityManager, APSettingsService* apSettingsService) : + _apSettingsService(apSettingsService) { + server->on(AP_STATUS_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), + AuthenticationPredicates::IS_AUTHENTICATED)); +} + +void APStatus::apStatus(AsyncWebServerRequest* request) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_AP_STATUS_SIZE); + JsonObject root = response->getRoot(); + + root["status"] = _apSettingsService->getAPNetworkStatus(); + root["ip_address"] = WiFi.softAPIP().toString(); + root["mac_address"] = WiFi.softAPmacAddress(); + root["station_num"] = WiFi.softAPgetStationNum(); + + response->setLength(); + request->send(response); +} diff --git a/lib/framework/APStatus.h b/lib/framework/APStatus.h new file mode 100644 index 0000000..12620b0 --- /dev/null +++ b/lib/framework/APStatus.h @@ -0,0 +1,31 @@ +#ifndef APStatus_h +#define APStatus_h + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +#define MAX_AP_STATUS_SIZE 1024 +#define AP_STATUS_SERVICE_PATH "/rest/apStatus" + +class APStatus { + public: + APStatus(AsyncWebServer* server, SecurityManager* securityManager, APSettingsService* apSettingsService); + + private: + APSettingsService* _apSettingsService; + void apStatus(AsyncWebServerRequest* request); +}; + +#endif // end APStatus_h diff --git a/lib/framework/ArduinoJsonJWT.cpp b/lib/framework/ArduinoJsonJWT.cpp new file mode 100644 index 0000000..8b449e1 --- /dev/null +++ b/lib/framework/ArduinoJsonJWT.cpp @@ -0,0 +1,144 @@ +#include "ArduinoJsonJWT.h" + +ArduinoJsonJWT::ArduinoJsonJWT(String secret) : _secret(secret) { +} + +void ArduinoJsonJWT::setSecret(String secret) { + _secret = secret; +} + +String ArduinoJsonJWT::getSecret() { + return _secret; +} + +/* + * ESP32 uses mbedtls, ESP2866 uses bearssl. + * + * Both come with decent HMAC implmentations supporting sha256, as well as others. + * + * No need to pull in additional crypto libraries - lets use what we already have. + */ +String ArduinoJsonJWT::sign(String& payload) { + unsigned char hmacResult[32]; + { +#ifdef ESP32 + mbedtls_md_context_t ctx; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1); + mbedtls_md_hmac_starts(&ctx, (unsigned char*)_secret.c_str(), _secret.length()); + mbedtls_md_hmac_update(&ctx, (unsigned char*)payload.c_str(), payload.length()); + mbedtls_md_hmac_finish(&ctx, hmacResult); + mbedtls_md_free(&ctx); +#elif defined(ESP8266) + br_hmac_key_context keyCtx; + br_hmac_key_init(&keyCtx, &br_sha256_vtable, _secret.c_str(), _secret.length()); + br_hmac_context hmacCtx; + br_hmac_init(&hmacCtx, &keyCtx, 0); + br_hmac_update(&hmacCtx, payload.c_str(), payload.length()); + br_hmac_out(&hmacCtx, hmacResult); +#endif + } + return encode((char*)hmacResult, 32); +} + +String ArduinoJsonJWT::buildJWT(JsonObject& payload) { + // serialize, then encode payload + String jwt; + serializeJson(payload, jwt); + jwt = encode(jwt.c_str(), jwt.length()); + + // add the header to payload + jwt = JWT_HEADER + '.' + jwt; + + // add signature + jwt += '.' + sign(jwt); + + return jwt; +} + +void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument& jsonDocument) { + // clear json document before we begin, jsonDocument wil be null on failure + jsonDocument.clear(); + + // must have the correct header and delimiter + if (!jwt.startsWith(JWT_HEADER) || jwt.indexOf('.') != JWT_HEADER_SIZE) { + return; + } + + // check there is a signature delimieter + int signatureDelimiterIndex = jwt.lastIndexOf('.'); + if (signatureDelimiterIndex == JWT_HEADER_SIZE) { + return; + } + + // check the signature is valid + String signature = jwt.substring(signatureDelimiterIndex + 1); + jwt = jwt.substring(0, signatureDelimiterIndex); + if (sign(jwt) != signature) { + return; + } + + // decode payload + jwt = jwt.substring(JWT_HEADER_SIZE + 1); + jwt = decode(jwt); + + // parse payload, clearing json document after failure + DeserializationError error = deserializeJson(jsonDocument, jwt); + if (error != DeserializationError::Ok || !jsonDocument.is()) { + jsonDocument.clear(); + } +} + +String ArduinoJsonJWT::encode(const char* cstr, int inputLen) { + // prepare encoder + base64_encodestate _state; +#ifdef ESP32 + base64_init_encodestate(&_state); + size_t encodedLength = base64_encode_expected_len(inputLen) + 1; +#elif defined(ESP8266) + base64_init_encodestate_nonewlines(&_state); + size_t encodedLength = base64_encode_expected_len_nonewlines(inputLen) + 1; +#endif + // prepare buffer of correct length, returning an empty string on failure + char* buffer = (char*)malloc(encodedLength * sizeof(char)); + if (buffer == nullptr) { + return ""; + } + + // encode to buffer + int len = base64_encode_block(cstr, inputLen, &buffer[0], &_state); + len += base64_encode_blockend(&buffer[len], &_state); + buffer[len] = 0; + + // convert to arduino string, freeing buffer + String value = String(buffer); + free(buffer); + buffer = nullptr; + + // remove padding and convert to URL safe form + while (value.length() > 0 && value.charAt(value.length() - 1) == '=') { + value.remove(value.length() - 1); + } + value.replace('+', '-'); + value.replace('/', '_'); + + // return as string + return value; +} + +String ArduinoJsonJWT::decode(String value) { + // convert to standard base64 + value.replace('-', '+'); + value.replace('_', '/'); + + // prepare buffer of correct length + char buffer[base64_decode_expected_len(value.length()) + 1]; + + // decode + int len = base64_decode_chars(value.c_str(), value.length(), &buffer[0]); + buffer[len] = 0; + + // return as string + return String(buffer); +} diff --git a/lib/framework/ArduinoJsonJWT.h b/lib/framework/ArduinoJsonJWT.h new file mode 100644 index 0000000..beeedc0 --- /dev/null +++ b/lib/framework/ArduinoJsonJWT.h @@ -0,0 +1,37 @@ +#ifndef ArduinoJsonJWT_H +#define ArduinoJsonJWT_H + +#include +#include +#include +#include + +#ifdef ESP32 +#include +#elif defined(ESP8266) +#include +#endif + +class ArduinoJsonJWT { + private: + String _secret; + + const String JWT_HEADER = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; + const int JWT_HEADER_SIZE = JWT_HEADER.length(); + + String sign(String& value); + + static String encode(const char* cstr, int len); + static String decode(String value); + + public: + ArduinoJsonJWT(String secret); + + void setSecret(String secret); + String getSecret(); + + String buildJWT(JsonObject& payload); + void parseJWT(String jwt, JsonDocument& jsonDocument); +}; + +#endif diff --git a/lib/framework/AuthenticationService.cpp b/lib/framework/AuthenticationService.cpp new file mode 100644 index 0000000..84c347c --- /dev/null +++ b/lib/framework/AuthenticationService.cpp @@ -0,0 +1,48 @@ +#include + +#if FT_ENABLED(FT_SECURITY) + +AuthenticationService::AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager) : + _securityManager(securityManager), + _signInHandler(SIGN_IN_PATH, + std::bind(&AuthenticationService::signIn, this, std::placeholders::_1, std::placeholders::_2)) { + server->on(VERIFY_AUTHORIZATION_PATH, + HTTP_GET, + std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1)); + _signInHandler.setMethod(HTTP_POST); + _signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE); + server->addHandler(&_signInHandler); +} + +/** + * Verifys that the request supplied a valid JWT. + */ +void AuthenticationService::verifyAuthorization(AsyncWebServerRequest* request) { + Authentication authentication = _securityManager->authenticateRequest(request); + request->send(authentication.authenticated ? 200 : 401); +} + +/** + * Signs in a user if the username and password match. Provides a JWT to be used in the Authorization header in + * subsequent requests. + */ +void AuthenticationService::signIn(AsyncWebServerRequest* request, JsonVariant& json) { + if (json.is()) { + String username = json["username"]; + String password = json["password"]; + Authentication authentication = _securityManager->authenticate(username, password); + if (authentication.authenticated) { + User* user = authentication.user; + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_AUTHENTICATION_SIZE); + JsonObject jsonObject = response->getRoot(); + jsonObject["access_token"] = _securityManager->generateJWT(user); + response->setLength(); + request->send(response); + return; + } + } + AsyncWebServerResponse* response = request->beginResponse(401); + request->send(response); +} + +#endif // end FT_ENABLED(FT_SECURITY) diff --git a/lib/framework/AuthenticationService.h b/lib/framework/AuthenticationService.h new file mode 100644 index 0000000..8520223 --- /dev/null +++ b/lib/framework/AuthenticationService.h @@ -0,0 +1,30 @@ +#ifndef AuthenticationService_H_ +#define AuthenticationService_H_ + +#include +#include +#include +#include + +#define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization" +#define SIGN_IN_PATH "/rest/signIn" + +#define MAX_AUTHENTICATION_SIZE 256 + +#if FT_ENABLED(FT_SECURITY) + +class AuthenticationService { + public: + AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager); + + private: + SecurityManager* _securityManager; + AsyncCallbackJsonWebHandler _signInHandler; + + // endpoint functions + void signIn(AsyncWebServerRequest* request, JsonVariant& json); + void verifyAuthorization(AsyncWebServerRequest* request); +}; + +#endif // end FT_ENABLED(FT_SECURITY) +#endif // end SecurityManager_h diff --git a/lib/framework/ESP8266React.cpp b/lib/framework/ESP8266React.cpp new file mode 100644 index 0000000..5baed6d --- /dev/null +++ b/lib/framework/ESP8266React.cpp @@ -0,0 +1,114 @@ +#include + +ESP8266React::ESP8266React(AsyncWebServer* server) : + _featureService(server), + _securitySettingsService(server, &ESPFS), + _wifiSettingsService(server, &ESPFS, &_securitySettingsService), + _wifiScanner(server, &_securitySettingsService), + _wifiStatus(server, &_securitySettingsService), + _apSettingsService(server, &ESPFS, &_securitySettingsService), + _apStatus(server, &_securitySettingsService, &_apSettingsService), +#if FT_ENABLED(FT_NTP) + _ntpSettingsService(server, &ESPFS, &_securitySettingsService), + _ntpStatus(server, &_securitySettingsService), +#endif +#if FT_ENABLED(FT_OTA) + _otaSettingsService(server, &ESPFS, &_securitySettingsService), +#endif +#if FT_ENABLED(FT_UPLOAD_FIRMWARE) + _uploadFirmwareService(server, &_securitySettingsService), +#endif +#if FT_ENABLED(FT_MQTT) + _mqttSettingsService(server, &ESPFS, &_securitySettingsService), + _mqttStatus(server, &_mqttSettingsService, &_securitySettingsService), +#endif +#if FT_ENABLED(FT_SECURITY) + _authenticationService(server, &_securitySettingsService), +#endif + _restartService(server, &_securitySettingsService), + _factoryResetService(server, &ESPFS, &_securitySettingsService), + _systemStatus(server, &_securitySettingsService) { +#ifdef PROGMEM_WWW + // Serve static resources from PROGMEM + WWWData::registerRoutes( + [server, this](const String& uri, const String& contentType, const uint8_t* content, size_t len) { + ArRequestHandlerFunction requestHandler = [contentType, content, len](AsyncWebServerRequest* request) { + AsyncWebServerResponse* response = request->beginResponse_P(200, contentType, content, len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }; + server->on(uri.c_str(), HTTP_GET, requestHandler); + // Serving non matching get requests with "/index.html" + // OPTIONS get a straight up 200 response + if (uri.equals("/index.html")) { + server->onNotFound([requestHandler](AsyncWebServerRequest* request) { + if (request->method() == HTTP_GET) { + requestHandler(request); + } else if (request->method() == HTTP_OPTIONS) { + request->send(200); + } else { + request->send(404); + } + }); + } + }); +#else + // Serve static resources from /www/ + server->serveStatic("/js/", ESPFS, "/www/js/"); + server->serveStatic("/css/", ESPFS, "/www/css/"); + server->serveStatic("/fonts/", ESPFS, "/www/fonts/"); + server->serveStatic("/app/", ESPFS, "/www/app/"); + server->serveStatic("/favicon.ico", ESPFS, "/www/favicon.ico"); + // Serving all other get requests with "/www/index.htm" + // OPTIONS get a straight up 200 response + server->onNotFound([](AsyncWebServerRequest* request) { + if (request->method() == HTTP_GET) { + request->send(ESPFS, "/www/index.html"); + } else if (request->method() == HTTP_OPTIONS) { + request->send(200); + } else { + request->send(404); + } + }); +#endif + +// Disable CORS if required +#if defined(ENABLE_CORS) + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", CORS_ORIGIN); + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization"); + DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true"); +#endif +} + +void ESP8266React::begin() { +#ifdef ESP32 + ESPFS.begin(true); +#elif defined(ESP8266) + ESPFS.begin(); +#endif + _wifiSettingsService.begin(); + _apSettingsService.begin(); +#if FT_ENABLED(FT_NTP) + _ntpSettingsService.begin(); +#endif +#if FT_ENABLED(FT_OTA) + _otaSettingsService.begin(); +#endif +#if FT_ENABLED(FT_MQTT) + _mqttSettingsService.begin(); +#endif +#if FT_ENABLED(FT_SECURITY) + _securitySettingsService.begin(); +#endif +} + +void ESP8266React::loop() { + _wifiSettingsService.loop(); + _apSettingsService.loop(); +#if FT_ENABLED(FT_OTA) + _otaSettingsService.loop(); +#endif +#if FT_ENABLED(FT_MQTT) + _mqttSettingsService.loop(); +#endif +} diff --git a/lib/framework/ESP8266React.h b/lib/framework/ESP8266React.h new file mode 100644 index 0000000..b1daf8a --- /dev/null +++ b/lib/framework/ESP8266React.h @@ -0,0 +1,122 @@ +#ifndef ESP8266React_h +#define ESP8266React_h + +#include + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PROGMEM_WWW +#include +#endif + +class ESP8266React { + public: + ESP8266React(AsyncWebServer* server); + + void begin(); + void loop(); + + FS* getFS() { + return &ESPFS; + } + + SecurityManager* getSecurityManager() { + return &_securitySettingsService; + } + +#if FT_ENABLED(FT_SECURITY) + StatefulService* getSecuritySettingsService() { + return &_securitySettingsService; + } +#endif + + StatefulService* getWiFiSettingsService() { + return &_wifiSettingsService; + } + + StatefulService* getAPSettingsService() { + return &_apSettingsService; + } + +#if FT_ENABLED(FT_NTP) + StatefulService* getNTPSettingsService() { + return &_ntpSettingsService; + } +#endif + +#if FT_ENABLED(FT_OTA) + StatefulService* getOTASettingsService() { + return &_otaSettingsService; + } +#endif + +#if FT_ENABLED(FT_MQTT) + StatefulService* getMqttSettingsService() { + return &_mqttSettingsService; + } + + AsyncMqttClient* getMqttClient() { + return _mqttSettingsService.getMqttClient(); + } +#endif + + void factoryReset() { + _factoryResetService.factoryReset(); + } + + private: + FeaturesService _featureService; + SecuritySettingsService _securitySettingsService; + WiFiSettingsService _wifiSettingsService; + WiFiScanner _wifiScanner; + WiFiStatus _wifiStatus; + APSettingsService _apSettingsService; + APStatus _apStatus; +#if FT_ENABLED(FT_NTP) + NTPSettingsService _ntpSettingsService; + NTPStatus _ntpStatus; +#endif +#if FT_ENABLED(FT_OTA) + OTASettingsService _otaSettingsService; +#endif +#if FT_ENABLED(FT_UPLOAD_FIRMWARE) + UploadFirmwareService _uploadFirmwareService; +#endif +#if FT_ENABLED(FT_MQTT) + MqttSettingsService _mqttSettingsService; + MqttStatus _mqttStatus; +#endif +#if FT_ENABLED(FT_SECURITY) + AuthenticationService _authenticationService; +#endif + RestartService _restartService; + FactoryResetService _factoryResetService; + SystemStatus _systemStatus; +}; + +#endif diff --git a/lib/framework/ESPFS.h b/lib/framework/ESPFS.h new file mode 100644 index 0000000..7585f02 --- /dev/null +++ b/lib/framework/ESPFS.h @@ -0,0 +1,7 @@ +#ifdef ESP32 +#include +#define ESPFS SPIFFS +#elif defined(ESP8266) +#include +#define ESPFS LittleFS +#endif diff --git a/lib/framework/ESPUtils.h b/lib/framework/ESPUtils.h new file mode 100644 index 0000000..834459d --- /dev/null +++ b/lib/framework/ESPUtils.h @@ -0,0 +1,17 @@ +#ifndef ESPUtils_h +#define ESPUtils_h + +#include + +class ESPUtils { + public: + static String defaultDeviceValue(String prefix = "") { +#ifdef ESP32 + return prefix + String((unsigned long)ESP.getEfuseMac(), HEX); +#elif defined(ESP8266) + return prefix + String(ESP.getChipId(), HEX); +#endif + } +}; + +#endif // end ESPUtils diff --git a/lib/framework/FSPersistence.h b/lib/framework/FSPersistence.h new file mode 100644 index 0000000..9fc547b --- /dev/null +++ b/lib/framework/FSPersistence.h @@ -0,0 +1,98 @@ +#ifndef FSPersistence_h +#define FSPersistence_h + +#include +#include + +template +class FSPersistence { + public: + FSPersistence(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + FS* fs, + const char* filePath, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + _stateReader(stateReader), + _stateUpdater(stateUpdater), + _statefulService(statefulService), + _fs(fs), + _filePath(filePath), + _bufferSize(bufferSize), + _updateHandlerId(0) { + enableUpdateHandler(); + } + + void readFromFS() { + File settingsFile = _fs->open(_filePath, "r"); + + if (settingsFile) { + DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize); + DeserializationError error = deserializeJson(jsonDocument, settingsFile); + if (error == DeserializationError::Ok && jsonDocument.is()) { + JsonObject jsonObject = jsonDocument.as(); + _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); + settingsFile.close(); + return; + } + settingsFile.close(); + } + + // If we reach here we have not been successful in loading the config, + // hard-coded emergency defaults are now applied. + applyDefaults(); + } + + bool writeToFS() { + // create and populate a new json object + DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize); + JsonObject jsonObject = jsonDocument.to(); + _statefulService->read(jsonObject, _stateReader); + + // serialize it to filesystem + File settingsFile = _fs->open(_filePath, "w"); + + // failed to open file, return false + if (!settingsFile) { + return false; + } + + // serialize the data to the file + serializeJson(jsonDocument, settingsFile); + settingsFile.close(); + return true; + } + + void disableUpdateHandler() { + if (_updateHandlerId) { + _statefulService->removeUpdateHandler(_updateHandlerId); + _updateHandlerId = 0; + } + } + + void enableUpdateHandler() { + if (!_updateHandlerId) { + _updateHandlerId = _statefulService->addUpdateHandler([&](const String& originId) { writeToFS(); }); + } + } + + private: + JsonStateReader _stateReader; + JsonStateUpdater _stateUpdater; + StatefulService* _statefulService; + FS* _fs; + const char* _filePath; + size_t _bufferSize; + update_handler_id_t _updateHandlerId; + + protected: + // We assume the updater supplies sensible defaults if an empty object + // is supplied, this virtual function allows that to be changed. + virtual void applyDefaults() { + DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize); + JsonObject jsonObject = jsonDocument.as(); + _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); + } +}; + +#endif // end FSPersistence diff --git a/lib/framework/FactoryResetService.cpp b/lib/framework/FactoryResetService.cpp new file mode 100644 index 0000000..9742207 --- /dev/null +++ b/lib/framework/FactoryResetService.cpp @@ -0,0 +1,37 @@ +#include + +using namespace std::placeholders; + +FactoryResetService::FactoryResetService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : fs(fs) { + server->on(FACTORY_RESET_SERVICE_PATH, + HTTP_POST, + securityManager->wrapRequest(std::bind(&FactoryResetService::handleRequest, this, _1), + AuthenticationPredicates::IS_ADMIN)); +} + +void FactoryResetService::handleRequest(AsyncWebServerRequest* request) { + request->onDisconnect(std::bind(&FactoryResetService::factoryReset, this)); + request->send(200); +} + +/** + * Delete function assumes that all files are stored flat, within the config directory. + */ +void FactoryResetService::factoryReset() { +#ifdef ESP32 + File root = fs->open(FS_CONFIG_DIRECTORY); + File file; + while (file = root.openNextFile()) { + fs->remove(file.name()); + } +#elif defined(ESP8266) + Dir configDirectory = fs->openDir(FS_CONFIG_DIRECTORY); + while (configDirectory.next()) { + String path = FS_CONFIG_DIRECTORY; + path.concat("/"); + path.concat(configDirectory.fileName()); + fs->remove(path); + } +#endif + RestartService::restartNow(); +} diff --git a/lib/framework/FactoryResetService.h b/lib/framework/FactoryResetService.h new file mode 100644 index 0000000..2336e6f --- /dev/null +++ b/lib/framework/FactoryResetService.h @@ -0,0 +1,32 @@ +#ifndef FactoryResetService_h +#define FactoryResetService_h + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include +#include + +#define FS_CONFIG_DIRECTORY "/config" +#define FACTORY_RESET_SERVICE_PATH "/rest/factoryReset" + +class FactoryResetService { + FS* fs; + + public: + FactoryResetService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); + + void factoryReset(); + + private: + void handleRequest(AsyncWebServerRequest* request); +}; + +#endif // end FactoryResetService_h diff --git a/lib/framework/Features.h b/lib/framework/Features.h new file mode 100644 index 0000000..2de82c5 --- /dev/null +++ b/lib/framework/Features.h @@ -0,0 +1,37 @@ +#ifndef Features_h +#define Features_h + +#define FT_ENABLED(feature) feature + +// project feature off by default +#ifndef FT_PROJECT +#define FT_PROJECT 0 +#endif + +// security feature on by default +#ifndef FT_SECURITY +#define FT_SECURITY 1 +#endif + +// mqtt feature on by default +#ifndef FT_MQTT +#define FT_MQTT 1 +#endif + +// ntp feature on by default +#ifndef FT_NTP +#define FT_NTP 1 +#endif + +// mqtt feature on by default +#ifndef FT_OTA +#define FT_OTA 1 +#endif + +// upload firmware feature off by default +#ifndef FT_UPLOAD_FIRMWARE +#define FT_UPLOAD_FIRMWARE 0 +#endif + + +#endif diff --git a/lib/framework/FeaturesService.cpp b/lib/framework/FeaturesService.cpp new file mode 100644 index 0000000..095f1f2 --- /dev/null +++ b/lib/framework/FeaturesService.cpp @@ -0,0 +1,42 @@ +#include + +FeaturesService::FeaturesService(AsyncWebServer* server) { + server->on(FEATURES_SERVICE_PATH, HTTP_GET, std::bind(&FeaturesService::features, this, std::placeholders::_1)); +} + +void FeaturesService::features(AsyncWebServerRequest* request) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_FEATURES_SIZE); + JsonObject root = response->getRoot(); +#if FT_ENABLED(FT_PROJECT) + root["project"] = true; +#else + root["project"] = false; +#endif +#if FT_ENABLED(FT_SECURITY) + root["security"] = true; +#else + root["security"] = false; +#endif +#if FT_ENABLED(FT_MQTT) + root["mqtt"] = true; +#else + root["mqtt"] = false; +#endif +#if FT_ENABLED(FT_NTP) + root["ntp"] = true; +#else + root["ntp"] = false; +#endif +#if FT_ENABLED(FT_OTA) + root["ota"] = true; +#else + root["ota"] = false; +#endif +#if FT_ENABLED(FT_UPLOAD_FIRMWARE) + root["upload_firmware"] = true; +#else + root["upload_firmware"] = false; +#endif + response->setLength(); + request->send(response); +} diff --git a/lib/framework/FeaturesService.h b/lib/framework/FeaturesService.h new file mode 100644 index 0000000..867101e --- /dev/null +++ b/lib/framework/FeaturesService.h @@ -0,0 +1,29 @@ +#ifndef FeaturesService_h +#define FeaturesService_h + +#include + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include + +#define MAX_FEATURES_SIZE 256 +#define FEATURES_SERVICE_PATH "/rest/features" + +class FeaturesService { + public: + FeaturesService(AsyncWebServer* server); + + private: + void features(AsyncWebServerRequest* request); +}; + +#endif diff --git a/lib/framework/HttpEndpoint.h b/lib/framework/HttpEndpoint.h new file mode 100644 index 0000000..f45e716 --- /dev/null +++ b/lib/framework/HttpEndpoint.h @@ -0,0 +1,165 @@ +#ifndef HttpEndpoint_h +#define HttpEndpoint_h + +#include + +#include +#include + +#include +#include + +#define HTTP_ENDPOINT_ORIGIN_ID "http" + +template +class HttpGetEndpoint { + public: + HttpGetEndpoint(JsonStateReader stateReader, + StatefulService* statefulService, + AsyncWebServer* server, + const String& servicePath, + SecurityManager* securityManager, + AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + _stateReader(stateReader), _statefulService(statefulService), _bufferSize(bufferSize) { + server->on(servicePath.c_str(), + HTTP_GET, + securityManager->wrapRequest(std::bind(&HttpGetEndpoint::fetchSettings, this, std::placeholders::_1), + authenticationPredicate)); + } + + HttpGetEndpoint(JsonStateReader stateReader, + StatefulService* statefulService, + AsyncWebServer* server, + const String& servicePath, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + _stateReader(stateReader), _statefulService(statefulService), _bufferSize(bufferSize) { + server->on(servicePath.c_str(), HTTP_GET, std::bind(&HttpGetEndpoint::fetchSettings, this, std::placeholders::_1)); + } + + protected: + JsonStateReader _stateReader; + StatefulService* _statefulService; + size_t _bufferSize; + + void fetchSettings(AsyncWebServerRequest* request) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, _bufferSize); + JsonObject jsonObject = response->getRoot().to(); + _statefulService->read(jsonObject, _stateReader); + + response->setLength(); + request->send(response); + } +}; + +template +class HttpPostEndpoint { + public: + HttpPostEndpoint(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const String& servicePath, + SecurityManager* securityManager, + AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + _stateReader(stateReader), + _stateUpdater(stateUpdater), + _statefulService(statefulService), + _updateHandler( + servicePath, + securityManager->wrapCallback( + std::bind(&HttpPostEndpoint::updateSettings, this, std::placeholders::_1, std::placeholders::_2), + authenticationPredicate), + bufferSize), + _bufferSize(bufferSize) { + _updateHandler.setMethod(HTTP_POST); + server->addHandler(&_updateHandler); + } + + HttpPostEndpoint(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const String& servicePath, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + _stateReader(stateReader), + _stateUpdater(stateUpdater), + _statefulService(statefulService), + _updateHandler(servicePath, + std::bind(&HttpPostEndpoint::updateSettings, this, std::placeholders::_1, std::placeholders::_2), + bufferSize), + _bufferSize(bufferSize) { + _updateHandler.setMethod(HTTP_POST); + server->addHandler(&_updateHandler); + } + + protected: + JsonStateReader _stateReader; + JsonStateUpdater _stateUpdater; + StatefulService* _statefulService; + AsyncCallbackJsonWebHandler _updateHandler; + size_t _bufferSize; + + void updateSettings(AsyncWebServerRequest* request, JsonVariant& json) { + if (!json.is()) { + request->send(400); + return; + } + JsonObject jsonObject = json.as(); + StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); + if (outcome == StateUpdateResult::ERROR) { + request->send(400); + return; + } + if (outcome == StateUpdateResult::CHANGED) { + request->onDisconnect([this]() { _statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID); }); + } + AsyncJsonResponse* response = new AsyncJsonResponse(false, _bufferSize); + jsonObject = response->getRoot().to(); + _statefulService->read(jsonObject, _stateReader); + response->setLength(); + request->send(response); + } +}; + +template +class HttpEndpoint : public HttpGetEndpoint, public HttpPostEndpoint { + public: + HttpEndpoint(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const String& servicePath, + SecurityManager* securityManager, + AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + HttpGetEndpoint(stateReader, + statefulService, + server, + servicePath, + securityManager, + authenticationPredicate, + bufferSize), + HttpPostEndpoint(stateReader, + stateUpdater, + statefulService, + server, + servicePath, + securityManager, + authenticationPredicate, + bufferSize) { + } + + HttpEndpoint(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const String& servicePath, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + HttpGetEndpoint(stateReader, statefulService, server, servicePath, bufferSize), + HttpPostEndpoint(stateReader, stateUpdater, statefulService, server, servicePath, bufferSize) { + } +}; + +#endif // end HttpEndpoint diff --git a/lib/framework/JsonUtils.h b/lib/framework/JsonUtils.h new file mode 100644 index 0000000..0c40898 --- /dev/null +++ b/lib/framework/JsonUtils.h @@ -0,0 +1,29 @@ +#ifndef JsonUtils_h +#define JsonUtils_h + +#include +#include +#include + +class JsonUtils { + public: + static void readIP(JsonObject& root, const String& key, IPAddress& ip, const String& def) { + IPAddress defaultIp = {}; + if (!defaultIp.fromString(def)) { + defaultIp = INADDR_NONE; + } + readIP(root, key, ip, defaultIp); + } + static void readIP(JsonObject& root, const String& key, IPAddress& ip, const IPAddress& defaultIp = INADDR_NONE) { + if (!root[key].is() || !ip.fromString(root[key].as())) { + ip = defaultIp; + } + } + static void writeIP(JsonObject& root, const String& key, const IPAddress& ip) { + if (ip != INADDR_NONE) { + root[key] = ip.toString(); + } + } +}; + +#endif // end JsonUtils diff --git a/lib/framework/MqttPubSub.h b/lib/framework/MqttPubSub.h new file mode 100644 index 0000000..c3ed3f1 --- /dev/null +++ b/lib/framework/MqttPubSub.h @@ -0,0 +1,167 @@ +#ifndef MqttPubSub_h +#define MqttPubSub_h + +#include +#include + +#define MQTT_ORIGIN_ID "mqtt" + +template +class MqttConnector { + protected: + StatefulService* _statefulService; + AsyncMqttClient* _mqttClient; + size_t _bufferSize; + + MqttConnector(StatefulService* statefulService, AsyncMqttClient* mqttClient, size_t bufferSize) : + _statefulService(statefulService), _mqttClient(mqttClient), _bufferSize(bufferSize) { + _mqttClient->onConnect(std::bind(&MqttConnector::onConnect, this)); + } + + virtual void onConnect() = 0; + + public: + inline AsyncMqttClient* getMqttClient() const { + return _mqttClient; + } +}; + +template +class MqttPub : virtual public MqttConnector { + public: + MqttPub(JsonStateReader stateReader, + StatefulService* statefulService, + AsyncMqttClient* mqttClient, + const String& pubTopic = "", + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + MqttConnector(statefulService, mqttClient, bufferSize), _stateReader(stateReader), _pubTopic(pubTopic) { + MqttConnector::_statefulService->addUpdateHandler([&](const String& originId) { publish(); }, false); + } + + void setPubTopic(const String& pubTopic) { + _pubTopic = pubTopic; + publish(); + } + + protected: + virtual void onConnect() { + publish(); + } + + private: + JsonStateReader _stateReader; + String _pubTopic; + + void publish() { + if (_pubTopic.length() > 0 && MqttConnector::_mqttClient->connected()) { + // serialize to json doc + DynamicJsonDocument json(MqttConnector::_bufferSize); + JsonObject jsonObject = json.to(); + MqttConnector::_statefulService->read(jsonObject, _stateReader); + + // serialize to string + String payload; + serializeJson(json, payload); + + // publish the payload + MqttConnector::_mqttClient->publish(_pubTopic.c_str(), 0, false, payload.c_str()); + } + } +}; + +template +class MqttSub : virtual public MqttConnector { + public: + MqttSub(JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncMqttClient* mqttClient, + const String& subTopic = "", + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + MqttConnector(statefulService, mqttClient, bufferSize), _stateUpdater(stateUpdater), _subTopic(subTopic) { + MqttConnector::_mqttClient->onMessage(std::bind(&MqttSub::onMqttMessage, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5, + std::placeholders::_6)); + } + + void setSubTopic(const String& subTopic) { + if (!_subTopic.equals(subTopic)) { + // unsubscribe from the existing topic if one was set + if (_subTopic.length() > 0) { + MqttConnector::_mqttClient->unsubscribe(_subTopic.c_str()); + } + // set the new topic and re-configure the subscription + _subTopic = subTopic; + subscribe(); + } + } + + protected: + virtual void onConnect() { + subscribe(); + } + + private: + JsonStateUpdater _stateUpdater; + String _subTopic; + + void subscribe() { + if (_subTopic.length() > 0) { + MqttConnector::_mqttClient->subscribe(_subTopic.c_str(), 2); + } + } + + void onMqttMessage(char* topic, + char* payload, + AsyncMqttClientMessageProperties properties, + size_t len, + size_t index, + size_t total) { + // we only care about the topic we are watching in this class + if (strcmp(_subTopic.c_str(), topic)) { + return; + } + + // deserialize from string + DynamicJsonDocument json(MqttConnector::_bufferSize); + DeserializationError error = deserializeJson(json, payload, len); + if (!error && json.is()) { + JsonObject jsonObject = json.as(); + MqttConnector::_statefulService->update(jsonObject, _stateUpdater, MQTT_ORIGIN_ID); + } + } +}; + +template +class MqttPubSub : public MqttPub, public MqttSub { + public: + MqttPubSub(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncMqttClient* mqttClient, + const String& pubTopic = "", + const String& subTopic = "", + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + MqttConnector(statefulService, mqttClient, bufferSize), + MqttPub(stateReader, statefulService, mqttClient, pubTopic, bufferSize), + MqttSub(stateUpdater, statefulService, mqttClient, subTopic, bufferSize) { + } + + public: + void configureTopics(const String& pubTopic, const String& subTopic) { + MqttSub::setSubTopic(subTopic); + MqttPub::setPubTopic(pubTopic); + } + + protected: + void onConnect() { + MqttSub::onConnect(); + MqttPub::onConnect(); + } +}; + +#endif // end MqttPubSub diff --git a/lib/framework/MqttSettingsService.cpp b/lib/framework/MqttSettingsService.cpp new file mode 100644 index 0000000..a9932ae --- /dev/null +++ b/lib/framework/MqttSettingsService.cpp @@ -0,0 +1,161 @@ +#include + +/** + * Retains a copy of the cstr provided in the pointer provided using dynamic allocation. + * + * Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr. + */ +static char* retainCstr(const char* cstr, char** ptr) { + // free up previously retained value if exists + free(*ptr); + *ptr = nullptr; + + // dynamically allocate and copy cstr (if non null) + if (cstr != nullptr) { + *ptr = (char*)malloc(strlen(cstr) + 1); + strcpy(*ptr, cstr); + } + + // return reference to pointer for convenience + return *ptr; +} + +MqttSettingsService::MqttSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : + _httpEndpoint(MqttSettings::read, MqttSettings::update, this, server, MQTT_SETTINGS_SERVICE_PATH, securityManager), + _fsPersistence(MqttSettings::read, MqttSettings::update, this, fs, MQTT_SETTINGS_FILE), + _retainedHost(nullptr), + _retainedClientId(nullptr), + _retainedUsername(nullptr), + _retainedPassword(nullptr), + _reconfigureMqtt(false), + _disconnectedAt(0), + _disconnectReason(AsyncMqttClientDisconnectReason::TCP_DISCONNECTED), + _mqttClient() { +#ifdef ESP32 + WiFi.onEvent( + std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), + WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); + WiFi.onEvent(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), + WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); +#elif defined(ESP8266) + _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected( + std::bind(&MqttSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); + _onStationModeGotIPHandler = + WiFi.onStationModeGotIP(std::bind(&MqttSettingsService::onStationModeGotIP, this, std::placeholders::_1)); +#endif + _mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, std::placeholders::_1)); + _mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, std::placeholders::_1)); + addUpdateHandler([&](const String& originId) { onConfigUpdated(); }, false); +} + +MqttSettingsService::~MqttSettingsService() { +} + +void MqttSettingsService::begin() { + _fsPersistence.readFromFS(); +} + +void MqttSettingsService::loop() { + if (_reconfigureMqtt || (_disconnectedAt && (unsigned long)(millis() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) { + // reconfigure MQTT client + configureMqtt(); + + // clear the reconnection flags + _reconfigureMqtt = false; + _disconnectedAt = 0; + } +} + +bool MqttSettingsService::isEnabled() { + return _state.enabled; +} + +bool MqttSettingsService::isConnected() { + return _mqttClient.connected(); +} + +const char* MqttSettingsService::getClientId() { + return _mqttClient.getClientId(); +} + +AsyncMqttClientDisconnectReason MqttSettingsService::getDisconnectReason() { + return _disconnectReason; +} + +AsyncMqttClient* MqttSettingsService::getMqttClient() { + return &_mqttClient; +} + +void MqttSettingsService::onMqttConnect(bool sessionPresent) { + Serial.print(F("Connected to MQTT, ")); + if (sessionPresent) { + Serial.println(F("with persistent session")); + } else { + Serial.println(F("without persistent session")); + } +} + +void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { + Serial.print(F("Disconnected from MQTT reason: ")); + Serial.println((uint8_t)reason); + _disconnectReason = reason; + _disconnectedAt = millis(); +} + +void MqttSettingsService::onConfigUpdated() { + _reconfigureMqtt = true; + _disconnectedAt = 0; +} + +#ifdef ESP32 +void MqttSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { + if (_state.enabled) { + Serial.println(F("WiFi connection dropped, starting MQTT client.")); + onConfigUpdated(); + } +} + +void MqttSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { + if (_state.enabled) { + Serial.println(F("WiFi connection dropped, stopping MQTT client.")); + onConfigUpdated(); + } +} +#elif defined(ESP8266) +void MqttSettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) { + if (_state.enabled) { + Serial.println(F("WiFi connection dropped, starting MQTT client.")); + onConfigUpdated(); + } +} + +void MqttSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) { + if (_state.enabled) { + Serial.println(F("WiFi connection dropped, stopping MQTT client.")); + onConfigUpdated(); + } +} +#endif + +void MqttSettingsService::configureMqtt() { + // disconnect if currently connected + _mqttClient.disconnect(); + + // only connect if WiFi is connected and MQTT is enabled + if (_state.enabled && WiFi.isConnected()) { + Serial.println(F("Connecting to MQTT...")); + _mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port); + if (_state.username.length() > 0) { + _mqttClient.setCredentials( + retainCstr(_state.username.c_str(), &_retainedUsername), + retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword)); + } else { + _mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword)); + } + _mqttClient.setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId)); + _mqttClient.setKeepAlive(_state.keepAlive); + _mqttClient.setCleanSession(_state.cleanSession); + _mqttClient.setMaxTopicLength(_state.maxTopicLength); + _mqttClient.connect(); + } +} diff --git a/lib/framework/MqttSettingsService.h b/lib/framework/MqttSettingsService.h new file mode 100644 index 0000000..e6a0357 --- /dev/null +++ b/lib/framework/MqttSettingsService.h @@ -0,0 +1,156 @@ +#ifndef MqttSettingsService_h +#define MqttSettingsService_h + +#include +#include +#include +#include +#include + +#define MQTT_RECONNECTION_DELAY 5000 + +#define MQTT_SETTINGS_FILE "/config/mqttSettings.json" +#define MQTT_SETTINGS_SERVICE_PATH "/rest/mqttSettings" + +#ifndef FACTORY_MQTT_ENABLED +#define FACTORY_MQTT_ENABLED false +#endif + +#ifndef FACTORY_MQTT_HOST +#define FACTORY_MQTT_HOST "test.mosquitto.org" +#endif + +#ifndef FACTORY_MQTT_PORT +#define FACTORY_MQTT_PORT 1883 +#endif + +#ifndef FACTORY_MQTT_USERNAME +#define FACTORY_MQTT_USERNAME "" +#endif + +#ifndef FACTORY_MQTT_PASSWORD +#define FACTORY_MQTT_PASSWORD "" +#endif + +#ifndef FACTORY_MQTT_CLIENT_ID +#define FACTORY_MQTT_CLIENT_ID generateClientId() +#endif + +#ifndef FACTORY_MQTT_KEEP_ALIVE +#define FACTORY_MQTT_KEEP_ALIVE 16 +#endif + +#ifndef FACTORY_MQTT_CLEAN_SESSION +#define FACTORY_MQTT_CLEAN_SESSION true +#endif + +#ifndef FACTORY_MQTT_MAX_TOPIC_LENGTH +#define FACTORY_MQTT_MAX_TOPIC_LENGTH 128 +#endif + +static String generateClientId() { +#ifdef ESP32 + return ESPUtils::defaultDeviceValue("esp32-"); +#elif defined(ESP8266) + return ESPUtils::defaultDeviceValue("esp8266-"); +#endif +} + +class MqttSettings { + public: + // host and port - if enabled + bool enabled; + String host; + uint16_t port; + + // username and password + String username; + String password; + + // client id settings + String clientId; + + // connection settings + uint16_t keepAlive; + bool cleanSession; + uint16_t maxTopicLength; + + static void read(MqttSettings& settings, JsonObject& root) { + root["enabled"] = settings.enabled; + root["host"] = settings.host; + root["port"] = settings.port; + root["username"] = settings.username; + root["password"] = settings.password; + root["client_id"] = settings.clientId; + root["keep_alive"] = settings.keepAlive; + root["clean_session"] = settings.cleanSession; + root["max_topic_length"] = settings.maxTopicLength; + } + + static StateUpdateResult update(JsonObject& root, MqttSettings& settings) { + settings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED; + settings.host = root["host"] | FACTORY_MQTT_HOST; + settings.port = root["port"] | FACTORY_MQTT_PORT; + settings.username = root["username"] | FACTORY_MQTT_USERNAME; + settings.password = root["password"] | FACTORY_MQTT_PASSWORD; + settings.clientId = root["client_id"] | FACTORY_MQTT_CLIENT_ID; + settings.keepAlive = root["keep_alive"] | FACTORY_MQTT_KEEP_ALIVE; + settings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION; + settings.maxTopicLength = root["max_topic_length"] | FACTORY_MQTT_MAX_TOPIC_LENGTH; + return StateUpdateResult::CHANGED; + } +}; + +class MqttSettingsService : public StatefulService { + public: + MqttSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); + ~MqttSettingsService(); + + void begin(); + void loop(); + bool isEnabled(); + bool isConnected(); + const char* getClientId(); + AsyncMqttClientDisconnectReason getDisconnectReason(); + AsyncMqttClient* getMqttClient(); + + protected: + void onConfigUpdated(); + + private: + HttpEndpoint _httpEndpoint; + FSPersistence _fsPersistence; + + // Pointers to hold retained copies of the mqtt client connection strings. + // This is required as AsyncMqttClient holds refrences to the supplied connection strings. + char* _retainedHost; + char* _retainedClientId; + char* _retainedUsername; + char* _retainedPassword; + + // variable to help manage connection + bool _reconfigureMqtt; + unsigned long _disconnectedAt; + + // connection status + AsyncMqttClientDisconnectReason _disconnectReason; + + // the MQTT client instance + AsyncMqttClient _mqttClient; + +#ifdef ESP32 + void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); + void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); +#elif defined(ESP8266) + WiFiEventHandler _onStationModeDisconnectedHandler; + WiFiEventHandler _onStationModeGotIPHandler; + void onStationModeGotIP(const WiFiEventStationModeGotIP& event); + void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); +#endif + + void onMqttConnect(bool sessionPresent); + void onMqttDisconnect(AsyncMqttClientDisconnectReason reason); + void configureMqtt(); +}; + +#endif // end MqttSettingsService_h diff --git a/lib/framework/MqttStatus.cpp b/lib/framework/MqttStatus.cpp new file mode 100644 index 0000000..8f5bac3 --- /dev/null +++ b/lib/framework/MqttStatus.cpp @@ -0,0 +1,24 @@ +#include + +MqttStatus::MqttStatus(AsyncWebServer* server, + MqttSettingsService* mqttSettingsService, + SecurityManager* securityManager) : + _mqttSettingsService(mqttSettingsService) { + server->on(MQTT_STATUS_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&MqttStatus::mqttStatus, this, std::placeholders::_1), + AuthenticationPredicates::IS_AUTHENTICATED)); +} + +void MqttStatus::mqttStatus(AsyncWebServerRequest* request) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_MQTT_STATUS_SIZE); + JsonObject root = response->getRoot(); + + root["enabled"] = _mqttSettingsService->isEnabled(); + root["connected"] = _mqttSettingsService->isConnected(); + root["client_id"] = _mqttSettingsService->getClientId(); + root["disconnect_reason"] = (uint8_t)_mqttSettingsService->getDisconnectReason(); + + response->setLength(); + request->send(response); +} diff --git a/lib/framework/MqttStatus.h b/lib/framework/MqttStatus.h new file mode 100644 index 0000000..a726d3b --- /dev/null +++ b/lib/framework/MqttStatus.h @@ -0,0 +1,31 @@ +#ifndef MqttStatus_h +#define MqttStatus_h + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#define MAX_MQTT_STATUS_SIZE 1024 +#define MQTT_STATUS_SERVICE_PATH "/rest/mqttStatus" + +class MqttStatus { + public: + MqttStatus(AsyncWebServer* server, MqttSettingsService* mqttSettingsService, SecurityManager* securityManager); + + private: + MqttSettingsService* _mqttSettingsService; + + void mqttStatus(AsyncWebServerRequest* request); +}; + +#endif // end MqttStatus_h diff --git a/lib/framework/NTPSettingsService.cpp b/lib/framework/NTPSettingsService.cpp new file mode 100644 index 0000000..420db7f --- /dev/null +++ b/lib/framework/NTPSettingsService.cpp @@ -0,0 +1,90 @@ +#include + +NTPSettingsService::NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : + _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager), + _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE), + _timeHandler(TIME_PATH, + securityManager->wrapCallback( + std::bind(&NTPSettingsService::configureTime, this, std::placeholders::_1, std::placeholders::_2), + AuthenticationPredicates::IS_ADMIN)) { + _timeHandler.setMethod(HTTP_POST); + _timeHandler.setMaxContentLength(MAX_TIME_SIZE); + server->addHandler(&_timeHandler); +#ifdef ESP32 + WiFi.onEvent( + std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), + WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); + WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), + WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); +#elif defined(ESP8266) + _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected( + std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); + _onStationModeGotIPHandler = + WiFi.onStationModeGotIP(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1)); +#endif + addUpdateHandler([&](const String& originId) { configureNTP(); }, false); +} + +void NTPSettingsService::begin() { + _fsPersistence.readFromFS(); + configureNTP(); +} + +#ifdef ESP32 +void NTPSettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { + Serial.println(F("Got IP address, starting NTP Synchronization")); + configureNTP(); +} + +void NTPSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { + Serial.println(F("WiFi connection dropped, stopping NTP.")); + configureNTP(); +} +#elif defined(ESP8266) +void NTPSettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) { + Serial.println(F("Got IP address, starting NTP Synchronization")); + configureNTP(); +} + +void NTPSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) { + Serial.println(F("WiFi connection dropped, stopping NTP.")); + configureNTP(); +} +#endif + +void NTPSettingsService::configureNTP() { + if (WiFi.isConnected() && _state.enabled) { + Serial.println(F("Starting NTP...")); +#ifdef ESP32 + configTzTime(_state.tzFormat.c_str(), _state.server.c_str()); +#elif defined(ESP8266) + configTime(_state.tzFormat.c_str(), _state.server.c_str()); +#endif + } else { +#ifdef ESP32 + setenv("TZ", _state.tzFormat.c_str(), 1); + tzset(); +#elif defined(ESP8266) + setTZ(_state.tzFormat.c_str()); +#endif + sntp_stop(); + } +} + +void NTPSettingsService::configureTime(AsyncWebServerRequest* request, JsonVariant& json) { + if (!sntp_enabled() && json.is()) { + String timeUtc = json["time_utc"]; + struct tm tm = {0}; + char* s = strptime(timeUtc.c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm); + if (s != nullptr) { + time_t time = mktime(&tm); + struct timeval now = {.tv_sec = time}; + settimeofday(&now, nullptr); + AsyncWebServerResponse* response = request->beginResponse(200); + request->send(response); + return; + } + } + AsyncWebServerResponse* response = request->beginResponse(400); + request->send(response); +} diff --git a/lib/framework/NTPSettingsService.h b/lib/framework/NTPSettingsService.h new file mode 100644 index 0000000..bf25ca4 --- /dev/null +++ b/lib/framework/NTPSettingsService.h @@ -0,0 +1,84 @@ +#ifndef NTPSettingsService_h +#define NTPSettingsService_h + +#include +#include + +#include +#ifdef ESP32 +#include +#elif defined(ESP8266) +#include +#endif + +#ifndef FACTORY_NTP_ENABLED +#define FACTORY_NTP_ENABLED true +#endif + +#ifndef FACTORY_NTP_TIME_ZONE_LABEL +#define FACTORY_NTP_TIME_ZONE_LABEL "Europe/London" +#endif + +#ifndef FACTORY_NTP_TIME_ZONE_FORMAT +#define FACTORY_NTP_TIME_ZONE_FORMAT "GMT0BST,M3.5.0/1,M10.5.0" +#endif + +#ifndef FACTORY_NTP_SERVER +#define FACTORY_NTP_SERVER "time.google.com" +#endif + +#define NTP_SETTINGS_FILE "/config/ntpSettings.json" +#define NTP_SETTINGS_SERVICE_PATH "/rest/ntpSettings" + +#define MAX_TIME_SIZE 256 +#define TIME_PATH "/rest/time" + +class NTPSettings { + public: + bool enabled; + String tzLabel; + String tzFormat; + String server; + + static void read(NTPSettings& settings, JsonObject& root) { + root["enabled"] = settings.enabled; + root["server"] = settings.server; + root["tz_label"] = settings.tzLabel; + root["tz_format"] = settings.tzFormat; + } + + static StateUpdateResult update(JsonObject& root, NTPSettings& settings) { + settings.enabled = root["enabled"] | FACTORY_NTP_ENABLED; + settings.server = root["server"] | FACTORY_NTP_SERVER; + settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL; + settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT; + return StateUpdateResult::CHANGED; + } +}; + +class NTPSettingsService : public StatefulService { + public: + NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); + + void begin(); + + private: + HttpEndpoint _httpEndpoint; + FSPersistence _fsPersistence; + AsyncCallbackJsonWebHandler _timeHandler; + +#ifdef ESP32 + void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); + void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); +#elif defined(ESP8266) + WiFiEventHandler _onStationModeDisconnectedHandler; + WiFiEventHandler _onStationModeGotIPHandler; + + void onStationModeGotIP(const WiFiEventStationModeGotIP& event); + void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); +#endif + void configureNTP(); + void configureTime(AsyncWebServerRequest* request, JsonVariant& json); +}; + +#endif // end NTPSettingsService_h diff --git a/lib/framework/NTPStatus.cpp b/lib/framework/NTPStatus.cpp new file mode 100644 index 0000000..2275d2f --- /dev/null +++ b/lib/framework/NTPStatus.cpp @@ -0,0 +1,40 @@ +#include + +NTPStatus::NTPStatus(AsyncWebServer* server, SecurityManager* securityManager) { + server->on(NTP_STATUS_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, std::placeholders::_1), + AuthenticationPredicates::IS_AUTHENTICATED)); +} + +String toISOString(tm* time, bool incOffset) { + char time_string[25]; + strftime(time_string, 25, incOffset ? "%FT%T%z" : "%FT%TZ", time); + return String(time_string); +} + +void NTPStatus::ntpStatus(AsyncWebServerRequest* request) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NTP_STATUS_SIZE); + JsonObject root = response->getRoot(); + + // grab the current instant in unix seconds + time_t now = time(nullptr); + + // only provide enabled/disabled status for now + root["status"] = sntp_enabled() ? 1 : 0; + + // the current time in UTC + root["time_utc"] = toISOString(gmtime(&now), false); + + // local time as ISO String with TZ + root["time_local"] = toISOString(localtime(&now), true); + + // the sntp server name + root["server"] = sntp_getservername(0); + + // device uptime in seconds + root["uptime"] = millis() / 1000; + + response->setLength(); + request->send(response); +} diff --git a/lib/framework/NTPStatus.h b/lib/framework/NTPStatus.h new file mode 100644 index 0000000..7bb9180 --- /dev/null +++ b/lib/framework/NTPStatus.h @@ -0,0 +1,31 @@ +#ifndef NTPStatus_h +#define NTPStatus_h + +#include +#ifdef ESP32 +#include +#include +#include +#elif defined(ESP8266) +#include +#include +#include +#endif + +#include +#include +#include +#include + +#define MAX_NTP_STATUS_SIZE 1024 +#define NTP_STATUS_SERVICE_PATH "/rest/ntpStatus" + +class NTPStatus { + public: + NTPStatus(AsyncWebServer* server, SecurityManager* securityManager); + + private: + void ntpStatus(AsyncWebServerRequest* request); +}; + +#endif // end NTPStatus_h diff --git a/lib/framework/OTASettingsService.cpp b/lib/framework/OTASettingsService.cpp new file mode 100644 index 0000000..073f78b --- /dev/null +++ b/lib/framework/OTASettingsService.cpp @@ -0,0 +1,71 @@ +#include + +OTASettingsService::OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : + _httpEndpoint(OTASettings::read, OTASettings::update, this, server, OTA_SETTINGS_SERVICE_PATH, securityManager), + _fsPersistence(OTASettings::read, OTASettings::update, this, fs, OTA_SETTINGS_FILE), + _arduinoOTA(nullptr) { +#ifdef ESP32 + WiFi.onEvent(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), + WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); +#elif defined(ESP8266) + _onStationModeGotIPHandler = + WiFi.onStationModeGotIP(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1)); +#endif + addUpdateHandler([&](const String& originId) { configureArduinoOTA(); }, false); +} + +void OTASettingsService::begin() { + _fsPersistence.readFromFS(); + configureArduinoOTA(); +} + +void OTASettingsService::loop() { + if (_state.enabled && _arduinoOTA) { + _arduinoOTA->handle(); + } +} + +void OTASettingsService::configureArduinoOTA() { + if (_arduinoOTA) { +#ifdef ESP32 + _arduinoOTA->end(); +#endif + delete _arduinoOTA; + _arduinoOTA = nullptr; + } + if (_state.enabled) { + Serial.println(F("Starting OTA Update Service...")); + _arduinoOTA = new ArduinoOTAClass; + _arduinoOTA->setPort(_state.port); + _arduinoOTA->setPassword(_state.password.c_str()); + _arduinoOTA->onStart([]() { Serial.println(F("Starting")); }); + _arduinoOTA->onEnd([]() { Serial.println(F("\r\nEnd")); }); + _arduinoOTA->onProgress([](unsigned int progress, unsigned int total) { + Serial.printf_P(PSTR("Progress: %u%%\r\n"), (progress / (total / 100))); + }); + _arduinoOTA->onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) + Serial.println(F("Auth Failed")); + else if (error == OTA_BEGIN_ERROR) + Serial.println(F("Begin Failed")); + else if (error == OTA_CONNECT_ERROR) + Serial.println(F("Connect Failed")); + else if (error == OTA_RECEIVE_ERROR) + Serial.println(F("Receive Failed")); + else if (error == OTA_END_ERROR) + Serial.println(F("End Failed")); + }); + _arduinoOTA->begin(); + } +} + +#ifdef ESP32 +void OTASettingsService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { + configureArduinoOTA(); +} +#elif defined(ESP8266) +void OTASettingsService::onStationModeGotIP(const WiFiEventStationModeGotIP& event) { + configureArduinoOTA(); +} +#endif diff --git a/lib/framework/OTASettingsService.h b/lib/framework/OTASettingsService.h new file mode 100644 index 0000000..c8d8609 --- /dev/null +++ b/lib/framework/OTASettingsService.h @@ -0,0 +1,72 @@ +#ifndef OTASettingsService_h +#define OTASettingsService_h + +#include +#include + +#ifdef ESP32 +#include +#elif defined(ESP8266) +#include +#endif + +#include +#include + +#ifndef FACTORY_OTA_PORT +#define FACTORY_OTA_PORT 8266 +#endif + +#ifndef FACTORY_OTA_PASSWORD +#define FACTORY_OTA_PASSWORD "esp-react" +#endif + +#ifndef FACTORY_OTA_ENABLED +#define FACTORY_OTA_ENABLED true +#endif + +#define OTA_SETTINGS_FILE "/config/otaSettings.json" +#define OTA_SETTINGS_SERVICE_PATH "/rest/otaSettings" + +class OTASettings { + public: + bool enabled; + int port; + String password; + + static void read(OTASettings& settings, JsonObject& root) { + root["enabled"] = settings.enabled; + root["port"] = settings.port; + root["password"] = settings.password; + } + + static StateUpdateResult update(JsonObject& root, OTASettings& settings) { + settings.enabled = root["enabled"] | FACTORY_OTA_ENABLED; + settings.port = root["port"] | FACTORY_OTA_PORT; + settings.password = root["password"] | FACTORY_OTA_PASSWORD; + return StateUpdateResult::CHANGED; + } +}; + +class OTASettingsService : public StatefulService { + public: + OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); + + void begin(); + void loop(); + + private: + HttpEndpoint _httpEndpoint; + FSPersistence _fsPersistence; + ArduinoOTAClass* _arduinoOTA; + + void configureArduinoOTA(); +#ifdef ESP32 + void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); +#elif defined(ESP8266) + WiFiEventHandler _onStationModeGotIPHandler; + void onStationModeGotIP(const WiFiEventStationModeGotIP& event); +#endif +}; + +#endif // end OTASettingsService_h diff --git a/lib/framework/RestartService.cpp b/lib/framework/RestartService.cpp new file mode 100644 index 0000000..9036e40 --- /dev/null +++ b/lib/framework/RestartService.cpp @@ -0,0 +1,13 @@ +#include + +RestartService::RestartService(AsyncWebServer* server, SecurityManager* securityManager) { + server->on(RESTART_SERVICE_PATH, + HTTP_POST, + securityManager->wrapRequest(std::bind(&RestartService::restart, this, std::placeholders::_1), + AuthenticationPredicates::IS_ADMIN)); +} + +void RestartService::restart(AsyncWebServerRequest* request) { + request->onDisconnect(RestartService::restartNow); + request->send(200); +} diff --git a/lib/framework/RestartService.h b/lib/framework/RestartService.h new file mode 100644 index 0000000..45a1008 --- /dev/null +++ b/lib/framework/RestartService.h @@ -0,0 +1,31 @@ +#ifndef RestartService_h +#define RestartService_h + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include + +#define RESTART_SERVICE_PATH "/rest/restart" + +class RestartService { + public: + RestartService(AsyncWebServer* server, SecurityManager* securityManager); + + static void restartNow() { + WiFi.disconnect(true); + delay(500); + ESP.restart(); + } + + private: + void restart(AsyncWebServerRequest* request); +}; + +#endif // end RestartService_h diff --git a/lib/framework/SecurityManager.h b/lib/framework/SecurityManager.h new file mode 100644 index 0000000..530ab81 --- /dev/null +++ b/lib/framework/SecurityManager.h @@ -0,0 +1,102 @@ +#ifndef SecurityManager_h +#define SecurityManager_h + +#include +#include +#include +#include +#include +#include + +#ifndef FACTORY_JWT_SECRET +#define FACTORY_JWT_SECRET ESPUtils::defaultDeviceValue() +#endif + +#define ACCESS_TOKEN_PARAMATER "access_token" + +#define AUTHORIZATION_HEADER "Authorization" +#define AUTHORIZATION_HEADER_PREFIX "Bearer " +#define AUTHORIZATION_HEADER_PREFIX_LEN 7 + +#define MAX_JWT_SIZE 128 + +class User { + public: + String username; + String password; + bool admin; + + public: + User(String username, String password, bool admin) : username(username), password(password), admin(admin) { + } +}; + +class Authentication { + public: + User* user; + boolean authenticated; + + public: + Authentication(User& user) : user(new User(user)), authenticated(true) { + } + Authentication() : user(nullptr), authenticated(false) { + } + ~Authentication() { + delete (user); + } +}; + +typedef std::function AuthenticationPredicate; + +class AuthenticationPredicates { + public: + static bool NONE_REQUIRED(Authentication& authentication) { + return true; + }; + static bool IS_AUTHENTICATED(Authentication& authentication) { + return authentication.authenticated; + }; + static bool IS_ADMIN(Authentication& authentication) { + return authentication.authenticated && authentication.user->admin; + }; +}; + +class SecurityManager { + public: +#if FT_ENABLED(FT_SECURITY) + /* + * Authenticate, returning the user if found + */ + virtual Authentication authenticate(const String& username, const String& password) = 0; + + /* + * Generate a JWT for the user provided + */ + virtual String generateJWT(User* user) = 0; + +#endif + + /* + * Check the request header for the Authorization token + */ + virtual Authentication authenticateRequest(AsyncWebServerRequest* request) = 0; + + /** + * Filter a request with the provided predicate, only returning true if the predicate matches. + */ + virtual ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate) = 0; + + /** + * Wrap the provided request to provide validation against an AuthenticationPredicate. + */ + virtual ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, + AuthenticationPredicate predicate) = 0; + + /** + * Wrap the provided json request callback to provide validation against an AuthenticationPredicate. + */ + virtual ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction onRequest, + AuthenticationPredicate predicate) = 0; +}; + +#endif // end SecurityManager_h diff --git a/lib/framework/SecuritySettingsService.cpp b/lib/framework/SecuritySettingsService.cpp new file mode 100644 index 0000000..87027db --- /dev/null +++ b/lib/framework/SecuritySettingsService.cpp @@ -0,0 +1,140 @@ +#include + +#if FT_ENABLED(FT_SECURITY) + +SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) : + _httpEndpoint(SecuritySettings::read, SecuritySettings::update, this, server, SECURITY_SETTINGS_PATH, this), + _fsPersistence(SecuritySettings::read, SecuritySettings::update, this, fs, SECURITY_SETTINGS_FILE), + _jwtHandler(FACTORY_JWT_SECRET) { + addUpdateHandler([&](const String& originId) { configureJWTHandler(); }, false); +} + +void SecuritySettingsService::begin() { + _fsPersistence.readFromFS(); + configureJWTHandler(); +} + +Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest* request) { + AsyncWebHeader* authorizationHeader = request->getHeader(AUTHORIZATION_HEADER); + if (authorizationHeader) { + String value = authorizationHeader->value(); + if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)) { + value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN); + return authenticateJWT(value); + } + } else if (request->hasParam(ACCESS_TOKEN_PARAMATER)) { + AsyncWebParameter* tokenParamater = request->getParam(ACCESS_TOKEN_PARAMATER); + String value = tokenParamater->value(); + return authenticateJWT(value); + } + return Authentication(); +} + +void SecuritySettingsService::configureJWTHandler() { + _jwtHandler.setSecret(_state.jwtSecret); +} + +Authentication SecuritySettingsService::authenticateJWT(String& jwt) { + DynamicJsonDocument payloadDocument(MAX_JWT_SIZE); + _jwtHandler.parseJWT(jwt, payloadDocument); + if (payloadDocument.is()) { + JsonObject parsedPayload = payloadDocument.as(); + String username = parsedPayload["username"]; + for (User _user : _state.users) { + if (_user.username == username && validatePayload(parsedPayload, &_user)) { + return Authentication(_user); + } + } + } + return Authentication(); +} + +Authentication SecuritySettingsService::authenticate(const String& username, const String& password) { + for (User _user : _state.users) { + if (_user.username == username && _user.password == password) { + return Authentication(_user); + } + } + return Authentication(); +} + +inline void populateJWTPayload(JsonObject& payload, User* user) { + payload["username"] = user->username; + payload["admin"] = user->admin; +} + +boolean SecuritySettingsService::validatePayload(JsonObject& parsedPayload, User* user) { + DynamicJsonDocument jsonDocument(MAX_JWT_SIZE); + JsonObject payload = jsonDocument.to(); + populateJWTPayload(payload, user); + return payload == parsedPayload; +} + +String SecuritySettingsService::generateJWT(User* user) { + DynamicJsonDocument jsonDocument(MAX_JWT_SIZE); + JsonObject payload = jsonDocument.to(); + populateJWTPayload(payload, user); + return _jwtHandler.buildJWT(payload); +} + +ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) { + return [this, predicate](AsyncWebServerRequest* request) { + Authentication authentication = authenticateRequest(request); + return predicate(authentication); + }; +} + +ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest, + AuthenticationPredicate predicate) { + return [this, onRequest, predicate](AsyncWebServerRequest* request) { + Authentication authentication = authenticateRequest(request); + if (!predicate(authentication)) { + request->send(401); + return; + } + onRequest(request); + }; +} + +ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction onRequest, + AuthenticationPredicate predicate) { + return [this, onRequest, predicate](AsyncWebServerRequest* request, JsonVariant& json) { + Authentication authentication = authenticateRequest(request); + if (!predicate(authentication)) { + request->send(401); + return; + } + onRequest(request, json); + }; +} + +#else + +User ADMIN_USER = User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true); + +SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) : SecurityManager() { +} +SecuritySettingsService::~SecuritySettingsService() { +} + +ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) { + return [this, predicate](AsyncWebServerRequest* request) { return true; }; +} + +// Return the admin user on all request - disabling security features +Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest* request) { + return Authentication(ADMIN_USER); +} + +// Return the function unwrapped +ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest, + AuthenticationPredicate predicate) { + return onRequest; +} + +ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction onRequest, + AuthenticationPredicate predicate) { + return onRequest; +} + +#endif diff --git a/lib/framework/SecuritySettingsService.h b/lib/framework/SecuritySettingsService.h new file mode 100644 index 0000000..236bfe4 --- /dev/null +++ b/lib/framework/SecuritySettingsService.h @@ -0,0 +1,114 @@ +#ifndef SecuritySettingsService_h +#define SecuritySettingsService_h + +#include +#include +#include +#include + +#ifndef FACTORY_ADMIN_USERNAME +#define FACTORY_ADMIN_USERNAME "admin" +#endif + +#ifndef FACTORY_ADMIN_PASSWORD +#define FACTORY_ADMIN_PASSWORD "admin" +#endif + +#ifndef FACTORY_GUEST_USERNAME +#define FACTORY_GUEST_USERNAME "guest" +#endif + +#ifndef FACTORY_GUEST_PASSWORD +#define FACTORY_GUEST_PASSWORD "guest" +#endif + +#define SECURITY_SETTINGS_FILE "/config/securitySettings.json" +#define SECURITY_SETTINGS_PATH "/rest/securitySettings" + +#if FT_ENABLED(FT_SECURITY) + +class SecuritySettings { + public: + String jwtSecret; + std::list users; + + static void read(SecuritySettings& settings, JsonObject& root) { + // secret + root["jwt_secret"] = settings.jwtSecret; + + // users + JsonArray users = root.createNestedArray("users"); + for (User user : settings.users) { + JsonObject userRoot = users.createNestedObject(); + userRoot["username"] = user.username; + userRoot["password"] = user.password; + userRoot["admin"] = user.admin; + } + } + + static StateUpdateResult update(JsonObject& root, SecuritySettings& settings) { + // secret + settings.jwtSecret = root["jwt_secret"] | FACTORY_JWT_SECRET; + + // users + settings.users.clear(); + if (root["users"].is()) { + for (JsonVariant user : root["users"].as()) { + settings.users.push_back(User(user["username"], user["password"], user["admin"])); + } + } else { + settings.users.push_back(User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true)); + settings.users.push_back(User(FACTORY_GUEST_USERNAME, FACTORY_GUEST_PASSWORD, false)); + } + return StateUpdateResult::CHANGED; + } +}; + +class SecuritySettingsService : public StatefulService, public SecurityManager { + public: + SecuritySettingsService(AsyncWebServer* server, FS* fs); + + void begin(); + + // Functions to implement SecurityManager + Authentication authenticate(const String& username, const String& password); + Authentication authenticateRequest(AsyncWebServerRequest* request); + String generateJWT(User* user); + ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate); + ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate); + ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction callback, AuthenticationPredicate predicate); + + private: + HttpEndpoint _httpEndpoint; + FSPersistence _fsPersistence; + ArduinoJsonJWT _jwtHandler; + + void configureJWTHandler(); + + /* + * Lookup the user by JWT + */ + Authentication authenticateJWT(String& jwt); + + /* + * Verify the payload is correct + */ + boolean validatePayload(JsonObject& parsedPayload, User* user); +}; + +#else + +class SecuritySettingsService : public SecurityManager { + public: + SecuritySettingsService(AsyncWebServer* server, FS* fs); + ~SecuritySettingsService(); + + // minimal set of functions to support framework with security settings disabled + Authentication authenticateRequest(AsyncWebServerRequest* request); + ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate); + ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate); + ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction onRequest, AuthenticationPredicate predicate); +}; + +#endif // end FT_ENABLED(FT_SECURITY) +#endif // end SecuritySettingsService_h diff --git a/lib/framework/StatefulService.cpp b/lib/framework/StatefulService.cpp new file mode 100644 index 0000000..ece6b1f --- /dev/null +++ b/lib/framework/StatefulService.cpp @@ -0,0 +1,3 @@ +#include + +update_handler_id_t StateUpdateHandlerInfo::currentUpdatedHandlerId = 0; diff --git a/lib/framework/StatefulService.h b/lib/framework/StatefulService.h new file mode 100644 index 0000000..9a38e66 --- /dev/null +++ b/lib/framework/StatefulService.h @@ -0,0 +1,148 @@ +#ifndef StatefulService_h +#define StatefulService_h + +#include +#include + +#include +#include +#ifdef ESP32 +#include +#include +#endif + +#ifndef DEFAULT_BUFFER_SIZE +#define DEFAULT_BUFFER_SIZE 1024 +#endif + +enum class StateUpdateResult { + CHANGED = 0, // The update changed the state and propagation should take place if required + UNCHANGED, // The state was unchanged, propagation should not take place + ERROR // There was a problem updating the state, propagation should not take place +}; + +template +using JsonStateUpdater = std::function; + +template +using JsonStateReader = std::function; + +typedef size_t update_handler_id_t; +typedef std::function StateUpdateCallback; + +typedef struct StateUpdateHandlerInfo { + static update_handler_id_t currentUpdatedHandlerId; + update_handler_id_t _id; + StateUpdateCallback _cb; + bool _allowRemove; + StateUpdateHandlerInfo(StateUpdateCallback cb, bool allowRemove) : + _id(++currentUpdatedHandlerId), _cb(cb), _allowRemove(allowRemove){}; +} StateUpdateHandlerInfo_t; + +template +class StatefulService { + public: + template +#ifdef ESP32 + StatefulService(Args&&... args) : + _state(std::forward(args)...), _accessMutex(xSemaphoreCreateRecursiveMutex()) { + } +#else + StatefulService(Args&&... args) : _state(std::forward(args)...) { + } +#endif + + update_handler_id_t addUpdateHandler(StateUpdateCallback cb, bool allowRemove = true) { + if (!cb) { + return 0; + } + StateUpdateHandlerInfo_t updateHandler(cb, allowRemove); + _updateHandlers.push_back(updateHandler); + return updateHandler._id; + } + + void removeUpdateHandler(update_handler_id_t id) { + for (auto i = _updateHandlers.begin(); i != _updateHandlers.end();) { + if ((*i)._allowRemove && (*i)._id == id) { + i = _updateHandlers.erase(i); + } else { + ++i; + } + } + } + + StateUpdateResult update(std::function stateUpdater, const String& originId) { + beginTransaction(); + StateUpdateResult result = stateUpdater(_state); + endTransaction(); + if (result == StateUpdateResult::CHANGED) { + callUpdateHandlers(originId); + } + return result; + } + + StateUpdateResult updateWithoutPropagation(std::function stateUpdater) { + beginTransaction(); + StateUpdateResult result = stateUpdater(_state); + endTransaction(); + return result; + } + + StateUpdateResult update(JsonObject& jsonObject, JsonStateUpdater stateUpdater, const String& originId) { + beginTransaction(); + StateUpdateResult result = stateUpdater(jsonObject, _state); + endTransaction(); + if (result == StateUpdateResult::CHANGED) { + callUpdateHandlers(originId); + } + return result; + } + + StateUpdateResult updateWithoutPropagation(JsonObject& jsonObject, JsonStateUpdater stateUpdater) { + beginTransaction(); + StateUpdateResult result = stateUpdater(jsonObject, _state); + endTransaction(); + return result; + } + + void read(std::function stateReader) { + beginTransaction(); + stateReader(_state); + endTransaction(); + } + + void read(JsonObject& jsonObject, JsonStateReader stateReader) { + beginTransaction(); + stateReader(_state, jsonObject); + endTransaction(); + } + + void callUpdateHandlers(const String& originId) { + for (const StateUpdateHandlerInfo_t& updateHandler : _updateHandlers) { + updateHandler._cb(originId); + } + } + + protected: + T _state; + + inline void beginTransaction() { +#ifdef ESP32 + xSemaphoreTakeRecursive(_accessMutex, portMAX_DELAY); +#endif + } + + inline void endTransaction() { +#ifdef ESP32 + xSemaphoreGiveRecursive(_accessMutex); +#endif + } + + private: +#ifdef ESP32 + SemaphoreHandle_t _accessMutex; +#endif + std::list _updateHandlers; +}; + +#endif // end StatefulService_h diff --git a/lib/framework/SystemStatus.cpp b/lib/framework/SystemStatus.cpp new file mode 100644 index 0000000..fa637e5 --- /dev/null +++ b/lib/framework/SystemStatus.cpp @@ -0,0 +1,45 @@ +#include + +SystemStatus::SystemStatus(AsyncWebServer* server, SecurityManager* securityManager) { + server->on(SYSTEM_STATUS_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, std::placeholders::_1), + AuthenticationPredicates::IS_AUTHENTICATED)); +} + +void SystemStatus::systemStatus(AsyncWebServerRequest* request) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE); + JsonObject root = response->getRoot(); +#ifdef ESP32 + root["esp_platform"] = "esp32"; + root["max_alloc_heap"] = ESP.getMaxAllocHeap(); + root["psram_size"] = ESP.getPsramSize(); + root["free_psram"] = ESP.getFreePsram(); +#elif defined(ESP8266) + root["esp_platform"] = "esp8266"; + root["max_alloc_heap"] = ESP.getMaxFreeBlockSize(); + root["heap_fragmentation"] = ESP.getHeapFragmentation(); +#endif + root["cpu_freq_mhz"] = ESP.getCpuFreqMHz(); + root["free_heap"] = ESP.getFreeHeap(); + root["sketch_size"] = ESP.getSketchSize(); + root["free_sketch_space"] = ESP.getFreeSketchSpace(); + root["sdk_version"] = ESP.getSdkVersion(); + root["flash_chip_size"] = ESP.getFlashChipSize(); + root["flash_chip_speed"] = ESP.getFlashChipSpeed(); + +// TODO - Ideally this class will take an *FS and extract the file system information from there. +// ESP8266 and ESP32 do not have feature parity in FS.h which currently makes that difficult. +#ifdef ESP32 + root["fs_total"] = ESPFS.totalBytes(); + root["fs_used"] = ESPFS.usedBytes(); +#elif defined(ESP8266) + FSInfo fs_info; + ESPFS.info(fs_info); + root["fs_total"] = fs_info.totalBytes; + root["fs_used"] = fs_info.usedBytes; +#endif + + response->setLength(); + request->send(response); +} diff --git a/lib/framework/SystemStatus.h b/lib/framework/SystemStatus.h new file mode 100644 index 0000000..3175ec4 --- /dev/null +++ b/lib/framework/SystemStatus.h @@ -0,0 +1,29 @@ +#ifndef SystemStatus_h +#define SystemStatus_h + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#define MAX_ESP_STATUS_SIZE 1024 +#define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus" + +class SystemStatus { + public: + SystemStatus(AsyncWebServer* server, SecurityManager* securityManager); + + private: + void systemStatus(AsyncWebServerRequest* request); +}; + +#endif // end SystemStatus_h diff --git a/lib/framework/UploadFirmwareService.cpp b/lib/framework/UploadFirmwareService.cpp new file mode 100644 index 0000000..1858ace --- /dev/null +++ b/lib/framework/UploadFirmwareService.cpp @@ -0,0 +1,85 @@ +#include + +UploadFirmwareService::UploadFirmwareService(AsyncWebServer* server, SecurityManager* securityManager) : + _securityManager(securityManager) { + server->on(UPLOAD_FIRMWARE_PATH, + HTTP_POST, + std::bind(&UploadFirmwareService::uploadComplete, this, std::placeholders::_1), + std::bind(&UploadFirmwareService::handleUpload, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5, + std::placeholders::_6)); +#ifdef ESP8266 + Update.runAsync(true); +#endif +} + +void UploadFirmwareService::handleUpload(AsyncWebServerRequest* request, + const String& filename, + size_t index, + uint8_t* data, + size_t len, + bool final) { + if (!index) { + Authentication authentication = _securityManager->authenticateRequest(request); + if (AuthenticationPredicates::IS_ADMIN(authentication)) { + if (Update.begin(request->contentLength())) { + // success, let's make sure we end the update if the client hangs up + request->onDisconnect(UploadFirmwareService::handleEarlyDisconnect); + } else { + // failed to begin, send an error response + Update.printError(Serial); + handleError(request, 500); + } + } else { + // send the forbidden response + handleError(request, 403); + } + } + + // if we haven't delt with an error, continue with the update + if (!request->_tempObject) { + if (Update.write(data, len) != len) { + Update.printError(Serial); + handleError(request, 500); + } + if (final) { + if (!Update.end(true)) { + Update.printError(Serial); + handleError(request, 500); + } + } + } +} + +void UploadFirmwareService::uploadComplete(AsyncWebServerRequest* request) { + // if no error, send the success response + if (!request->_tempObject) { + request->onDisconnect(RestartService::restartNow); + AsyncWebServerResponse* response = request->beginResponse(200); + request->send(response); + } +} + +void UploadFirmwareService::handleError(AsyncWebServerRequest* request, int code) { + // if we have had an error already, do nothing + if (request->_tempObject) { + return; + } + // send the error code to the client and record the error code in the temp object + request->_tempObject = new int(code); + AsyncWebServerResponse* response = request->beginResponse(code); + request->send(response); +} + +void UploadFirmwareService::handleEarlyDisconnect() { +#ifdef ESP32 + Update.abort(); +#elif defined(ESP8266) + Update.end(); +#endif +} diff --git a/lib/framework/UploadFirmwareService.h b/lib/framework/UploadFirmwareService.h new file mode 100644 index 0000000..6312af1 --- /dev/null +++ b/lib/framework/UploadFirmwareService.h @@ -0,0 +1,38 @@ +#ifndef UploadFirmwareService_h +#define UploadFirmwareService_h + +#include + +#ifdef ESP32 +#include +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include + +#define UPLOAD_FIRMWARE_PATH "/rest/uploadFirmware" + +class UploadFirmwareService { + public: + UploadFirmwareService(AsyncWebServer* server, SecurityManager* securityManager); + + private: + SecurityManager* _securityManager; + void handleUpload(AsyncWebServerRequest* request, + const String& filename, + size_t index, + uint8_t* data, + size_t len, + bool final); + void uploadComplete(AsyncWebServerRequest* request); + void handleError(AsyncWebServerRequest* request, int code); + static void handleEarlyDisconnect(); +}; + +#endif // end UploadFirmwareService_h diff --git a/lib/framework/WebSocketTxRx.h b/lib/framework/WebSocketTxRx.h new file mode 100644 index 0000000..d2871ad --- /dev/null +++ b/lib/framework/WebSocketTxRx.h @@ -0,0 +1,273 @@ +#ifndef WebSocketTxRx_h +#define WebSocketTxRx_h + +#include +#include +#include + +#define WEB_SOCKET_CLIENT_ID_MSG_SIZE 128 + +#define WEB_SOCKET_ORIGIN "websocket" +#define WEB_SOCKET_ORIGIN_CLIENT_ID_PREFIX "websocket:" + +template +class WebSocketConnector { + protected: + StatefulService* _statefulService; + AsyncWebServer* _server; + AsyncWebSocket _webSocket; + size_t _bufferSize; + + WebSocketConnector(StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + SecurityManager* securityManager, + AuthenticationPredicate authenticationPredicate, + size_t bufferSize) : + _statefulService(statefulService), _server(server), _webSocket(webSocketPath), _bufferSize(bufferSize) { + _webSocket.setFilter(securityManager->filterRequest(authenticationPredicate)); + _webSocket.onEvent(std::bind(&WebSocketConnector::onWSEvent, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5, + std::placeholders::_6)); + _server->addHandler(&_webSocket); + _server->on(webSocketPath, HTTP_GET, std::bind(&WebSocketConnector::forbidden, this, std::placeholders::_1)); + } + + WebSocketConnector(StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + size_t bufferSize) : + _statefulService(statefulService), _server(server), _webSocket(webSocketPath), _bufferSize(bufferSize) { + _webSocket.onEvent(std::bind(&WebSocketConnector::onWSEvent, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5, + std::placeholders::_6)); + _server->addHandler(&_webSocket); + } + + virtual void onWSEvent(AsyncWebSocket* server, + AsyncWebSocketClient* client, + AwsEventType type, + void* arg, + uint8_t* data, + size_t len) = 0; + + String clientId(AsyncWebSocketClient* client) { + return WEB_SOCKET_ORIGIN_CLIENT_ID_PREFIX + String(client->id()); + } + + private: + void forbidden(AsyncWebServerRequest* request) { + request->send(403); + } +}; + +template +class WebSocketTx : virtual public WebSocketConnector { + public: + WebSocketTx(JsonStateReader stateReader, + StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + SecurityManager* securityManager, + AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + WebSocketConnector(statefulService, + server, + webSocketPath, + securityManager, + authenticationPredicate, + bufferSize), + _stateReader(stateReader) { + WebSocketConnector::_statefulService->addUpdateHandler( + [&](const String& originId) { transmitData(nullptr, originId); }, false); + } + + WebSocketTx(JsonStateReader stateReader, + StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + WebSocketConnector(statefulService, server, webSocketPath, bufferSize), _stateReader(stateReader) { + WebSocketConnector::_statefulService->addUpdateHandler( + [&](const String& originId) { transmitData(nullptr, originId); }, false); + } + + protected: + virtual void onWSEvent(AsyncWebSocket* server, + AsyncWebSocketClient* client, + AwsEventType type, + void* arg, + uint8_t* data, + size_t len) { + if (type == WS_EVT_CONNECT) { + // when a client connects, we transmit it's id and the current payload + transmitId(client); + transmitData(client, WEB_SOCKET_ORIGIN); + } + } + + private: + JsonStateReader _stateReader; + + void transmitId(AsyncWebSocketClient* client) { + DynamicJsonDocument jsonDocument = DynamicJsonDocument(WEB_SOCKET_CLIENT_ID_MSG_SIZE); + JsonObject root = jsonDocument.to(); + root["type"] = "id"; + root["id"] = WebSocketConnector::clientId(client); + size_t len = measureJson(jsonDocument); + AsyncWebSocketMessageBuffer* buffer = WebSocketConnector::_webSocket.makeBuffer(len); + if (buffer) { + serializeJson(jsonDocument, (char*)buffer->get(), len + 1); + client->text(buffer); + } + } + + /** + * Broadcasts the payload to the destination, if provided. Otherwise broadcasts to all clients except the origin, if + * specified. + * + * Original implementation sent clients their own IDs so they could ignore updates they initiated. This approach + * simplifies the client and the server implementation but may not be sufficent for all use-cases. + */ + void transmitData(AsyncWebSocketClient* client, const String& originId) { + DynamicJsonDocument jsonDocument = DynamicJsonDocument(WebSocketConnector::_bufferSize); + JsonObject root = jsonDocument.to(); + root["type"] = "payload"; + root["origin_id"] = originId; + JsonObject payload = root.createNestedObject("payload"); + WebSocketConnector::_statefulService->read(payload, _stateReader); + + size_t len = measureJson(jsonDocument); + AsyncWebSocketMessageBuffer* buffer = WebSocketConnector::_webSocket.makeBuffer(len); + if (buffer) { + serializeJson(jsonDocument, (char*)buffer->get(), len + 1); + if (client) { + client->text(buffer); + } else { + WebSocketConnector::_webSocket.textAll(buffer); + } + } + } +}; + +template +class WebSocketRx : virtual public WebSocketConnector { + public: + WebSocketRx(JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + SecurityManager* securityManager, + AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + WebSocketConnector(statefulService, + server, + webSocketPath, + securityManager, + authenticationPredicate, + bufferSize), + _stateUpdater(stateUpdater) { + } + + WebSocketRx(JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + WebSocketConnector(statefulService, server, webSocketPath, bufferSize), _stateUpdater(stateUpdater) { + } + + protected: + virtual void onWSEvent(AsyncWebSocket* server, + AsyncWebSocketClient* client, + AwsEventType type, + void* arg, + uint8_t* data, + size_t len) { + if (type == WS_EVT_DATA) { + AwsFrameInfo* info = (AwsFrameInfo*)arg; + if (info->final && info->index == 0 && info->len == len) { + if (info->opcode == WS_TEXT) { + DynamicJsonDocument jsonDocument = DynamicJsonDocument(WebSocketConnector::_bufferSize); + DeserializationError error = deserializeJson(jsonDocument, (char*)data); + if (!error && jsonDocument.is()) { + JsonObject jsonObject = jsonDocument.as(); + WebSocketConnector::_statefulService->update( + jsonObject, _stateUpdater, WebSocketConnector::clientId(client)); + } + } + } + } + } + + private: + JsonStateUpdater _stateUpdater; +}; + +template +class WebSocketTxRx : public WebSocketTx, public WebSocketRx { + public: + WebSocketTxRx(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + SecurityManager* securityManager, + AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + WebSocketConnector(statefulService, + server, + webSocketPath, + securityManager, + authenticationPredicate, + bufferSize), + WebSocketTx(stateReader, + statefulService, + server, + webSocketPath, + securityManager, + authenticationPredicate, + bufferSize), + WebSocketRx(stateUpdater, + statefulService, + server, + webSocketPath, + securityManager, + authenticationPredicate, + bufferSize) { + } + + WebSocketTxRx(JsonStateReader stateReader, + JsonStateUpdater stateUpdater, + StatefulService* statefulService, + AsyncWebServer* server, + const char* webSocketPath, + size_t bufferSize = DEFAULT_BUFFER_SIZE) : + WebSocketConnector(statefulService, server, webSocketPath, bufferSize), + WebSocketTx(stateReader, statefulService, server, webSocketPath, bufferSize), + WebSocketRx(stateUpdater, statefulService, server, webSocketPath, bufferSize) { + } + + protected: + void onWSEvent(AsyncWebSocket* server, + AsyncWebSocketClient* client, + AwsEventType type, + void* arg, + uint8_t* data, + size_t len) { + WebSocketRx::onWSEvent(server, client, type, arg, data, len); + WebSocketTx::onWSEvent(server, client, type, arg, data, len); + } +}; + +#endif diff --git a/lib/framework/WiFiScanner.cpp b/lib/framework/WiFiScanner.cpp new file mode 100644 index 0000000..a6f2b65 --- /dev/null +++ b/lib/framework/WiFiScanner.cpp @@ -0,0 +1,70 @@ +#include + +WiFiScanner::WiFiScanner(AsyncWebServer* server, SecurityManager* securityManager) { + server->on(SCAN_NETWORKS_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, std::placeholders::_1), + AuthenticationPredicates::IS_ADMIN)); + server->on(LIST_NETWORKS_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1), + AuthenticationPredicates::IS_ADMIN)); +}; + +void WiFiScanner::scanNetworks(AsyncWebServerRequest* request) { + if (WiFi.scanComplete() != -1) { + WiFi.scanDelete(); + WiFi.scanNetworks(true); + } + request->send(202); +} + +void WiFiScanner::listNetworks(AsyncWebServerRequest* request) { + int numNetworks = WiFi.scanComplete(); + if (numNetworks > -1) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_WIFI_SCANNER_SIZE); + JsonObject root = response->getRoot(); + JsonArray networks = root.createNestedArray("networks"); + for (int i = 0; i < numNetworks; i++) { + JsonObject network = networks.createNestedObject(); + network["rssi"] = WiFi.RSSI(i); + network["ssid"] = WiFi.SSID(i); + network["bssid"] = WiFi.BSSIDstr(i); + network["channel"] = WiFi.channel(i); +#ifdef ESP32 + network["encryption_type"] = (uint8_t)WiFi.encryptionType(i); +#elif defined(ESP8266) + network["encryption_type"] = convertEncryptionType(WiFi.encryptionType(i)); +#endif + } + response->setLength(); + request->send(response); + } else if (numNetworks == -1) { + request->send(202); + } else { + scanNetworks(request); + } +} + +#ifdef ESP8266 +/* + * Convert encryption type to standard used by ESP32 rather than the translated form which the esp8266 libaries expose. + * + * This allows us to use a single set of mappings in the UI. + */ +uint8_t WiFiScanner::convertEncryptionType(uint8_t encryptionType) { + switch (encryptionType) { + case ENC_TYPE_NONE: + return AUTH_OPEN; + case ENC_TYPE_WEP: + return AUTH_WEP; + case ENC_TYPE_TKIP: + return AUTH_WPA_PSK; + case ENC_TYPE_CCMP: + return AUTH_WPA2_PSK; + case ENC_TYPE_AUTO: + return AUTH_WPA_WPA2_PSK; + } + return -1; +} +#endif diff --git a/lib/framework/WiFiScanner.h b/lib/framework/WiFiScanner.h new file mode 100644 index 0000000..6f91030 --- /dev/null +++ b/lib/framework/WiFiScanner.h @@ -0,0 +1,35 @@ +#ifndef WiFiScanner_h +#define WiFiScanner_h + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include +#include + +#define SCAN_NETWORKS_SERVICE_PATH "/rest/scanNetworks" +#define LIST_NETWORKS_SERVICE_PATH "/rest/listNetworks" + +#define MAX_WIFI_SCANNER_SIZE 1024 + +class WiFiScanner { + public: + WiFiScanner(AsyncWebServer* server, SecurityManager* securityManager); + + private: + void scanNetworks(AsyncWebServerRequest* request); + void listNetworks(AsyncWebServerRequest* request); + +#ifdef ESP8266 + uint8_t convertEncryptionType(uint8_t encryptionType); +#endif +}; + +#endif // end WiFiScanner_h diff --git a/lib/framework/WiFiSettingsService.cpp b/lib/framework/WiFiSettingsService.cpp new file mode 100644 index 0000000..1c228c1 --- /dev/null +++ b/lib/framework/WiFiSettingsService.cpp @@ -0,0 +1,100 @@ +#include + +WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : + _httpEndpoint(WiFiSettings::read, WiFiSettings::update, this, server, WIFI_SETTINGS_SERVICE_PATH, securityManager), + _fsPersistence(WiFiSettings::read, WiFiSettings::update, this, fs, WIFI_SETTINGS_FILE), + _lastConnectionAttempt(0) { + // We want the device to come up in opmode=0 (WIFI_OFF), when erasing the flash this is not the default. + // If needed, we save opmode=0 before disabling persistence so the device boots with WiFi disabled in the future. + if (WiFi.getMode() != WIFI_OFF) { + WiFi.mode(WIFI_OFF); + } + + // Disable WiFi config persistance and auto reconnect + WiFi.persistent(false); + WiFi.setAutoReconnect(false); +#ifdef ESP32 + // Init the wifi driver on ESP32 + WiFi.mode(WIFI_MODE_MAX); + WiFi.mode(WIFI_MODE_NULL); + WiFi.onEvent( + std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), + WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); + WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeStop, this, std::placeholders::_1, std::placeholders::_2), + WiFiEvent_t::SYSTEM_EVENT_STA_STOP); +#elif defined(ESP8266) + _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected( + std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); +#endif + + addUpdateHandler([&](const String& originId) { reconfigureWiFiConnection(); }, false); +} + +void WiFiSettingsService::begin() { + _fsPersistence.readFromFS(); + reconfigureWiFiConnection(); +} + +void WiFiSettingsService::reconfigureWiFiConnection() { + // reset last connection attempt to force loop to reconnect immediately + _lastConnectionAttempt = 0; + +// disconnect and de-configure wifi +#ifdef ESP32 + if (WiFi.disconnect(true)) { + _stopping = true; + } +#elif defined(ESP8266) + WiFi.disconnect(true); +#endif +} + +void WiFiSettingsService::loop() { + unsigned long currentMillis = millis(); + if (!_lastConnectionAttempt || (unsigned long)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) { + _lastConnectionAttempt = currentMillis; + manageSTA(); + } +} + +void WiFiSettingsService::manageSTA() { + // Abort if already connected, or if we have no SSID + if (WiFi.isConnected() || _state.ssid.length() == 0) { + return; + } + // Connect or reconnect as required + if ((WiFi.getMode() & WIFI_STA) == 0) { + Serial.println(F("Connecting to WiFi.")); + if (_state.staticIPConfig) { + // configure for static IP + WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); + } else { + // configure for DHCP +#ifdef ESP32 + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + WiFi.setHostname(_state.hostname.c_str()); +#elif defined(ESP8266) + WiFi.config(INADDR_ANY, INADDR_ANY, INADDR_ANY); + WiFi.hostname(_state.hostname); +#endif + } + // attempt to connect to the network + WiFi.begin(_state.ssid.c_str(), _state.password.c_str()); + } +} + +#ifdef ESP32 +void WiFiSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { + WiFi.disconnect(true); +} +void WiFiSettingsService::onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info) { + if (_stopping) { + _lastConnectionAttempt = 0; + _stopping = false; + } +} +#elif defined(ESP8266) +void WiFiSettingsService::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) { + WiFi.disconnect(true); +} +#endif diff --git a/lib/framework/WiFiSettingsService.h b/lib/framework/WiFiSettingsService.h new file mode 100644 index 0000000..2b520bd --- /dev/null +++ b/lib/framework/WiFiSettingsService.h @@ -0,0 +1,110 @@ +#ifndef WiFiSettingsService_h +#define WiFiSettingsService_h + +#include +#include +#include +#include + +#define WIFI_SETTINGS_FILE "/config/wifiSettings.json" +#define WIFI_SETTINGS_SERVICE_PATH "/rest/wifiSettings" +#define WIFI_RECONNECTION_DELAY 1000 * 30 + +#ifndef FACTORY_WIFI_SSID +#define FACTORY_WIFI_SSID "" +#endif + +#ifndef FACTORY_WIFI_PASSWORD +#define FACTORY_WIFI_PASSWORD "" +#endif + +#ifndef FACTORY_WIFI_HOSTNAME +#define FACTORY_WIFI_HOSTNAME ESPUtils::defaultDeviceValue("esp-react-") +#endif + +class WiFiSettings { + public: + // core wifi configuration + String ssid; + String password; + String hostname; + bool staticIPConfig; + + // optional configuration for static IP address + IPAddress localIP; + IPAddress gatewayIP; + IPAddress subnetMask; + IPAddress dnsIP1; + IPAddress dnsIP2; + + static void read(WiFiSettings& settings, JsonObject& root) { + // connection settings + root["ssid"] = settings.ssid; + root["password"] = settings.password; + root["hostname"] = settings.hostname; + root["static_ip_config"] = settings.staticIPConfig; + + // extended settings + JsonUtils::writeIP(root, "local_ip", settings.localIP); + JsonUtils::writeIP(root, "gateway_ip", settings.gatewayIP); + JsonUtils::writeIP(root, "subnet_mask", settings.subnetMask); + JsonUtils::writeIP(root, "dns_ip_1", settings.dnsIP1); + JsonUtils::writeIP(root, "dns_ip_2", settings.dnsIP2); + } + + static StateUpdateResult update(JsonObject& root, WiFiSettings& settings) { + settings.ssid = root["ssid"] | FACTORY_WIFI_SSID; + settings.password = root["password"] | FACTORY_WIFI_PASSWORD; + settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME; + settings.staticIPConfig = root["static_ip_config"] | false; + + // extended settings + JsonUtils::readIP(root, "local_ip", settings.localIP); + JsonUtils::readIP(root, "gateway_ip", settings.gatewayIP); + JsonUtils::readIP(root, "subnet_mask", settings.subnetMask); + JsonUtils::readIP(root, "dns_ip_1", settings.dnsIP1); + JsonUtils::readIP(root, "dns_ip_2", settings.dnsIP2); + + // Swap around the dns servers if 2 is populated but 1 is not + if (settings.dnsIP1 == INADDR_NONE && settings.dnsIP2 != INADDR_NONE) { + settings.dnsIP1 = settings.dnsIP2; + settings.dnsIP2 = INADDR_NONE; + } + + // Turning off static ip config if we don't meet the minimum requirements + // of ipAddress, gateway and subnet. This may change to static ip only + // as sensible defaults can be assumed for gateway and subnet + if (settings.staticIPConfig && + (settings.localIP == INADDR_NONE || settings.gatewayIP == INADDR_NONE || settings.subnetMask == INADDR_NONE)) { + settings.staticIPConfig = false; + } + return StateUpdateResult::CHANGED; + } +}; + +class WiFiSettingsService : public StatefulService { + public: + WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); + + void begin(); + void loop(); + + private: + HttpEndpoint _httpEndpoint; + FSPersistence _fsPersistence; + unsigned long _lastConnectionAttempt; + +#ifdef ESP32 + bool _stopping; + void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); + void onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info); +#elif defined(ESP8266) + WiFiEventHandler _onStationModeDisconnectedHandler; + void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); +#endif + + void reconfigureWiFiConnection(); + void manageSTA(); +}; + +#endif // end WiFiSettingsService_h diff --git a/lib/framework/WiFiStatus.cpp b/lib/framework/WiFiStatus.cpp new file mode 100644 index 0000000..de69542 --- /dev/null +++ b/lib/framework/WiFiStatus.cpp @@ -0,0 +1,75 @@ +#include + +WiFiStatus::WiFiStatus(AsyncWebServer* server, SecurityManager* securityManager) { + server->on(WIFI_STATUS_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&WiFiStatus::wifiStatus, this, std::placeholders::_1), + AuthenticationPredicates::IS_AUTHENTICATED)); +#ifdef ESP32 + WiFi.onEvent(onStationModeConnected, WiFiEvent_t::SYSTEM_EVENT_STA_CONNECTED); + WiFi.onEvent(onStationModeDisconnected, WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); + WiFi.onEvent(onStationModeGotIP, WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); +#elif defined(ESP8266) + _onStationModeConnectedHandler = WiFi.onStationModeConnected(onStationModeConnected); + _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(onStationModeDisconnected); + _onStationModeGotIPHandler = WiFi.onStationModeGotIP(onStationModeGotIP); +#endif +} + +#ifdef ESP32 +void WiFiStatus::onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info) { + Serial.println(F("WiFi Connected.")); +} + +void WiFiStatus::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { + Serial.print(F("WiFi Disconnected. Reason code=")); + Serial.println(info.disconnected.reason); +} + +void WiFiStatus::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { + Serial.printf_P( + PSTR("WiFi Got IP. localIP=%s, hostName=%s\r\n"), WiFi.localIP().toString().c_str(), WiFi.getHostname()); +} +#elif defined(ESP8266) +void WiFiStatus::onStationModeConnected(const WiFiEventStationModeConnected& event) { + Serial.print(F("WiFi Connected. SSID=")); + Serial.println(event.ssid); +} + +void WiFiStatus::onStationModeDisconnected(const WiFiEventStationModeDisconnected& event) { + Serial.print(F("WiFi Disconnected. Reason code=")); + Serial.println(event.reason); +} + +void WiFiStatus::onStationModeGotIP(const WiFiEventStationModeGotIP& event) { + Serial.printf_P( + PSTR("WiFi Got IP. localIP=%s, hostName=%s\r\n"), event.ip.toString().c_str(), WiFi.hostname().c_str()); +} +#endif + +void WiFiStatus::wifiStatus(AsyncWebServerRequest* request) { + AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_WIFI_STATUS_SIZE); + JsonObject root = response->getRoot(); + wl_status_t status = WiFi.status(); + root["status"] = (uint8_t)status; + if (status == WL_CONNECTED) { + root["local_ip"] = WiFi.localIP().toString(); + root["mac_address"] = WiFi.macAddress(); + root["rssi"] = WiFi.RSSI(); + root["ssid"] = WiFi.SSID(); + root["bssid"] = WiFi.BSSIDstr(); + root["channel"] = WiFi.channel(); + root["subnet_mask"] = WiFi.subnetMask().toString(); + root["gateway_ip"] = WiFi.gatewayIP().toString(); + IPAddress dnsIP1 = WiFi.dnsIP(0); + IPAddress dnsIP2 = WiFi.dnsIP(1); + if (dnsIP1 != INADDR_NONE) { + root["dns_ip_1"] = dnsIP1.toString(); + } + if (dnsIP2 != INADDR_NONE) { + root["dns_ip_2"] = dnsIP2.toString(); + } + } + response->setLength(); + request->send(response); +} diff --git a/lib/framework/WiFiStatus.h b/lib/framework/WiFiStatus.h new file mode 100644 index 0000000..197bd64 --- /dev/null +++ b/lib/framework/WiFiStatus.h @@ -0,0 +1,45 @@ +#ifndef WiFiStatus_h +#define WiFiStatus_h + +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#define MAX_WIFI_STATUS_SIZE 1024 +#define WIFI_STATUS_SERVICE_PATH "/rest/wifiStatus" + +class WiFiStatus { + public: + WiFiStatus(AsyncWebServer* server, SecurityManager* securityManager); + + private: +#ifdef ESP32 + // static functions for logging WiFi events to the UART + static void onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info); + static void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); + static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); +#elif defined(ESP8266) + // handler refrences for logging important WiFi events over serial + WiFiEventHandler _onStationModeConnectedHandler; + WiFiEventHandler _onStationModeDisconnectedHandler; + WiFiEventHandler _onStationModeGotIPHandler; + // static functions for logging WiFi events to the UART + static void onStationModeConnected(const WiFiEventStationModeConnected& event); + static void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); + static void onStationModeGotIP(const WiFiEventStationModeGotIP& event); +#endif + + void wifiStatus(AsyncWebServerRequest* request); +}; + +#endif // end WiFiStatus_h diff --git a/lib/readme.txt b/lib/readme.txt new file mode 100644 index 0000000..dbadc3d --- /dev/null +++ b/lib/readme.txt @@ -0,0 +1,36 @@ + +This directory is intended for the project specific (private) libraries. +PlatformIO will compile them to static libraries and link to executable file. + +The source code of each library should be placed in separate directory, like +"lib/private_lib/[here are source files]". + +For example, see how can be organized `Foo` and `Bar` libraries: + +|--lib +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| |--Foo +| | |- Foo.c +| | |- Foo.h +| |- readme.txt --> THIS FILE +|- platformio.ini +|--src + |- main.c + +Then in `src/main.c` you should use: + +#include +#include + +// rest H/C/CPP code + +PlatformIO will find your libraries automatically, configure preprocessor's +include paths and build them. + +More information about PlatformIO Library Dependency Finder +- http://docs.platformio.org/page/librarymanager/ldf.html diff --git a/media/build.png b/media/build.png new file mode 100644 index 0000000000000000000000000000000000000000..33e807a93add396239ae3d22f59ffe568250b309 GIT binary patch literal 8646 zcmb7qcT^MDw=N1wkQ$JpQY0|qh%}Ynn}DLgNDW8`IEn-*Mmh;yK$^%X3;;#|W}&Fz!@9ck;j46F4<5jtZ2HVoz)LUbmK-bRpz zCw5lH(){fJ(y;+b1YvE_SMZ$Dy2aQU!n_tW^g3 zp8|}TiwwBzJ3s3NtweJxdTJS&I3CWfZw%r|`3*P^=}QA}vut;i0YX{N0B*Mnz?~BH z$&rab`h$rSDXPIB5QIJ4Htp|gu?Pmvxv@Xu2X|NO$m$KVgrC1&ymtXuGbv>@>E9(W zkzu9xeIlIH+q>&zEV-3ltJ;#MLtA_^u}2{gUa}U$5;KcTMs5cYCid21_yhAX3zu)0 zEeb&aIfZ$l#m->x>8Q`1-!);vQ1!`R56Xx~T0mpqs#hPLS}6#f*}92+3rZHB1>J+` zu{K;Nax1YsKWss}k%(@=H10IOa#9Bbp$XXt`VLA!9kRcb*>xg5p**3SIT-q;VhyyC zLtxxRTN^OK7qkhdCZ75`p99*O3L+-nL)WK!JX$j`+wX+;F4zhvWwUdnnTQ>=2`QEe z+`2z8Kdd#oULC`IW!lpP+ijZVg?ilw+uY5*?tcNi?$AOT{!?4}jQdjcAhB&fIZ1-$ zG&Sbt?(3({vY91UnIz4-7?=l#I7dgRtdwWArf+PDQO4o@78UZ6`IzbL4)V)wx=#r> z1gPk$?Vp$y0fU@8lOLM2IF#+xYaDjgx!>w0L@4BTtn}I){jwUSInpnCY(dFK&MA9p z8eNa&;`8;fVho@`(Q@&6oZ9BHb`@ALq)y@wxVw2|WLIJTV4S2t<~Yi6a2{1Xh@&0z zmkM1h5RNW3C8O!GIrh0Ia;gv%1DU~{Vr@NxdEC9r`5z1f%r*QXiEk9*{q?tj$A=#~ zpYksD6PPhE5*9XoZBpUIs~Bk_uT%lF-5R_h1_$SKxu=Q266NB>*YKm$D-33jmlXhCEPun^C8t$Cd_}BDVsEnYq!thaMWZ+EdA4j-W^HX$WUn>d?Iqig zaCO^%JGlNJPJIcgE+;yxSD83YBw=(V!Dw2KX>1(R1(hBbfNHB<>Ehpz*6=K1qlx$; zLaKhZU|ml^+o$7X%zhPt>x|%UI=45rnbYYc({E(CxoiT}XFnZx7QKql+a|j5tQx|a zC9N>a_yB{${3zGL*~Km?UsVi%Jlw0QFTJ5T*TBe;~?@l14K;ZK0Gwa3Csc;Dia(m65Kegxig zro`cl;L@#%O&i#?*GY=YHLpHrO=Yi0xl-DGE@J!>%hcTfw)bj<$H8WP{hV=?!Vtn)d9x7?)6EnuJcLij7Vrcd>gh} zy}oehXFyKoV8s6WwRP9<`y8t;dclSst9A5!p9B1wOMaS6CUPU3LiRlff%}M4n|DTG z6Kzs^w}Z%NMDhJf;CKJAvNd0b&NyOgk^t+o;tr#ZlazXNe3*uI_;=_=3^$X5_Tg|J zo0pr{g97k+8-%OzX5)*&Y|W2P2;BX+k8#0X;}$~@sR8AM*(BXCM$tMe&#|Y|6Y6M_G817f z!zm`f8Gtk`Qu&##JD1@f3j#vxq11?!&dI%$gUX8+P9A*J&b+zxqe$g!tx49_2gx+M zWBhtges6>Y9%Kq*Z)&LDykDf8V{9oT;Z4t>)1)L0O!+LAbBs6pLsIn;uYM0*|j*+0|GT#eyhZcO#?^ zX9ADtRcbx8wck`=KR~kJU6!ECWTxAui}kUmZ?s^@_z)BUYDsj^MeTi14MuHmZjMT6 zpDPn9?AO>CzUf~a%tXg>EsYV)soU)XFV6d`yshyDa)};P`sT}KCH!9Tmioj@3My?F z#gA!!wO-$h!aURtcsU{nRmFUmnYH1`%gd}u`n?N(EkD>{jW#CiAB9;@Z?ys?Hx(E4 zV>-@EZnmx6mfE$X$X$<65d?=zC2yv!j_O9&U}ScNC`jdx9bF!lpPcSBzoDm0L<|(v zzlhM@qBq_P5_){zz|!2s*8jI+NVQCAYW2G=jPBWYYUt^MSBP9dJ_pLo9#BlMqyX{CJq%{?UzqON*c zdnT=_zY)1`B4>e*apN-1OJnz(Hy@;j5<}>)sU|z0s$~~7Mob$<#{`nQ0>MCg(=_9} z3&-V$qHaqB5niO=W>kY8_&9s)?hpE|I7T3D~ddy)aY^gUXcyB=P_lzgXz1Q!Mxze@p zawC5cw>_%O$9HwC<;XM_7%u`Ipu0_+RF3C`|IGA*56I%YMBksEO6 zRf6x)ieXyhNVdm=H6o}VukhpDe%(uE0kF5a?soPx`1Of1vC$m-2#nDC%@^j2NlMOn zOrELFAr#Eh0i6d zj9`mNyO0oS#ryRu7cFDIUe#HYxomR$s3B4Z2v9W1S}1aCPjBJAl=Tk4K00fy=VxO# zV^@`j2`ze#kWnHjrk2ap&{}CHyW^hYEqL5%dUX(__N7<>+|BE<(v||}X&Sw8M*?Zo z9(^MZN$r&DQ&rP4=Vuq{#Y#X|cLI7g#fDl@&wQ{6McKuz((mVA*$Hj$1-`Ww_d;We zn^jZMNy@Z#xBb^+`JST`e=mlRFzh50swHp@@D}I7EEDA-0%rxy3wo>7CnlPMsq1E- zl6?7vvcBj{A>okmv@Z%q8fh~`y>kIpwO)@_j1@7-(rS#Y@`d`j=P7pd) z3lTo7(09$zfSELl$q357bV2iJ&QCVM`T_1aWdHB(oEa83yDI~_Sjw&Lx^sErMy4w+ zz`5p8MEH*8jT~knhh7E(MdmvjC&T{?!kdZ)9FTc^#S)b&{-W5j?A`~he7~2!nio8s zI6tnjF~e`w!jv@=yy}c=gLmJwA&)%3p#$UgH2kIvYGL@Yc}8e7l{QqKZ~MDQA^VQV_9TvOu!*Da zRnqJE=|sP+(5f;$o7uD2aUXL_UX|He0I-wNRJSRph}mDTV#KWJGpW*In41EDwWG?* zLBQjRM#0y5%*Uy{&)QQ6r&qsM7HWrXFP_k5gm@)~^jqY;d-pC~e=~3$-PmL%Vyu>r`4)4Q{m_OnPFKQ#h@R4pnuCTWm5|sp1$ZVk2l9zpPizIkqe5%se?K zrd^Ng40x(d;%@B~=Ozhz-=C0kPyRyaBX$UX^ON}fD*iy2<_8}U)tjN^l?Y!~)|VYH z5r$%L+1xZ-TLu!gmw~$^PhArxbUh2+Jo7=xwY++X6w0|d8;$CCtNzfq)(bVxJPzn!Ad*f#Q^x&g%82B)dF-(;q*W!e*_s% z)P^b`;bU>#)9h;W2mA-JT~)PS3HA0p%qTmP6vvbig5r_q4Q)TC$-Oo*;&u@`;y=3{ z&2#s6Y^0jzU;MIvfj7k=a<&z-q#@oJldSpK+Q}A)@0>@EO1Jr1_zaz?a8iC$@*+*% z7yyMU!+|1d>fx4Oc%S+NYz2W>sz410g(`+`Kf9i(pZ#{?BNxk(%goPwHoj*2v~PXA z!%F983FXS_j5ih>PTl922Q^a4R3i1!0^OOttSK@Qe{~N22gULqnDnpgX>CYSK8P7A zF^wqC(J$+jI^p}>+l2aNis8TEbl|_{AK~2`xBoPR$e-+MyPVBh&WUM8XIrYd(M2vk zuU@NAPlv`3u5^)EcU~P;92oz0nq8Z~-Zmo3NpHgG$zo-7!kZDWtgEpVK54o)c(T+Y zSQdHCgRl&@%;2wvno9*vt6;3B>yV3}>>=SjC(Hl`Cg=VG@_x3Lw@rTJc$r=_GE@@IC(SOUMC+z0dMFoWv zMq+Ik1tBB-=_ddj`4%*AS;?QHYHnt#gsh!x5&PwM)w$jfNy_tF?rg0tt&v;3yLqc) zwGqRhQk;<@;Y|O;=;aNHu>_iYK`(^t`lGsG9Yeob^Uqw^6l`0kikvs_vg^Sx2j*_| zckQ`XJ{y?u%}q*Ke~3>Wzy@95E5SO^4pQ!nNAJN)Gv>J0Nm-;KGM6T|O1Z97g!KN6F*<@cFz+ z$2_U!(}=v9NulC`9s07}?T>?66+!7H5S1mF(kjXP68hkivD#EtfXCD)DN877dDHkZ zmK|0TJ{1gUwQ}eoLK29e`ybZpn^2B?nw=7A4%5xYP0O$;70BJt=%p)?ip-gXgWv zc{^fV04s>an0WpLPgU1HNSUKswN&3j&;f{$CK1}KU5Z_mA#5UblKmsR;s4 zCTrHBFeuE1DxPfhje;oX%|hSu^!AkSVG_9?#>;K>-qW6Xw+{_xT3z3=YVwUmoSkKzsi4dE@0dfUMXeFv_t(*89%{|D*OV37 zB~1?=ul4;w$T$j-M@)x|U+Y~8tU{#Rtd_uwV&)t63-ktX4a>0QbuMyI)c$}Ls}A#s zoWpv;*_Pgj@X7N@>~5Nzr54zkvhXclV~D+4GQk+}q24pYc-Mf_Q{L5-xKxq}{;s}t zX?+@??OwuPYE{7~-_c4mv?Op+a>%}Bf5a?1>|;hSnE^^0P)m%eqUHpSAeX#*+7O+A z*Rp_6vx&4Wa$=#DW6XMy*S%C4(bsGTCBv+xoo@4>i@l@W`R0-^6u(C-Y@ke5T?TpQCIGZI zH@EMOaOyoXc{DfE$qck6X4j%yKg2S2f;={{`>Stpx$t1d+z0y$2Iq~?0FTJTaPh-_ zn{pVFvH8-!!&q=9faN*0ud#Iyq0;hilSNMbSBLgLJ43&478|f0?m(GNQc8U_@zF`1 zsEExATjQL_IM^TSt@oemYPqgbZOAjZ-r2YDL0msLs~%u1F8z$rUs2b3NXF6-(?Syk9$wqEEq?1K z8bb^eajmyJPyr}=%WEd~5qXC;W2dPbea=@|T?v^9e9LCa+EiOiHz=7Yr@tP2R*-to z>8QYD0R8$0jE|1bg43rQlK>@$xU2*D*^5w341T6CfTQl~?+x0l9GVKPSP3T3Gfi;< zBW`0)D!}uK*eMEzM(+lF>Uhp%Wjq$;p2@rMlE}I+^032yA+ru?Vm+1Fh-l>3(P*&n z=vfv1v{wQkWlPKlXmhf#SzGqwvQ9;n>#~DoUO>y0n`;pil&=DvckZxn{e|)4Q(AH? zj=*)Gt2Z#>ZhW#_x*KQm4)^_N#Hv+qeE#zCm{PcB*xq*h!^h0%`=R06veU5k zoR6Y9eK(s7vZGcjHBf?=D#BPfR=_#Y3c| z%GJ-|u= z+P}60ZeWR4XKnA34&yUbX`a*_tw6Z%m<4##i%Qi48=IUBce!&mT(+t;4k%!@|8a2q zqN&)xx%jOpLi=#A@Wh>JM$zE0>~(I>GT)ZZ7Wp;q0)u!anoGwb)!OxKnAj>EyAe7Q zBSo_gqHg?1|6I(}d8DqT6{m>IJ7{uv_`@iWjQ+7d8$iqu4p` ze)MHR;opDP17y#aL6hGkv>tihMs8#zscsB8!ft0sz84=@3))`% z`gd83mX4k!2+$tN#l9MY(=Tai7XvGiNUji*kuPergFl}km~^!Fvx`aAK_rgfLqaD* z(rCEsx8!-#-j0kjLTEE$_H1Mk=M}_sub0A*9p$g^jQOl>RVVq<99@s~#r_LQDvw>` zar-^l3FT@tu1wuJ($jN0HcHAG39uMn+1$za8Q|Yug3)Mv1Cuifhb=JgDj<`z)1N0PX0RCxNMQR}5tT&4RNTH>A)d$c zR!g|<-D6?RK_Sx%JA*6aI@J<%opIO=q^lg0#8Ajuk?W_1_O{5@EiIhkO5wU&Byzlf zkwzO!{%N_DFL2f~#`%_y#7XTe&n$od2U`6{3bM3po6s>|;79xsx~WWrk$~t^C5Ia# zYgQ`WiLBn@UYUSQy-^Lx(Ih}dk-@adOIJ}_q|v1?)RQ^-T9wygH+LxSY?`i`R|yh* zBrKvi7`G?fv!u%YutbmiydNs5-TTE}wF;;C#r4xbwnHU;L*z$BSwZqbHF(InnYF^*(q>E&sk&=f5F5VP4Pu&|p>`hV=_;zX~>n!8|9t8|Moc=VP=M=`SAJ*(%x}S#FiU zQ(Ub1_2YFg7?B=2lF3zwQ%gqIc_i*&eBzs^)viL;5&>uf;%kgF@IB%g1ZFAFkJtOF zR@e;g)txDasD}06#D?%qm_7t@6ptGL?}U2xqUv#3XXEi2Lxs0t--xM^=mYd_Smfw3 zILhA}Hp$F-xh(n($2h6a3^yF~ofMAMGbFJW(oTe5vENH1y5D26WN-xsi9F?Fc%$93 zcUa47&Ei!JIDh@?TXZ7LhrjAn2^>Wp+#zcW8QplI`d4i=|46MXBySYro0M%9j6zjU z4Q`bX+2+Wqb!i`}Em?kYZRw0%{`)OtA@XIiP5z`=HVJ%Z0drG6kcmMv%r@Mxah#mG z!E*Oa;$1T(PaA`r?ybFt2e)^>K-PoxR7$AgI3!yS@ znQ`?8^y!Vi@1o_LDj!z4YqkfB6<~JEL%bxI9Zs_3hcKI>ki&3;f|6_aPEE1RayBy_ zDK9=fGQZa`={|bOz6J(Q+$hm79Y@xmEa51fAwipY?OE_ zjzwb@PMnpC*@^-)Zw#Kxp`lyW-~HVf2zl*-(A zyMxj5d0}sh zyP?jUxsPu3&wljrPj)yH+3Pl3TNmAPYW?idE}d7*JI18OCSS$cwDD|CeH=pY^Q#&YKDgYi3WD>wGIrXM9x?<`oF<0gKI@xR&Pgx6IFMx_h#Pt=cWxqiCO;jl`q}GY8@NndBPL>vffBp@hHU#`QP*0xInzJ!SaNT4F!e3Zt~A6$5=Ug zyhv$#^3*ZPp4C(gA`~0VuF2sgCfj4$whA}Q&97M4QYctoxoCUkGP}by+pFw~Cr_Q$ zy0w{sf`Xmm1wJt$f2|F9H$ZKZYva-TA4%W;Z{jlC!yR(JKl z>xO=w(92h@)U~#ra&wcpbLURZ%JM=`P|)HpgMN?wbZ6qvK2_m9%NyM6A+XtJOphP& zc~=`pr>3Shc4uBau=D=$-MqmY_;Zh5#Ix{b;f2Go>UC{xstyh_2ipvy z>n;c}o=#}^VJ6PMqw)%yLUQA!13QEJ`(A1$SV=`_Cw}Mq`H-&b>$mG-1_lPdY^AQ` z;~K7-o9FiAb^8eH-Rt`&IY08|O^WZyhHCEad5bUZkieP0>FY~1{PB;#E48SHA&Al1 zQ(`-50s;cO?%WYJ`ysSrzwYO_D0kjlWyPOAe;)m&p_WB+wYK1s-PbQoP37JGay2QJ zN-0KXW=uYLZMe@S7y0}-`+=P_t*xzR&z(!L>OMX`K7RGuwN(XX;u9@4wOh7tx2qdE zpQu?;SvfaeDcF={!(*S_IwbijCPv6*+Dt@5M2L}EB0}}|pFd6SF0L_cOghI}$|WxT zWS~ASFgW;5TpSNYVq&7}(p2MH?UdU;fBy7)cqb}~En3l^n}^5e=~G60`^s#ooOX&) zF_*%#swx$3m8XZTtwp#4@7}(>dU>&5?oyg=zEw+d{<5=iO?dnsCm9|79TgQ7+8GwR z4mk`j7OvlYJxzB*QQp2P`mO~!CZ_Virqoc8D;r7d5V8w3Uiz zwxgk;IdJe`blp{|4I2uJiWD{|a_-)(lWECeoElo}$Dqt^%@LvM6B5GE*4Ea(=(U`` zkw(jRyu*|BaZr$#=AY%WOG`^9m6SO7`23Ff?Kq>Q<)fQea#_T!`_kI=>mNr()|f=O zl|1HB4x+m-+EKVT?2x}(Na%F@G{xxH7za1Ex0lyi1D7GOpUusyPN=E%2Pm>~@bkZI z9O|zMEh@OR#;GsVM8a+ULv#1cNPE=6aJK*KtYa^YaYl1+qw5RAkwxy5rnR-T(9Q=+ zncY$xSuBWITj+*R2!2`h{IHQMWjIBu`mOtC99M4VJ4?LrvzGqoc%w2M-oI zX+54NC8m+c$%S*Z6F84Gkt4=L2doQ`>k{!)MRrrq|S{4%#2u z?Bj`liM?(9>&uIr@d`f12gmQ-yXQDrr+Cf6;>kfzve2LX!wWBTbo#Iv5B^BWeQ1u$ zuMJd_Ex)yfQYchK&#vK|^x|mI?7{+H#@O_9-}1spKlb;nL9XuV0Oe~}uXYsC%ANgm zCo-4?N4cUxNriiBMvL{P^78W6XL;WwBp8UAVVAlrCH4vk z7*{_NBd5)zhQ-y@l~L^awnO%V7b>6ZpPiq#ZZ^-@vSWvLQRjvBJh!*{*_utNSiiBc zv8qr}pM!0V3h~!{@7?RFQ)J_klG+(pf70B1|GIVSSfm{v?N)p^xs&I{jT^&R{jA3y zvfR~8d=(per>o0o%*sl2NpE;X}1(gmTT7^`kIKY2}dWzpvP_3OTO z?_T`=R%b0D;QF_{BuFCN=LgstCO?Roe*g0G=RL$oadC0@A&1Qr(RIE!y4-;q@Yxwl z8Gnz-?AS9g(;b04YQuIl=d`p+x2j1O=D980oJi%w+8wvF6xy_d-!fqjmY{Pce?{iX zl`9o*X*V1dxRBbkm!ChUCx~9lQRqSe1s9cL=N*P0`5yV!OD`0BW|u}h{PEqpkKeyA zH{NTZq06$F5`R3{lBJPlHqlp2&T!Q;u}#r+WnLS$?%lhW9Xa#I5ACzO+Yzog(?3na zW!-cKXsw6R8oN3>kLc>|JfCjHv2Wkq%uETq37?fS+vTU!a692%;W^{s&dyua#tL!u z!Z+HaU%q^4DZxTkI-||`&*Mv2Y{r8YEJfZl3W=IF<2@%0+@{WLW|f|eaG^gSF8=;n zJ$J^KW5+E@Mp0wx>b7%1@zO9?cEh`)O<;&^bHSu*fh;HTNnKNf%;^Lw;6RusqZq)hdPDMZVHswaUY@|~kQ%-I!(;<6)KL){9 zA3mJT%FoC+7#|-$J3EV#htr1y-t)3y2XFAbn3z3AMn+%$Olc=-s)kF{nY!rc=pZ|O z`Sz{n`^0XnDz@Wg{QyF6&%(?|X=SC~+qe85boXPK&uVG$t(uIKaS4)DGB-DObaJ{V z5?WSM^U5&ay<(fV);nDd4bNgD4#fJ+@p0?TY_e~q-7jC>GcYi4HBA?%b0077 z<^kFhr%%%%STcWA-SPJJHlWeiwV85mZf>#fVE%wu8aF@xeP)ZyTSz?PlV|>x>uK-Jo5f$LM%=5rx<^`? z1u?7|r!m~#&~WVhd1gy@US&HwF~EW}-Nf*x3kwS+Fmi_kVmL#x`}saWot$qCbXVbScGL}U+w3UC0*VsT!eH54`qd7hyp?jiMt{<$Ov#=tV&xxE2p$inXax2oZva&%> zo&Z{r7sSIJP_jDSLMx zS#y11b=TA0>ZE$(?^)Oqsi>NRTwog+-G z{2xBtoKdOoc0ka6Av~Oglatdq?a{B)TV)vy-@hNfbZIxP3fX(y&v5Z}ta6Ao(&NYM zY_g8!JW)pz8j$#dz79un6cpdS85xqT`h|Jt&esVEMYXlGILMD5KixOe$0l)}I z_vz_R?EZYW>M7fD<^08q7rlIZ)|@_b=E#W?RBF;=Ymr!?4NGFK|-VRS6#F={|?m%sbaU8Rv*>4 zqE5@b=Pu(r$le}3e%vUdd0=qxtY+s^H$Pua!JGO>Tzwq^AHVIb z-c8z*F@=rmKInRH-sN1L_oTD4Qzcv?Aec{!w?D`^H_~aM??vMuLFcHBjtlhk^n2*C zew1ed<~p=F#eI#bwTo!Dex>{|7s-qdwB4r?43QB@@nB+NLRPt{pKX6eT^-k_pB!u? za4c56b7-hK=44<{!OM>yp8<{FhJl6G0dX*(F(5m}B4tbE;o*TVL-|Kv^9~8E!?pK> zf`USFDKJu1xa3xVIec$_O@ytj?em7~!6om2y*6y+?&$804vIO%vKfG)JnTl^Ndp5` z)wn=l!&uWBNW{2m9_L(xYaP#mgNt!gb#ffX9Iku4(M-5|@1D`*uR5gZLHlfx(n^H) z+(iFYI=aKio5~>qvCp4V0IXPK4~YZ*om5jZ`SI@JTf_WFG#I>YXY!WkO_!Hv^1Cf1 zGMDH7gdVs?k3&XQQpRN(eO6|tH#6d;6#3bHNH=eBTv=LLdUh(=o;uJK+PoL zCATtH3t*CB*(ndKjcx11ag52!TYg+`={0*p5(O#BV_7nPuKI>hShY%oR4^))x}Khj zySwbMW5-ZLTg)ZRJqrtvmQ``HSajF%a-O$(S@gLEwSpdV%G|2qC-U8wGLdt1K3v^$ zspS4evrtAV030M7N7)gx{Mzp*umi77g_VRDy3YwtjeohG78DYaYEsLJmL`Zj zI_}xCo$d?G?Z^e6qLwFlfI^X?r56TMzcn`2qu3lfwhp1jfogjHJ~b~N-(5ey-Q3*k zB@B-=+We0G2c?#osMljH1)XvcPyVv=dzY7&w{6>oJuI4PG^|C@5&ZZpo=*si%_As? zzF3RB&gQUo>`U>{(fS6c7NJuHR zI6f&U@7JnjfF>Z}wKX9_d$_sj+1UJ%e-aZPoC*`)$JKj2!-5OQ1D~=U_kG--HPK5f zPA#gBVC`oc4Sr9Z!eVnMcvGC#)qUf|d_8R^-UdLk^TB#HHny5@NdOBNai4w35ejG|Tb|3Z%Ep%E~%$;J`bJRw>!#*-KnzDoRR5 zU!EVqM{nLG^%;Syc15aVWvP8d*mc$tsj;l0;?rdjVf#UCw8cNXDd=HO|eV0|^CeBwkzD-QL0$69EVYi-UXOBHIZmT?y=kERcX9ZH5 zhr%Uoype{HslyK5(0sC=4VC;)V=|A7%r4+_+(5Sd(BpWEzigA7kaKR^5aWo^ZBNg+ z))99fK;2mNi$aWfDdu-H6S#zh$0%2R=7;PP#R{UW%RD8v>YX;f(#mEDLtz}5sMBZ9 ze*S!SYk5r#w}b?vXW?PgBrsrHyLWqP88{sat?2?nWR!DXJf>!(d;Yvmo~xvx$5I-- zu}YZugKPD#UesN^iV~8ZzJu(9epdIxL$mc!%RS!@Mw>8-xGy^P)kgUjUU-fQ=+N%g zm>74HPtpbuye%hmrp?9w=TBWgAE%xGMFJZTSinOd3^snyO;o3`?)tpJzAkUiP{^EYy1*D?VTz*~3zJUtV6G((6k?j7R{VOH1)DXcUlW z!oPpl?9D=^_Fb8aS~-&3SpVb4-cuUIv<4<7JfJS5nlo;gAjDCUkLv`=NK1z!nTk4& zUWj!5z3-l%A9%~teY)uP#?Tt>i`w7#fl0zJws&YK@xYCAZGM7Bn@sE-946-fBu_MG z8SdlLFD@X)juI$N?7;! zinO8+dSaTKi(W|O)G3-;*#&-|&AUFKksym;)2Bkeb!%4NGgC*fM6IdI39xzJL*8XT4e?Cw_OXF-~auq{f`5`GO z)K^=3d!RkE){9`C`hO=RmsD0NZ?F+4sjt_VyMW(L?+o*#q%{~nI&94*!I4Lsr1S;} zX)8UwJPOxV9@WcTpYP%z6Go@ip}l&yzjW94N8dUvC!IaApK#tVH7x>pG{-N+vN_`& zV+V3NqDODe0XQq!O{3O4JIO}hJziEhpyorKQcz%}sqwLJEKLhWC4tekD=`5NyE(Av)CT>(_a^OCF$^ zd)=rc3bqfqSABKB2ro9~_3OR81uK&S^`N&%K|?eG{P(=@VI@1XYR!5&7M8*EpMJ$g zov|SX)_kk-g8=$n-P}N9Zri@y>em;JE6yd}G|Z?p#kIBmlasbp#;MjuFV*8)`o=Rd zGA4itQ!kZ1G~l65l3ktD=PiR^y_nHlH(=}N;=;%GAyesM)M=i(zrM@N69sZPeK z>Vk*VMn&HFz#9iOSkk8N!hxNkQg*zcca_qP*BZKNCFzxyJYW`_Pq0*0-URLkjEyLI zck1Fi#D?1tVcHX%XTsn*bfE0K?8 z(@JZhQLQ;xNpXvoGVGUdsEW$711GOV>S=4wdfs@$ML=a8gHEF6!(E3;ZmwDrR0%Qz zkRWI3`*}i*hP-W?85_GeKRM9iGLmbN@C~f-^iVU;t+Io=f;roJX?&UGR zpsgryM|5;T-@m_akeq*2v4u~jQ#`D?!d%eR0PJjHpha!0X#Ll(gz%x-xbbCbY9N>L zlXvb*^9Ed<_Sq3&$-HUV9)gJw5P0aeFukuCD|U``1tf)1JAFdKy}}FZ+}y`?F0QW8 z(#e#6TvJnXBe&~btA$DHM>}LNZ!i*I?a}8Oql2IT!r^;yOizymwe*a8)-cl-FbP%0 zq9i{Q6%hu|z^QjTm)A~_%O{dkUcY(sGCP|YB}7}BQ8!U@gWuxPQs^NE0kk)0n{ba) z5o+^Zvua_IHr!y$c2iV_2=>!@%zBO+q&E+d6x-KljO0-FX9|3xYLx5)6tjc|MWnp^AVxbJp9~!&4#fe%Mx9-cIO4>;o2G#?H!=KYZ!st8{J9H=vjI+^! zowp{=Z2=2{1F)t)PB-&ev^xXf5f%<83V{~`oKi3+yQj#9R;zEZ5i8ul0Sb+T2QU># z3eqD)xlM;Q-=l}BQDj~miYVFZzXkMnPkA7Y7CtIAW)Xzuw}yrn>hU1{OlC(rpzo~5opbH(+bO(Xrkow|M>?6DsFAsky#19B%=sW@IE?()a` z|9B{E1B1wBPEPPyAu_dtTR^iNb~r_qRPrmVbvwbmHPw*W%uPAO&8aA(1J>52B2 z{W$oE&5f6Cz)8eHB-DBTz%Kw6+{JT%u>7T=8#pQ=;J0v;PpYcgAJQKA_3Qb&caLag zXAjS9pUMW*?jpDeVhNA9xTfTQgP5op^mHf}K-5eUD}PLn9`zbexO({T&2hewJ3QM^ zkx?=YHaP1otwpbm=3jl@k1RFOEKc_7Eggb#@>JSM1Wi0Ov$#rDQeIvpzV5l!)~|d^ z%oK#it`0jm0S0X~4kntgeS7ylfAQiL&^v9Srn0K)X5@E3gWlzchzM*!ipz{etQ2X- z0He2V+jbP>FHkFb3LpdFuqE5KFKGc%Jzit76N_w_4xlK7eqx(0Ta`fH$Ipm7Rz%PPOD&O1wC zKhkyzWE`|fz|mB<1$!O+<3!Hyq8w&hnWaQu2}&Pr1>r}CQZ(YRatHud>rFtX>neG~ zqokxHkv{h9*+bE9aw7-pi?cVQIQDGC^p>yb9fs5<*K*GrT6cU+vwq?v5zSCD*`WIM znP^{se?>GVkjX)LgK6ysRH?9K!ubKX4E}1>c=A&)@H*8d27${xWdUf1wxNQCpD_FR z;VvLAZ~aBWbu?OcPK-ENcY+d)HCqJ*$q{-LQNf_p6kHamYiKB5URr3%aT2w&v&$_R z1Q~d-F-e~=KLrJcd-q%e4#nv*oZb_SvIBJs`KQ^&N+uu7=a#KoJwea`%;Bv&ckYyM z7-sR?v7b{=(BG=NWD7n0ZKc>Q#Fkl0=9y3dihkvuC@3A=r=A_PwthdZjXfk^gQSEi z5kwJ>1cl?3f)rBX&!&d8+w7y@q`!UpcBQFDMV%dJ6h0ZH2wC@>0H+B64T_|kRoQjq zA)8#yC4ZUY#>U*(jy+sl=#$a1_o3RD{dji^jg_vhZqUMq^z?B^;$#oe=p4u91FRx` zQ{0!FLDF`m3zpT^#=UyweKL?+*yuAATmw*cNa#CF7-z&59K6w1h3?=J`gkf@+Bgum zfMVoWSbQAd#+!S4dkf~+Gcz+8Q9okmlj0Cq)5EQPz&5}V1LwYhvn15+xpTqv6d?8s zhQ!j-(&~QxR6=hKvSwMcF!3L+tCH}cV72xBhGO=$r;Sar^jsAZPSKkokN;h&Wn4 z{Io8Lfkx`^Y0WJS)G4)>fbNeMAE2l{oOk9fAc&4e_|7wJ$X9*tO(U# zur2S)_lky^I_M0Y{NkS14Ufk*{v0(uAvcl|2AD0 zPhn{(Wv~)g@PAxbzLj6mXE3cp1mCV72s-kgmDSra$8?TrERgfXe=J#DO8*xYEO&Ld zh^TM>`}?l<|F4Z*pVjXDAFt!d{}T_F+&Na@>!uc#o9l6eF%}azXPir(FM1<2oYzVwf zcG(88>H&`)6+oIidGh3u=sHU%N5~=yVC=y>QnWb#NxaW0^HEC;xuTdzkz>USRuU`~ zy;2bmiO`9cQsGkCA!qqHXN=4$bR?+LWj(bUNjSDhWb_&aY(CaX0pdp z;s=T$B`xb(c1YNS$6;b3-VP)Y5Ny_qvsQ4*fYKx~PMU5t^4`^}S1Ag>y#Toy2{F#1 z$bhEod}f*i$4}MJ7^?7(YzIN;3xLfK8X65;_5;eNnG&BvA-aIm34+Va>8%z#fb3w< z(O;wYxD0WqBIWeT@)FTvP-3BIsh>aJY|0G75^8-Ank&>n>;kC@C`Hf=6hAPEZ9}O<=W<9DPvjhHg{a8})2xfYagR@kD=&l`aHV`2Zp< zhy$=#)D*ZuloKY9xF~NG4sVoVIk6~^i|LSem119_lYaS<6HKm>gG0vnQ_z-Vfl<-1 zz}3~&P(w}|7z|^*{`x4#0=KZTsyaJML3aS^#8$)0_11dn-NhnCVWYK3|L}n93@q>2 z;k$>2NAw^24#KvlzaOFT)pUUZbfxsl;sk_7Fo}Tj0Hdjp*E0HJ>IaA_#02h?sH8(b z({NKoL*hiioc?hM2Lc8bd=x%6Fe0KFu7pqMSGBN}DJdzJFJH!Q(H2=W1B(CN&hn<= zI!IIKHgRv?s${_&NC&n8*A3WBaa2)pVlcJ#@zbZitrn#g8POop;Xz_zV#-+@uOy8O z+%XVI6irOx=*==WKVP$YHSvV)-%kU)3#0?q@^!;?+z-+6lk?_z6EqV)q0J&aC^{Vq z($`}PAWxtWj>FZbKgn)LRX4MilG0|P`XKt8`}pEcOX!B+7L7_D?s7#J4FUwVkkN^W zBBPYdA=)APLy#jWK!}Neib6;QyJ?%5@xx~2I^ASK&I?WmUVsz?(72W}sT5ou31XZT z(oo#JTX;Q<_tpoHPO#trL*>nOZNi!(%D{nicXxY&dH^bh-UtT7IhU0JJXHNa45*^$ zx)Z?ZIMKys;x;&5=oFz11I|B2CIOp*CSh320F4Q;X^{pR;&xHz;pn4O-pXt$X9-C)+7 zP6Lk@t^wT1E~M6qA;=hHkr7j7tsfhP7L@ILiH@OYt%0Vk}j{Tyo8icFn2v3=dR6l;?xyp5DnkIf3MV3 zk3aiHxy=}?BtHHO$SnY7CGhw7q~3>zhA#lEk=6iB&KgAfEUb=Ym6bNl7O=Dt>*cCZ zv{B%n6hVk7#a4i@Ckh?$bAg@5fg{#VvYj{>S?FRQEg6sZl=BR z?m9mZ2Zurc2z8=BRa6+E|5ECWs5b7d6wL4Wk#fmmA)8QwIXNWrW0j#JzQ0(s9!fgN z0`N;+#-%Ftwr6zON;TmcAdJZ;G(5(!_1&_Y@xWC&82C=VS=2+fzE@DNbikG#nkD*Y zssbN2_Y)c#TPr zzYmHN-A*m)3_KgCTt2vD=*@)lBmxSYnB?RH1{RT~k8O?DTFw>v2gf}joFOJ5Nqgh{ zV5dQOkoLbmPOZMJO(1p{sBD=}kEaj1EzWCTSXd>vY;;A$payjetT@hO#gIO%Mc5+r zRk-KlN=h3+CB1n4`otWoO>5h^NH>>I>`l;Kc+#9)Nm>1rT<0b|#`dBnt3=Jn(Me zOV{)(M^REU9>&47pOsKKG`zv$Bx};7BmTwI^iHQQ|ZP4_ZIBA z@a1$vFCxw;jX2eS$B*Tq{2z~o0vIdp0|KpAD=$*-mhYdDj*rziY$U-$(?i;Uq5;~J z*!kd~18?^F^=lNnP{{R?_H^=l7xdAFK>&mg_^hTT=or|fIbbM*2ZH#6-H?a{oIiyj z<$%`)7Jx(b87^QIacdwT#wI8CAir#2avq)#m>!8-*q6}o=4{#!cr)ne&l~@c<(t-9 zxa?Q_Qd+Lj#z86qdQA4Y5;&CJqbVeNio>*T-@c2VeYYSvD=8@j?c-+HM2l-eUx{n_ z`s2q5Pzy*?6|x`WK-&8~3~9K2?)EF-la9s7Xb`&}@3188dk8~&d=BJYi{#>~2Mi_; zRivGQu?E0l@BaOE34^u|9I#|4ojaAl^*2we zMM&L2MZq>jEe)Eu!dT2e!wM`%+{gfUAhn73g)9yJLUT1?2GCf8mmtjKj5(+_NZX&y z#Q7+FlFTXBuNMJjh}g&3Oivd_aP*7k_8WDNpW4m|3oKExfu@#WRwstfjhi+(4W^U^ zEucQ|m9D~t5f|E7*|0d(2qSPD7B*e_l#y`eqv%2k1Ewo5O4%FRhSVrM_IWEQu`quT z20@vT)64SEwWQatFF@%;g|&txl!_q4!FF6(nh9=R2QS=01hz3FatAUZ@*Dk@Ew?}f zBqi0Df4q#OF_OO`3v&`E0(p7)q+he$M)lhs9N&$r`X^)v>K0mc<~3~((wo%=%?98p z0>d}nOEM%FETw!dt>BJ3dN0l(>4Iv{RSzJt|K8dxlc>1J?p{lY*YWW$a&lS{d4m6B zO;P_8oN>rj-{E)X<3}k1xdAEBAB?2!YHS}yS+Qs@2U>F-Eu=(=MZHeZO$0$o$IM&_ zqXwjNxR`+BYG6p($F_IF(PcYCTZ?58&3)#Bn{muwUH}J6qJ`2JfC9(@CTe&iiGuDr z+vx)gp57R4LTIygChvl|xh@Qh0CWjq0s^))e0Q;ND#}*r5dkI{Ig7dEHX<1clZ4Uq)0&$Wt0W>W5)GP2EqZGl+ z5L6NkJ_BYoR1kEbXVVEpsM@L(e-;Errr1Z*t5+|KwB<6;92Kw=^5`u5jXF(5L(>cS z-UQ_jF3c-82elyDn_#Xb5QB%RF zWLPRh*9n0-&T!K|d2$1mjX)apc#;ix7I0(`b9@_*2u!sS^ThE7JMTc?fLxy1M98cc zFAB{)+_OfKH;ElMaQgJ=f^%B>v94;{VPb^pt!$C-;X@GE*4xkt=)f~gb`d%eLI%-2 z660{+(JdtjnVC-^lV?6SQ@b>l|M5oNDCOF?`f`vdPen~OqtRiJbzwF27OSPHGp>61+z5O&bM>Hxf1UDYQ8F947xX`h#uS+ibJ$067ehPk_()E|$wJ zkI@p}bc;P;k1N_?$O=Hn*wPj2HD94Yw7Jdb|Mdxv`r@L{OalT(0k~*qnS*tUa-ZLa zPO;*MDH5hS@6b-3Miv_+axmS3`HSz**EeB0=8T?R6?&$p(AN=BID`+O3oVcO$nEXk z?e(kqttOx8_qP}E{nU&?H&L$Wz}JJ(M|Vb!xWz&osQ>J9TQZ-${5fQQB{tE+p*OzO zLd*GB{8?TisH1gE&UEUJm0z#b{u=n@)2B}W?aL*<=^AaI6A-qITr}*_TefUD0^Sv$ z{MT~Td(ZS(DEth)V>OX7&8A#WR%~M};OzupV?TH>1O~^`T3Ry?F5#4ZhI)-63r+we z8|j$=Z6N|bAWc4$U0??$AiZ0+ZmEQd+<|vfcCKgZTz~;g5G4)#L^`@s`D6^;YTcJF zH(?b&a9|s{D`05k03vPy9g~Ll)WOyml|(Yox2&N@sSHg6c4|z@Akh-}9?2GJRjWKr z2R#x#;cYdYhzlrC9aVUT^`6h>E&QO%Rlap&#%uNLYlA z1pY%G0xBG~B;-mEb1PHK{Iv;KKVd%;jelk=Tf_;fMIVIuk+snNb!6A#x1iQkr{SI}9 zOgDV3uV(_O4v<0Ci|A*X%a zqqk@qzp|BC24B3gkiSx?ESUTGYpilg^AHk`51gZ+42G@&{ZSr~a!Uhhq`N2F!+jRX z#|Uu)*Rf-y|H1^{o(2v%Vco)adv)CjuYv1j)%cm?BJt z+uFt^_{!?s+}yFLDR5qwQk&4UUxL=p;3milw*(|nM#LS<{j6yp0+e)Q0nSr7s z5((5sWZRrU;qg0#6|s|x!}HvLPj%6Xq8RJK1mexY3k98)NG^)#Krl@ep*oZ3-|8aH zkpFnWJ*1gfrQrQU5=HM|(a84C0EiO_PmJa(`CU@BW%~=pv6Lw4*n7pfGjIu@3-Cl% zbbm_c)*(G5m)80Iy$H%J)#lB8Fk5jVx^U*Jjp3BXh|bu=1R1@7{pua~&Nj#H2Y$=< zCKcdqs5H-L_4fDow+=-IjFtdomd3erQ_&LpCdS9R(wi+bHrMDQTS%hzLgmv?pY)j8 z^t*)l#vU}IWS;3|0u3Yw4~<&457-jKF_sgE<448~HVn@UHJldX;<^J9F8nV}i({pd z&Xd391l1Ft0Ih{Gi5d&R-J$tbyYA1Sf&tt2n5#qpmY0=T9%5&PDG)p@EC~}oO_R}V zV>Ac+SStM6Mwc#;6p142ijM>bB?G!M5LM>cvu7lxg@w0-Rll;GbGQo!16pW%7g=0O zFT_Ku>?(^4;>_Y!i&O!Y5zHA~jky^vEDmgFIHqLol=NHRWpU1pYa>s|%df@@NR=1{ zjpxt*^(;D3Gl5tLJlE4$AJR4iJAFR%W92{B01ui6SjPwj_Z}+^4zUE|6i&UtT5tk? z27!g{7QNlxeft6qexSPzS_sydPzfteRPs2;*MI=%9O2DDCepd4PSek~=l%Qlm}s_X zmfH@x5@Bs+C5$|dPS+Ekg`y_)UO;q%|cXUy;ir@smcfpYSRNw08t+ISfaD`*n7v1H6 zT**K&8Xlx<9OcU#k?(K**9(9IMo5mQPaW$%h~K+^|1#DdWX-efOE3eGVGOjweXx|R zK_WlY?={`d1&=Qdf8f)n=%Ax@2E|20h%^m$qL7RU*vQPwEh)qOb^7#S3kv~6a@2Kp zqcq(tFvP?wi7>6Zo8lWDc$ocW;~%m7{Xanv!B_AbLLk*KpGx{v(4H;!&E{}c{#g8;k(Bfh$;PiC zLF*5L?okSK&C5sF>7E1q=j2FJ7Zr@m*ua3LnWRTXV9|ljF1fG1byIT9a8EuB#FCho zFK=(>)9jd-Bi;hE?WwGs_-tJGi-oQ&;^!)W}UvSA3_zjTC6(E_+R*Q+J zY(Fi2X=g%a#|)1Wus*Do80Ku1cK2A6;$)fW`?~^(Bz7o9YdH;%9hWCKZ?qhz2bX03+3u)aC1N5QQ zA!n7OW}G4S*&;T?R@B55HTJ%Uyi&A3qvaD0;6C`zLQNtErV_h( zf+HhU(d;TdWSKh~q97Te%IY#GERerw9qF;`L?DUVn}v5!hd}w%#2eh6G{?Q-1`FQ4 zq7}ky9#Z>%%vVSYq;ZCM4QGEh2HjDe;o@+%Ro}474}3|AHa}PZ%n%a&M<66Yk;*KC zSS)!U0f8m`Qdf7;oi7d7Z&2J!a;U26E4Yk+TA!r~$RAPMdmkip?Tjy2|1@tK>a-+6DLTuWq4?sx2MsE`EaXoSasD-Du%HlUdD1v+H4! zouMj*>O{3^Q#86<#kgd+p^&@4lK^@@ii~{NY7qw?a#B(ftA`wrbhR#P9N!br8Oo?< z0wI6yiyf6+ehLyO_1D$&=fiXq*DWUp50#omuk}1an$kfNh_v7b9i<~RYSvOeFoj>K zNnp9hLf}Qd0vakXn_t`79u{>H9{Vu+VWb)VF*VE-BllrimbLLQBIK`&>3);`tK8fO zhybi33*`&+8;>G6f4g}6R#}|jhgZYhY%jk!XZj6zz4BODmPTiTqnn2rtY?(W2@Qmq zD8{^14Mu5*NNf?=A^CUu?4+^rt58{RBF%3X<-je#K#T%MiIU8TIjD^0Q<#GRw?*c@ zkRX7pP>&#yq&42P0bLH;x3R|%x+4Rg6dq-`<+A!CQ7K1%Mf*=*trUayK?X?R&4OH+ zsV6}EJ}^0fGe9puI#57$A!<+X1%Xjf{#a;q4d%`1p~Ww#i#py{3hWjY4FqfntFOfu zgIp%FZ0Jph()!WPH2Hw|{{0V#NQr@h<{@KLHPEe(pFAmnmKh2oB_{aa>ZaYpY~L7c zq0_T{n)90MumdN`8NnWj;L%L4HQJ4Lx&Ard&M7Oq9F#HAoKdUC;3_<^utY`~$iqIM z*+2_{Yl)0r-Ef}>gA)F8(YvaDBE_spgiN^HE@UTw8|e(;1UsT1&?0ly2gWVfd(qK@~CtY>^R0G8W)k>Op6)H^`71acam< zPdl40vT?bdjXf{=I<7;97GBaG?f87Q2eYq4Lp^cgIjWo>@*v?U&=|s|M2|I|1^ZeB zyMZz$?NHX&sH)r{Bpk+D*REdGR}-NO6b3fCD>0*usBe(8#tPQZ3SIlU2Vk}k9Vs5| z&{uP4BnDJKJ7&(Y!lJN-$)d5bL2=X2*I&AO{y1RA76t}Iq&Ns6#;cmp%@7-qBAeS$ zCnrhxkGfxlS-gbr@y;fOuiw6X2C1HjLOBN!t_F`ru&U7EMLz3;UlFI%tPQ-rTM_0^}_LAMX%M;mgzI}cNt@J1bD5nk} zlueL)e+$!``R^L;@C7Wj(W$~LCcGG8V4(@z#?w~#cPRU}wK9k%H~N)!3pZDx$VCC@ z;Cy4NU+5%CBJ_v{7q0=JP~R-=?(7XQBob7?-A@kD#~-|W^X8tGp<6JDB#sIMjw`@c zSWH3>Adu0gEnvo@f;mlP>*|X*uhVPrW)oLj7ZK{GJtf# z&pOV2{j0_&TwD%;a`Q(?D;1(9R=}m1c8|ISI>{_9&E!>SO;xeGS^a&W3W4?>bf|22-bscBXL6Wgr zbPN}Sd~5r=q4L07)McOTV)jQbqqV8&q!8n0j7IH!&FsANLa7Z)Q9Ae>tpeIttL)Z3 zH`%s_32AA;AZ92;RleSN=ll0Z@7=8vsCAg9CC*ZmZ*)(08?NVGUSBUn4bJ))QW+tH z0Uod=XcoYqFaA=Ldzp|>nPZvJJOul6q(;`t^vjo#?aO8e%f6~6Lc5Lb6CNf=Sv3Bo3MWsNOXj{xots@IA_7QKh__j= zSCTH&B105n3Ym|F?S#obd~sf0&Ow5OG_in5qKwaET*SeZd={d{=Z`r`>$%VMqUXX` zKV-Y!yoKRz!Z-*E*M--u<}vn@VA<^U=Geas|5i4TiIc~W8s1oUn(pT{wBi*jC2aq(=+ZkPfk^d+bp}!~>LkB&Ysu z;9gwi{l^xTFjadWoDmtdB@d1DpCvjMia+5T>p+%-V%@JO zH@^j{IkC~gm-4$I0jvToM(v253WA6wwvIfL!X1$^{YH?}t+d#dpB%w00m{;JS>GI` zSqYDf@&;0Y(fbxMFQ%;zoc|h`Lruo4pgUQSj{xEZX2E$S7IbnI|0pknI70cE|DVA@ zOvp##kut2cjV&$2=uwbB#Rcs|EPJot-<4LD_Z=tdcmz2(nd5rgCqZ}0Ui zn@gEOzEJ=`;ZlHdhsP#>%ZYW^ru)G`GI2nBNB~xt^dgontm2@(OLBigVqz~mue~-= z3oMwr;}#X&8d6zI^c2+ABfudPWN0D&_3IAu4%|#M;3XcKm5L?~E)5FDnN|lP#6v9M z5)o0)fBqLW0X9MJ6RmOKs#qAwkE-=po`}npp`#kbW4XeHjC;Q#*yiw@tV$GFB9~3d zRyqa3A%p7^2vPRr`1>IyF-)A+2FGBoK{mwJ-8x(lKKJieoZ};tp=&u!&ewZb*PY7x zKuRPTBl`90Dhv~n_JdE?AFJWprTi~y_4I^9kD^0ud!URo<^zDZ1~7&M6-pt^y?>{A zvH4p0{ctUygt#GVa1G>Vd}JKof{7d~D-Kw7RD^V5F1llQL2{Y@y@hi;bXH|`0Hg{V z^nV7oPFxLDf$angSVJ}k=gRxk27U;>__xtBGy41)dBxG95T#lXs)h<#}_hy$gs;%FQfa*iLTQa)zCgGeiJ3sbZtL!?^PJ z?CkTNcrAA?`6S};anCnggH_`8FO5Ee*9^A#`j&B#IX5H}8n3@M8y?UX?Dy}sPeer@ z{s%pd9-U`d2f%w$GAjX(s>4s&06z5JPk^lAt$%;u>pLm=U&MDbrj}gKzaO`UtG8^) zia|?5bNlaG!-Mg{zn=jcT*beie_trD&->z4y8k4V|LJ%CF6ZyX{QKmu{r}T-=&9c> ze7^q3-#6A&?AX3N_6%Ks@@=WAzh6<7^&az@4{rPF(f{X@@k&~H`t@x`dmcj(jye7B z8*1)e{~s^vfBnU!uQ>1}D0_=l8S(N-e=m)p-6;n*8Q?K~(>%2a?IPw3_ig)o&vOju zt#CqMv{|mIN!*UFa+QA}gekb4e#iJ||0dMsbATR5o_Ycdtp5F?8;;p>3vz}8)piwJ zV_c6<*{JaE7VDj+O;Ws$n@n(WMjb}o6{0p1KlN@a`JTBCI{Z&+2ldWld&+pWZTwH7 zUW{~zQu|+R)8e7|kiQ{NR{X!%*^q5^9)Is9z~;sO7$*NGJM(Wr|3*m9V|wcKVr0mS zbW#7SYhm<$fk?$qKhfKOi&KAumI`M^B5#K(aP(Tv~c(!dzuQ=kaoOLS-eOTaKh zgRS68{?gE3SGUqtg6C~TMX8yZ@?ipshmMMjO3KW%D1Z-vdl=@*Q&Ef4SX$ZE6V5BB~KuBAp@x~%xg85g_f^mv=CZ1-M)%)Z; zSgj5S&u~ILLt8n*c=#kL>pG zzo(Uw6JspIoQyrZloI~B;rE#1Yv{XxFc_E$fX0X@cF$)k5<-`T{we^E{DGsA2qR$h z;3da(Izi7TPe8=em_Q5Y3wfr)dqyq^awB1`aI27{hz}LJ0*f+{?eSCy1Rh3;K4Yy7 z3{=r`V6qF`oPnqqa#z)(p0hA8+^;r1WPUg(G_;&F>G0Cm%FMtLKFH2U4PKm(3>bjC z1m>PR*R0PPW9UjSNMn0(Hpt99s6UeocpuOOLi@vWS1aGHs>cWvTHMivrGmRc{AgX# zO#ho+1j|e8a5gqJ{!1U4hXBgZC>{s@oSvTENY7p*1R?>ec$>Mm%A&5$+;z;g16Y!FdA&;j|0fWfF5M zzw@z0^>4NnC_Mc6dYT9xkqUAg%+q1^0)PhX97kb1tYz5l2+LQPvMYPZg9k7+JC0Z( zj{&oSnhfKNfBgV)tfI>MV65Cg$kQHA1cPOgJog9JjQ$U@A22;}-`?HIBZ9|>z^@2J zo(w_*jZEBLhM@TJ`SY823eFQGEKv%H`a9v(#+Sg3A#7lC%h3?v!8|?{%!0s>p*WP2 zPp`bkC>y4;4}%QG>j0dfI!e)MlZkRP>Nqt>WwQ(ID>dW2m1EAi#DcRjpS(iu0zEBs zKuF!hM*!&mH1!mDG*r^Z-@Mq##ME%C2jmoIG^Ja?$$&+7T_JRTg2?u_Y z#ljrid=KcRUMvYWh{2nneK74&1w1`hn+5D2WSB<7pn~%sIrw z2pODXAV}{X zfJxXDPs53WwIWY(0vX2xxeKzqji&csgZ@*|YpR={z?F|wBxBr!m8PR!UtJpUCh_$} zM$&vSu7`3mD5mfd4Ja^#c;FMUx#c@S|(+~d3w;$ivwyN#F$L# z4~vX*5NQ^SPi@a`1tos4^aj4uwU^J3gO2JQm`%)HJ{7vSnoOF2)CLn-z|ssNkqD^& z8)a_-)$_i-{bwFBgeXHO+n5qUg-Xd>$t-17L?j7G*huDCq(mr6LXyfHQbb8264ESG zl2H9$clQ4M&$HI^|3BwBYn`*sw#oPV`Mlrva9!7Z-83iC9P|5S43snd6~|HAk&60# zc;7q)A_-ssVp;p^>%rDIM_>oUaM-MZq_S!o#9l%OBRPI$ z0U{>5{_WXVyW6$!-b#=se|=`ytCcyEOis3PO4y-rB2F(SH+Ka?OrkJ+>hZllqKv*x zMDkezTJD^&GOes(0GiCBM(Yh3-J&z+M9Js~lf_gP_uhmtNmOzy^LPC{aj`h8R3z{5 zxJPp#(raLFG*?cj_5pV-=`CRqLBRH)53&N~pc^KX45XQ?r`YDmSTE4Ur!wLS_^^fs z4VhCn;xYrsJP!nH3PT_Cz-E9x8Er;I(X#cAq>|~Z#3X^?yK_Ou=hCVQu1-ScEm8c4 zd`6CMlltev!gAlP{URoGF&P&WgLd3IS36cwze!Dwq>yvcP^gTz^l(l;vjVv*L)5>> z-P{k#wBH}Q8=YhfXW0-P2FHZ!0>=hJ$V$6aHGqD7=;u-ah8@#&xz4wKWqgrow)!<; z9Rj4)c220WUa@%wxabqS4M(C$7&zmL`KuyVWNqRPjO zJ*)Cl%+qkMa5INFCFT*(k6`doaSis60+aZ5f{A6wKB~LKuDW8M_P!$5e~|qv-{0*_ ztE+xIrEmgJkwGmIm(RvYpn$ZyIPvbltMllWUBG;RT{)EySB>h{#%OU)gmr7Lhik~c zc5P1X2JfY!3~D;OKI;Bq!!}Nz5vQ|rW>NI7ehkV?nsiWqUeTml&fHGQLR3N62kI`A zvbOPX!*yV{AH_MjU%zM9Uw$SZhlD6bzQ+DVG!rz(IAXvgQqC?}yYkh)T7VKnZ9)@a z_i;(l?H!jv#vpEQs729Pd!qsnAN=-3GM`Mvh`kayfiDLlKC!-Lcixift*Wvx%c!9- z86Ge8;?Px3FM0p>Ndra`{Dy=3(o^fi{3K(P{ivUs?VQZpr3?jo^&hiwOsvl1wn$31 zh_J}{fqTr zxAfk6SUdVqz_KM*E1Tjtkz-U{YD6<3C0l>{WdkV36Ux9hBgGJu}yZPu~bRB7YJ z>25k4Uaw>H+5JyTK42-hk!1bYCb~5)Be7f`VSFn+&QB>^RM-dtPt2$IdV~tTj~w9( z;}vk(k&%Ihb@7%qqG|f{X$iC|7(PkN@A46+v*8nID4gaV6~+)Nkf7h^#pw6gv9X*& zeiBR;H-ple;~0)^w{)4w!fJ?IDH#z=Q~1EXp1p9P>R!YI!$n6ZibpS9dO?3)_bWq6 zTx_4neR=X^p#3S1hzy6W7w(IraurPaisG)E7K=1Q6Q4C>R)3N^x zDI`B~@QDHmzbi_kNS}lv#93W$SbU-+7U7fJPtW#CaVFeA$n`D%`Ywg|@_?2RRUhM` zJBj5K!VQgSeSwn}i1Z+I3UNAZvD&Zr?uEI|&pfnM=%%uTg7No%N<**)x{Iqz8WU#) zBsgRV{;e2GgE5GUB`!w9ZnCY*lBq=zw#cZAAL;72@L}7CXoB9`C5)8r1$23P*T+MCYOivTKT^ zc5fL8qi^8T+}QrQm-4=+26Y?Ry2Cd7Gk`!}dc3X8-EGlEAdLNIOtzmt-?yZ8CB@_d za6|;CL?XTy_v{i=Ei!&~%=Q*;?m}1Z2JNSVl{r|B5D9@CM%8n1_MO@|2re*OPg^jn zs>Hjkq5HL0M-!0G%$oJIy6Q{y<+=B_cbsz@Y5NZ-yStcsJyxuw4dL+h)YcY~Pn_~8 z;@;hJK8%f-TtbMrg`d}>Q-r|zu)ZpH{bRRb)dltgT|PB#OOaXg_mB)Mf?DZa8gdcB zOkk?I<)21D0{Fm}}alRX5xfl3S%#3)~C0L8v^=IIz4ZSf&ONiNM&K){Fd-LrDtoYx1&L8g}G8dV<^ zqC@CKEHSJmPd20EA&JEmxt88SFbmAWaNI-KKAF5dinbX!naoUMjr5_kLfiqLR@}|{ zSo!mZ*~9pg51;rAmT5j%;%q2Uo`cL0fCY=221$(i@1lE!v$*MZbjwp`kH#K2GDZxg zK2w;Biky<0mo2|Rq-pTDZgq934tr0(ycrndNS}52W5pGM4n*_>5Q_LFY5$qkD>|4J ztn~3i^S0VoD-DtUL&?*1v+-g<$HClTWL{jpCf<)0yr|GWiq{AMIU9?9RG`mZz1sFD zTZ6g>iKVz?(RN6c@mTTKc(oIn7q0ycR~DB=wR^ekgO3 zatuMIcnFb541c_ShdLxrJ{CFn8U`krYS z+y_m$6z-ensLG(kkOiH8hIN=nvn&pq(#YqQazkgoP$yevp=fxJ?QAt=isu~FasGyW zyuYOLX3rRzMLo*bpqdpD*3zS-Rq2=M3w@b?a;V?&&TJ*<5or#PtJ>X+q}-#pZUK~n z(_mt5w5pwj_~S& z6U6QY2C_5e?PR`eE4?myfw`!J=|l*w;zkP;bic^;n96`onbqhCUl&d3JGo+KPlf@|X*%&YtYFx=tk)GkvIz~Hd`Akx-#B_@(+|^Q7Dt4w z6R!Ni^^!5@{}#3RyGnO+;|)PUK}0l}Q;>`C{$5_A&1Dt@W zla?`nElh|(Z+?#mlgvd3mOh$-uJDo{GzE8h6j=}A#cl(AoVZmO{d)COpjg4le&(G5 z6%u=1>0-%eMjkqR zxP-2yJ($qq=+ZEcGEIWs<2VVtq(?HeWsDZ`v+$>e2z3U}yE7di0i8k|kp{24JS)=^ z5c+ZJX3Ute2GN6XyNTszIN2~m{qKp(9ph%Qbtum4rHoQbU(V~~Z|BKup{6QdSR|6n zo4lT56Mw(I_jvcL%7Uphji?Rmo_y4cnj+j=*!7aeBpN8tgx;#JpFNxV*&ApAAViDP zc4zLTBlCXa#H$>XvS@ec)7*JzD3M(qs?mxl5+TWD;R_c7J2HRwWx&;A107|13FdF1 zanI`QD`l#G!u08*nLDNMk+xg#ZE9eQcBaqz$1gH4?NbA?1)u=+5+W%vIimDNu_+#S zoXcbVn_D!4TvK3w&;tCvZf_g!0%|09GCc|^$j3{^1DpJ%+Jto5nAFN0J3k|GH^~PHANs?+L29S8aZtm%7}?QH0g1iFE!8r zi(ppFzx(mke*@E_#(-;nPiML^OtEZ7JXO9$Md@rEwD|x#YwI?k&_)}3eC3Qz&225Z z(_FuJVR!ZH&{nrH*FV^BKerTj){`@hs(+LY8Zf}`vckNxNuT0Ty-bg3Sg%Gk_;|{# zAR6+F!n=8sGTh${SIii{%X@{|jIgw|32E9YS9e5c?wz9wvwWE`W<-fHeoqZ4&?Hj> zbZ6qOPZ%ZgSgSa^V(&b-mcp0MkV>r=l(j;YJ1SsX^<7+{0U0Pk0SzXw- zqtqQsBj>5sr+}GHd6@Ivu;0};C#!!|dX(mN?~|dZHE(cQ@sQVrO*3vXbtRr}q&8E0C%kQ4+tNJV%_=@p zZ{E~UYcm1@Q7&i2uga>Kk3O07&j+D*dp_QvH5m>$IL3bg3`{|qUAXzvL8M#Y&OJ3X z=OqW2HMSF`L3@kTh$4Hk>7}mm%-eMDfoe6kZGsxH4*=~S1Rj%k6PbtS02CZ5w6Bm1e`M)M(A8-SQX;miHHpIy4!8Ddfwi$=CH= zS}eUZO_kXgk{M~6p8v`E>hkq;q+;+#_meDXs8UB(f!)yl zZL6&UaK%I5fLhwv_`dpFKIy%v>8U5E7IFHa5(M7<_A-;?{AOu+TT@SpcES?@mrM)W zw)VLpF|c1uDVKxH1RyBWmTGF|h=-&A3R_>PNuMASSI3q{)15cug+35f9fk5nW87HA zAj9Q%e!ldv2Q@jM5`|IQo4yu6#Tf5Vzc2+`!3ecysspgx1}XJHgdmyB$OSbd{=U-N z0qROED$4b2jb+yy&kXMxH1+^`ucB8LwzVI*xxo7Nw&`t|ttK{r;}NTanrJ+keAe+( zTx7P30n-+rta`T>XGtD4e~x*fd7s}zG2OvDMq2}yg<*&9(7OSpzbkViQroPrEaN~n zMvY&;jiq75U$PvGbbjR*MZlsL{Sux$$zdpa(Bh*qp(xXQhYr>AJ*(+LY5*6NrB160 z&IPSz8lK)y&vOp<`Zm4oPSF>FSm1xuHk~n(OA#rgAY}$ChJN$S5tdFG?dhAUk&VgE&>{{l&2~-uMsnM>k zSEpBZae1Gak&y^%!@ebHJ#Y@$j@+2Gf`G1}u6}alG^K(mE1;nIy5xzs^AG6W#jZZ` zZ=uxyCS(oaf(6+<%fpebQ1Bj*YYDoy91lMk%_J}hEC~lg_CqU2ZE+H}|5%-A>|X;` zL>0VUByPaalGIq&)vsSmiX)mhFnisYx6)dmV(94pbr>^TyIvP{<4kjQi9gf1SV)BJ zJCss92!;ZuCTxtXjRDl?ifIYsxm2|5BZ7=vcTwV$s5We(EiRlAKSu4CPyGOWwl?o% z=-54Yd_&SzGjY?Vq-_MN2^KnA2ccVc^o&G%rrk%48Dp?mr=-}wqS8b5!=W4%;DcuY zl*i4*{Nqkx8GVZ>AQ2!q;0|kD?jqxUBC1yAd68&=;1XTMo+wodfAd2KqSA)olOret zWed{11#Kof;?;U+>dceD!38_#T|=h|R}n=UK_te#B`B_tKW|5}LD%-U$q|WL)cx16 zV55YbP2-UBsR^N*%PL%Z!}^;THSvINVQC`xLpKN{ct@X=6KO6mmT?WsHVzqoPj_TBZqDnuhg+-R*oD3UcSN=JJ8h|GJY-s3!Wv{O-Kcyc# z7rewyt4UbeBd!CcAkwrHosNl)mep-f|8x)m(~YvEwc-sC+!VSS+`heSu3Vd1c`NVO z!W9FAQxYv%w~kpL@sE^=E4l?V<1`a+(Vb-45Mq(`BggDkT4A=tDQUs~=p^8$WDj3| zC4K$B#LM02XYw9_;7PS~o4}0v?mu+I8$$rk!pCiRQX&?HC_0LlEfD}Lfc~3vAzS^} z!gq0`)_$NTnSBSwsL$T8F`&8Jdbkw+l;91b^r$@M<5Oc7LDPZv#r~+j&LO&kPTK>w z=>;T66$+-tF=ST9;?+`jMh1pps)-H7Mvf}~dE8cCN=JY{m9q2QdD#0DkBTj^-=b{~ zyULb2y4H>=Vg6T>9&^Rljar7Vb~wo6`#G3Fa4c+-*B85JjoLC88JGKl|H`RwmuE@Ori>W6q*57+LRTe_iV?ovdn;vr77roJ`>zhOi|cEunKC0o#4Pc5%e z9#urvXtMmHF;rf^FmC4>Ry5F3~a!gw6d+IZwd-vSYO*eVjH0HZ4 zT(->Ui^?m{IY;~^e|%1%DsHeeZ8CyaZ*s_=)jBnLbAO3_!#~ca0<}wwEY+`LGk|~G zj}Pe|6<^_XM^naL^qFpB#HRX7X@zbNd3w&)!O*iMmg7h6Rfn$e}@$oVZ4Dc$3)9%mmBGi16a@0KE?%*K`5KRvofh zM|yIB$Pn4ebRV_ujha$O-pN~EZ)2J;C!B3oAn0sGtwM=HOvbJOw-;%^DRKyW4|c1K zoie2jdJAEE#g9P-A;9bMGX6Z57W+!?GS2cKD0;+wejq7^DaXinE(Q$8WV1|YK0cI; zGkv#iNrJ@4L#h^>n)j1Gpq(o2_wf+0q^#Mthx%j3jA5}>JMTv;-%7zr-NR9DddG9%92tr81A*04rU6)w00q>^$ zV~{43SOD9|a!~H=|GnkPt0mwgIGtJ01_0ngmB?ne8u>zLDKVVexm)m`ohWKn&^=d;WI&&~gldDR7$z z*btQ;cuWS5pyJ_0zg_R-Z#MknGbiWLL#1uK+=Iv3L2OcY{&PfVM3WX<)Rd-enoXK81sq5I@zo%Qm~8jWK%Sf8qaOApb5Fdt%6 zxFmhN{jK%i=RebF0t-x4D@uYIy20Lk94{jC=Zi@CxCdFqGXBV)qz(k57*+2Z&+Bf* z>z|8;?wg}3|$5ToA0I-ywn$zyx*Fp8=_3a(m<} zq0BihrjKxaLSLipbH3ATHf1~gvzXEE*daU3I506EJ**hPwF`%2y(6xEL=ad?v5wo- zJ`R)(_4yoXj@;kAz-jX!OTkBqTdiB`hwoeer$bDEd#cN3Rh!B1YP^QiiyciU*O|It zk>-ZoyLWdCk0FXMS4bPNB4;Y#k<*7`IjA(C2B8DLGS>cU_nzQ{YNIM2AA|f|dsWAb zQa7&MsH=;T)fD#5%}M*a^VLq%td?kAuvK=^nz6aHilSG*iN7~AuB~x$^ypFQdzGGz z@_U|NUfy8On`O06=GFH6Sn58+eU$T;aduB0-{_ya?rBAb=FLHh#1tbW6-mXeJ$srv zX(We*hEDFZXT&M1>I(rqpu);Lu*t$RkZ|(BIm&6piaHie4xkvrJpfZS8VE+)B3AFl zkP;6N3@=E-V1MDR&o^H?2(SvE&BXrgj0`^>`b9GO#1Xdm%zpU%*<(z@faHZNlEPyR zfNE3xd=vHzq6>Ppgq1>yI2&Ov3Ec=*OkkT1vA4GT^BLT}q36A8wn)pUOiqsHv19FB zV{C1;zEYXRrKB8S<=s&l8F|Y!?zdoGps263Z*^~^zB%vR#!*zHXhrS=qa&}EQm54>h36C{PC+-SL z>yKO3&JkURwl4Y4w(u?qCDs|4iHS{bR1H7yy6F3qtx*GuFyKQ-6uR4o4N7>w@fBTT zDi5ynxsan%zaG$lF4c&NAJKsE9i2`L=o#S7U2!XW@N|) zG(zlrgAIEp|NUa}zghsL&HbBqN07-p;!)|Y`W==26U8o)BpwXQIzt z)v8t0P!)`XRWSLmK26zBUAvxuU@YH)zrvnl*xb1^aq3zQn$Lz3r60wP|4YD=f%K>$XCw}xzX6!8XK!dF~MFLQE%eMK-t-$tn?`Pr9%)IV74<}ZK~)T=~(-t_v*1-Km|4k zH^KvS!lum}b1Cte%wi>nWD`~aqNDMAlWko#1IE% zVg>^p{96Hixw?*Jy~0PFT2xlfvqbep`7Y}%@zp_hYr@h%`V9mJvP+myNv6UsZ|bdU zwv0^)@+G@7kc1_LOzm^ry<{{zs26IMzI|J;AqDo9ZW_PeUGT?AVY7@_`>}l0s$7|5 z<yIayqCAQteKLqd-07z5?j+r`BNAOTU{XX7q7!Td|Pk z?6MZZo@PMCHVIX%$k>MOl*kw-PsYNf`0Lls?6cv|b21t=ZY=15%142tca@EG2Xg_ft-q`x@F1&v48>T@73D)Pm0v6_*h$ZZq zu_}B|S-ed&KM;QpI)3`)`Hh4;<^-4pr4$1b1gFeJWWJqEm~^4w(yaWzzRmH#uCyS_ zP6Q4)Z&)eGlplxGU}eE`jV4hawrh%FUL3XwJqTGCh_2DGvOUnhT&Q2jR{^NSKm&SZ z2!7|#L3L`5)#?w8ctKK%qKKh9DgGMUJSAq;vUkHTMPRMozEh`8NFDA27w|!ZYGx~P zNAabQ#ZR)O7N|zrX^d~B-pc9x; z(u`5j@ri&=WW1YW#QA@poxKGkNOrHVZAhSI)8<3(K?F7{G)bDw*}o9&pb5~Zcc6p`+y^oSiq zuKsIEB)SOd1waW`D_Z+KXcui_2P9^!jI#NSX&h&q$SSRo2*?N_!>p8L^BeYueB5Va z`&>d>g;%WLvx72RT8XTKXZyyzG!ZkhnXBK|BUGwT5Qyb~?D(8&yRtRsd_H;@B0?!Y zGI-V$5%I}fH8TwyErHLeLJ(gJCBkjO%^tuEb(^(qls!5M4vk35L7t!Y`UX&Yg4{@% zJgsj}$k+g(#Q9?yRYKfp#>SbpAi5CAr-0;&=QJR#byj_NZOvW0R1L6(J zHo|DvqA_4xM%BOjb4uYyTcC;{<(-~(TFL%o4{?4Jx`aqtMUfyY$pBiPa)d=mpZ}~L ztCMI2JGpM^j zoTI|Ggt=#g9o>-F;Ul@=Pv7ukDWkk~a(4hh17RLRzbs9ow}E>A8lw`Uc#I zfYW8v2v>Jm{)3eVL$N14h8d`lm}CffrO%$2n86syF>79uSzRSsOv0nWZKkGzw2#@) z4RT_{WQgX}on`DnS_*5Z-x#WCV$56-K%)z3DYbmqNZ*d?_u~Eb2hKZLQJgen$#~^0 zBKxM*bz&M~Kd2fH{)Stbi0x6%8{1YEa>cYvntDGn^YEzpQnf^M;J9Qk-z0=Dj1fD( zO4<$ZJ!Y?OvX(A#@!K#zi~(DUaH`j`Y{fZ?26mMQkx07TQ6^*8Wqb}HG6Y${CH z;K4J74)ob`cVUs!dU?*HdIm#4M?*|(NNO&wwRh?XkK>6=fapivu^s5 zv*zix8;zG@pFUsC-?^aV?L&jZ7V(R(mK5Y^;S+y9w=Yr(Mf_9SdtnQ=m8b0hU&wAH68A=Rn^?0zG`OnX_V!n`Y$LL+ENg%CzWy`QshepksJ#dH! z{-wL6o%z!lr;^Y9(oL+^qLW~Ip2319pC}Zfb;p={WlS!RF?CiA2 zrD|+SmsT1rji8lWB2n3aH9eSn=_|O7|5Z~~q&xyzWHj@TTiMIGmwfvTnjVzm*KbcI z3xRD7OF!<-vblMBK)rdn(ZQZdYQs{l+@pwu!Ahi%;>!QgMzewDK(w+QZ5k_MBpU)4 zve5S2`SYilor0{CvOdDt6}cD_f*cy1^;N&aJ@=Z&EhufFxjo?Q`nB*$BEX`MCg{oQ z*lr!9IN7>zZ_n)}6wPEp+J$}7!|f#MQNaT+F(J8&Y-xTtvvrXt#;P<6v9oo)rdS#k zQ$U1db|LOPfUc6UP|A9gY2pkGwzN9us67=CpZ#o?+fTB8IQ(3{*gv9sr(FA=yzcMuEJQ|(*w5@A;E`aH z573Q?-LqKFp+9GwONn5JMHrS`=uQL7E~P^K$=X;MB4fCX9TJd@Xj#vFK7bHRNF132 zrJm;{ABdNMBgCS!`GykiNh-ASsTJQ4P_Y_TmO+TuLBb(TT=wC4Wvixq5}eVb;G%ZA z&Mc-Z{-Iik_*!t(U??~bh6wcCsZmvlYKHErq)JRe+HEJ(5zw)umP*03>#-G0M}8c8 zNU1x0sni)l&d?Cyph?*dQY3p?XSo;Gqn;HNJghg3iO2-0f&xJn5l3SkoF$oIWjUA30Z zRTi9J-h;Bp85*1ho9EgEtXlL+4AX|qyn#i?DN-<*s?20eN^$D96%#A>=ETh|&AL(X z)I3tZA~z>)VM-Knyrrrt9cFWE@3jKQDPq~~xTR`t)uq6@Yt3i*94i=WGsfp|7?=$5 zD8C7vA3H=aC((jrlJ_dSyMT{q3&ngx93W6QyvxszKRx;Y4!0AhP7qp2szFL?Beu;C zz>S%rjb)Pec+(Z<)6taN9XBw>e`11b}~6djRCIZa4D9PI-mn<7Z%`C3jTs`!!VYmcH%cf8_A$K!?1zg$rez zG*-Zftj)kcohL=TS>mZwlz{$hH5kH-&|HS9;}}XPE-!~YX@~k1Qz)@Bf8Mh{P#MNJ zU4kzk&?|Z2q&-%M+eJJnueNvZB`us}Bb-`4rA2Sg-Ix?s(x5?ul*nbX0R60sHqYqY zhM#`2jpn$qW9Q{RJA(~&KYUZ%zJEIBv28jx(x~!VD>_zgBoLJ`J%t1up{q^=PhLed5Wr7ia`a~0F0|eqd?5yI)iZzBT`r^ zq}qiSGrC>Ee~*7(xmfGoLUXWqM$s~1dh7GN2FQO|8p$AGIC5b?w9{{M$})(0U?YZ&1U{Vv=N9v#&p)O(2sM`1**s2I{fnrI>nTwtDY6( zy6C*$??FC?vm9l?SAgNOc#E5v{3Rg~N*3j--c{FLsGc4kXl)y`qNJFlO8vUx!W682-~|8&JVTW8kuOJr zj)R=gJOjgmg`)F#-=^M-p+kn`(M-R6`<610pNLDPRiU@;&^=taKmD>OCqS6{x7+ot zAXSk{*3Hdr$H|DGR&4%2{>R}X90G$A5GF>lmQ+ZELGk0CdqifDEE_0Jjnm zGD#84@!-@yKV1HRN}^e#;T+p|$^cZqJ65Y;=Ay~w!*CdYMZmS=8OD%v{5 z$M}D~j@qvO+=}S*pSu>fcBxtZ_UE%3bhx3rQ7K@km2&p}HRmTNOsV+^56g>F z|Lp-n^1yWpe8)f|*LRIs&9_fiWsy9+B_PH#RSseLF2#0UlxzSYg0BM{--r8Q*nqvp&xsk>dNx(=l% zk!`e-lhck&Qi;sgP>ZD}u1L*y5ps-8Ai@|CQ?i?OPCuyF#*1a^qEZk~kT)3_D8LuY6=2QO_NVCgGBUWs_c^3{G-mI2y4NvAb$j_6O@B8dcS9j z4}-2Dw1F```*Ve{u>wCN&n3FeFN%H~@W@G1)_ViwZEvlqowz%2=2IECVX|LPOmI5E z9swZMO!T^1YIs9w71=RCWVrMp3J`fh;OyMl1ndN~X`yaA_5k}CtQ2s-W@YMR%8_l- zDfK%_uQvVIaTC1fW%)2-iGwY)SWf`dNfhFmc)vNO0Y?CLgJFIgp9Oft{>>~n#==6y z4Ue)}wgy5zqxbsY9*xOeBo3k}>_{%!+J5F^yo{tk+#W!-*W3jfaL6KPaSKmEaVaFv z=-7tE?eE{aN4@nm{Buz9LS!m1%K`V7uRd2_gN9Bfy13xyigXZy$r1%Gqu= zPan`S(aqAFhD#5?*3ef=mR|C&VSb@*WV{fWEdz1KP=zeT9FbOIT8yjXu?|(#XHTT| zpl=d=ELgzeVm(T%$58(aK!2b>z@50t_e;zo-CeQof5aZ2#kNp+aY&K@EeF{*9S#}s z7%*t;?Afz-w2G#4eQjo?%&18m7-9lt0Yl|=v1F_dJQ&_#%ZKX@9q(;>!HF-X7L(dX zxH5C|#AP>|Qx_trmjwyb#J^0RPB-yVY~_iZY*ToiO!IXDE*Q`7Q~^Ou^pf<7bBQ5eobVkaq!z~i__5gQEsvUvd#vY8G&J$>&b{& z71CuPKbcNfoGo-zsR;LW8SiEEwL=a|lvm|-0O|*k9z&lmBmxj!yD46-0q5)y1E(xmGv}$dSM&XHr+9XYyj4{({tH3Y8q+s8FmP+uVGH%FC!vrkUlkP*zg@( zq!`aSeovT}GUOJy_xP%}YjW3LSSx&fSXh|B`A-w9aP5VFNcD$1Ok^t-9qw-g9EJ6dK2c8@-w7<~&ulJ#i~ThU@SGbJ!><1tCC&!8CXn^$!*y~#C(gFR9lZ=$Ck z+e>LtyXmfkBUA`aKtmGv08h|!ZOK?_57UOqaW8XU30Kx6+xey$pPm{v6Lyv%;fK%x z9%;{($XiC+DH3{h6ie^ky&E_pZ}(W1{NYl6z{h6{Ef0M+uC`f}bLI7M>+c=T7)za$})bwc7o6p3*CmPh4=R`+eTHfbwQ6)0jvP|6$~RoVZ; z_oa{KxCloCb8#BWc;v#fnX;gj1M?B)Qm=1BS5hEj0{u|PKu^JB>t#ob89n;_#s(cb z^D}^M3kGdb58Yx4D96(h>U+c~but+s+fu~R(2?k!yRwn;_0pJKVm?B#fIkeK3;<6t zO*nIf7d+MFsN+q6Sb#W?ml~oXa|TrB&YO3*_Tevz>$q0-KFh=Z{yAeTLolMY;V-4d zSbC#u3KE3vu{E~roFm|i(;fZkOn?ZTm`4~7<;Wj~GR%cywBvR-ga*kjGOh*B1Kxt- zLy151q;)eK8L(bD%~S}gLJ%C8S8dp+(LNP&>`S3yiBUo#Th|Rp9NeFdaBA#c+E}q% z8>OmoZ%xVCz_T-ZtxSf;;22LC>8Y!ts`^kEQ(ghU_?gY>0g3v{x(w&p(;+FqLYH5O zJ>g?f-`?Q%9u#!-YjNepwcY%9lCs$xPQjg{Q?k=0@UPf%6%h(eiL8J@fty{ZxZJE*pC!ED|A5!*wqI^A40on-B>Bg7DvlY^YuoO!Em;%V@V0g*EDkmaODhC$#?PcBVhK-9Ixr@h z%uM7&-3AUkEXE^RPbMNL0WOj2jsA+HO~<^2BX@+&B6D=x$!c}c$>{0*xKip7x#ZPd zN|hY}J>IOZu9V%`WPWnE#xe`_s?JN7E)_$Dq@?kpr-W<;0i3*N9zh8@AQt6n;O-`p z!?LfnHu1gD|6H2bzB;qB)z5iOYm4*7Yrf@KQ6U+;S*5#tksjv&LWK{c5UOqVYewyT zgj{s*kT3{`&zrkm^Er<1-q23#fA_`dgOLjeD3^p4Y*r4$H@t(P`w^li+yYoCk@Zxn z1H(T0*#ogXFtZX*5R4D_@E>w>gLb>ga0?fPSy4Fw6vE^H2^0)qu&@%CLG+@aA0jp< zDuSa*W8bAW9}tk0&;^Sx%a=OsfCL8ftQl!*#?_P}HG zb{ zQte$O^(W!quQfgnzYk5G!^rvFl$7vPL$SRVTW}b}l5R?lrR&_)o0arm>2qvE9j5fR z5{*JqhHIZW5Es8E9|s~?X**+S)RtS622{a;_g!fLI7Kui*UMhasP-PQC<4ljTSD$y z9FajxmnBpJl#%rDEN4)W6}_4n9$0Q%n!C1S#j^Cz&QaD&7FSI}#fgTFY8N8Uw@u_S2TLSy z`n7hrhH}=#Gg?GH$od2z?68U2bk~TKfNRC^8$TZ1osrY!!;>~%S6w?Os;7H`0Lucr zlKrl1EjKj z)f~>BVf@e+FJW*wOBltR*u8gQ!E6ZRh=%QbR>^*hwckITTwh(qx}77)lSCZBlq2iE z|LWE)c&fAI1(VQ}d}|jcp9`O&ZM1E)r-rQXI<{&%Q&1eg@!rF^O6M_0TCHlO3nhFMt+5p7?1)dRFTr{aKh3K-7@dku1l) zHIYJtdC}PX=_3Wj-gIXJIHF_w0o9f9an_|P+*10wUhU%+q&Rc4()yib?P9d7Azk8` zTJjum>dtH(Y4}0RejBwmS21yELI@F~0ajNOUzzg|nkfM&tLyC6YTcC<`MeeOf;$O{ z7^-bLgCiyU9Cf0ILP*2&Sq>^w*GzRHw;hF^9N8Mc`SDA7g`G0qJ9M-`*;b5_M%EpQ zY9A3-^o{G+aZf?YHou}IyP)MEXl%|8-w5G)sOtzHlhbsq!uzz_1yNxIwoNT6yGwL* z_A+2GV4YU)-gKEMV2jXm&owR(@Eww$aVt}BFPSp9x4DrliIc%Oxj`sh`=Zd6HI5ue zkCa~@#=Z7gb>f<*6>-dO|f@&gefML5~=X_baooY58Pv(|uqpb0S~M zaGJLE=PSPkYU%&NyXPzU1TB;-5Cy3%2=2!Ja=kH8S{v{CMpQF!_giO%E$eG<$mc_7 zjxeTXiLG$1qei`hkF=*_Vy?c4Uf%(gy1h-)06~V_U*^^rWdW>UaJoJ1 z7@?nDv%tNQAGmVMR+(9$kN^3-D5TBE3^p$@+hJ5VIz8V-=3ekEkqANo`JPdxio`C) z9#2PC*%<2jjPN9C$>bS$1hHuWh`UHr;8Ne`hC zN%2%ir79Y(!#cxl`aLN;c$9ixR>naP$=n4(BKzwmnZ!QvlZRVHpdx7x|3-Qc1!CvZ zt^=~~pbW#LO}x)tT(125g=GWnrkadWiin#P#m_BFsI+O~Yg;`2GL)DsB0hZkAoNPm zSkhpMevvpX0J!6RtkPkktE#Fx=sBG*8~=6B`rn%xbX>hb+-aD942jJ^F`Iy~k@J|0 zz5Tbe68BdB>fhZhhn6W5zJ`J=@rHf{tPHdeE(K7lC8Qivj)G%@j#2jl<%47lE^-)Y zazzDVYDnd`6mbUQwewfg_zEM*YaO5~I|!Nbg~t_n)VOX3tc_PvSR$5j27D;qc_nJwetiHIG1{6<*}{meQtc)KW@5;w{jvH>8FL$&I?e8qE5lE`uB>r6jv)c ze$ECK2hPY#32M$K9#Zuq%h7qW7fc%$?EzFBf0^&)^NX35lQx;&hM?c4;LtP(Ya%?9 zD4YfyLq%EIEJXQJm$h%(HlAi4$ePDDV_g-RLkaJkiL)tQpmW^l9~BicI=!-&MJoan zM}6$5QC`*|^SMU_1uZF&#F_$==&MU!1$Z_<$RhGG3L}(EXD!x^fplg{khkpLSE*5x zCiB_J%u22+*D|}wd=fkdQB$0m=uvE=UFPtL3f?T>FX9}TgS0R-HlfoB;6w3^#eeyR z&l$=#)Qs!}Ih8D`9yYEXoF83>30-^yF5d6E^5%flrwto6+*@BoSOfhir1Ror23Ub4 zFBS^%^}Q@hR2K|M>p3Rw1*MUZ9xH3>UVX0W^?{2`^~l@O!O{I~ofd##0wSS}+K}py z4J4Dz10FK3f!V2K?Emi2;s$A-`iUBny#m4E+V8>J&8aT|#$GN9UQs$@G_W?{d!_?T z0%rfEgE9iO>S;)7rwKO7E>HA+aj16i2lwb{8@;OBGf&>1`(8x-aH=OQ{S5^v!XCu% z*Qfq$24gsf)uv}BCvN)t?@@ews)8KBKoE{_p~PUUk?B7mzW0!=vB?F!9D`2vNa%Sg zsd`lC(4~z`hp#1wRkp;kx!-D4xZ;~Lz<6w%^ z@(0H#wP#B~jsg0Y_Z&=hOa(b>R%W=T20$v&j>j}z-F1fP=>eb_9f!Il!8f5f7EqrtcI4(Bm1R?b zD_INf^>gzUh_M>FMPAC-O#a+Q7fTs6&RuYB%KxwS;##{`WLd@`WDTHFkCW^ZE5Og$XnH-S@P@`9EK1nf4jQgTgJ{>m-7@?Cg~Z zUk0>GY-=}+dcud>UDMpjn@m-zRrA$uJ}J`F!=drf7qk|+kGu+ zD7C1AffBja-1+kt|JXFjYV!ZQum6V4>h<9tHtR>0&6R*)SeU(gmC$@3JU>I<3@5=M zp$6JF^`B?XPp_duX*NW(0hoqV?n-*AIupgI-O8#3V@vFCn>h2|=cr_2qpaeduoHC; z<)Ex^rd6TaVlQhJLpn5Sl0!k{@?L}d>S^v#r;A5mC$ue*bd<3;y1tgcce%nytWcz@ZyoEvavzY&ZnQ zna>$(7cQQB0FoaoooWbWlGmeN=C|P z)3Ryq=g$@(Wa5IruYrbw9FP=w2I1zrTu^1?GPT1Xlpn5;)D!Ao-2Z(+YU%YlsRyL_ zKeVCpw1{D69`kX*_ouuzIF|Mk!H+nhIE`(?uxfGMxAfuur{J-=Y&!5f(aD+F*Ntm|CjS6LySVtm_=4GMGi`WqbEnh)kR&sR_K&R&}`h0TH=ogo(g6mTiF2< zoS*;uD)t(m9w3&v{D8%m(qp5>ZDTn*r5COhl-#osR`G>Ft{8HZVhb!_|Di)?b}yWM z(_LTWRLHs&IO~0J_aOYA4GBR!xR*tNWFx_JAYu7tV)iC-f4+eNxw{)co=Do5MDfDGB2r1@P!IMLtR9x!0{qH-o-+_3~p~_=o^J2zo#2I&$ZqFbm&5EOSbym(?xL+AIWN0yjShg)Kvc zK)Mv84dhe^977L|@Rx-LNSqXDk)*mrIb(%?I1>aiUj>>aB4rRt>TQt8)3mu8KtKDjhtQT0XknKK{Y6yPzo^!4i{0|&eruUwCv+!ooCra`5xl8$ z!NF`cp1Qlu^3e+)~hS%$wp>D}$eIsicC2JOW#1pZiDPH=7I)l-=YM#NYxx>vCd zrb=?O>d(UZRtN;+=ig0C+$9>D0TVfqVolD*)AM709Dh@5iM3T=eEtYmU-uY{^kERk z@uX=$@5aS705;`Fq!jFr|2Kl)J5vx)pBl)CUP0vkLZ;(c0G{q`bINSQh`Ifa!urZ; zIHIaEcqVuCfsBUniNPPO>TKmNp(eLnw1eMpwV|d@17-6vqj%MZwQnY|-Ot)40?>t9 z1XD<4@Xqh|@86t$Xh%CQ8RCRW#G1XaF%dv$KeNKG{(Ugh51@t=UvT7x=kAwkYH6L} zp%PUlj31BgiEk_EsBH0TsCy8yySw27FN6cqU!?ot1_ zMuhzgyKgQN8(PQM(xDQyQ5J!Ea#Rv~ck2BoLnC$QldiZtD5!A5jL<0&?|K+7UtZi* zzeKJbC?rGQ!n4t9quUdW5MIq&?$1?+0|GH)2moiFkJwiVX>$9vu}GDeOd3vm4qDm4 zz@?!y2<)K)1SR0gK4K)$q-q3V_#pCsB>M7ap;csx@6POnWqk)WA8fsLD5pi+Tak&b zKbT>i6YM|%??Nqx!V|@*t!>|tUSsdPs%^q(^FvBW83h3p_5E&11S37z+x8q!2)L$f z`}|~E06=kWK6D6CuL%9MMhwwSJFM8{Gd61=ud*V5H~^3WQzJ8!Q8wpi-8xQLN+g1* z>nR@on6%D?S1a(Kq2oGZDkX6h5@im58_k%i-X#-rmQY9?%;m%b{TUBT94#Cig4=EO zeN(a6A@acMFCYEkLq*%3?JMQO@_ENkaC&pbN`ti z-m`p!4}Qaau3kxrAM%v-aBmKZ&H+iBCG3#8%O)yZfkgHo4! zkEOeOPB5OtIQ;1Jh{fI_p#$sh$8&yn|| z8Qq!h6DWf^74A3N{My~N|A@#;4TK!J3Z+f?Jr}jL*s^ zW)1w-%9jwt--rn=FLmbA^7;&2dzFx#3Sm9;Tau{(t(!`{^rl&82K2HkA9Y&&u2xxo zO77{I^Wyh+{rPTF^Rp-W&xXg1#tHBW{FoN*#2q#Abbfo>a{cnw(Q=f#!L-9&V|C~m zM{cZ>=LCP|0_o&{il?N)-TM0KOI1v)4=n77{QlhFFV`oM-g;?irGls)LKw1l_`AB5 zY)uKmirA->+h^dD3u5e{R#M(1pM$*E-z?NU3Q_t{{Hr#f|1kv$uj;jn z!N@%qKWQ(aBqD03boI8;@P8Tvf8NUTMC_ucu|)>`x5lc+>fBs;)Jehq1rywi*iVxIcd^! z^)HQhcoC=tfX_zb8M2pNWsy(2flH1EV+(V=uJINVn+|$e7Gpa*U*5Iw(dC6+k$qEi z2QZ^(>vX4H$*)T0ANO3bf8sPj?O!dx(~gbn-;N~EJ;QbbE46PSvnmrh`ZPGPu9vp< z3;55oR4p?=NYX%R!kqNZ15C+Z1t{kYANCCdbRk=8l~tYgi$NDb!2-81eTUaU5q(^M zLJs=-XTDEY#*FbO`VHtHw=sK$em}zgIqhrjYOnReVzZz50pq$wcNaAp4x@en?6g%? z;EUYSzN^gID{hUozUdx?3)W;-N>gOD98*irj<_TP zd??%0>9_GlV`J*C;In6w_)=G(92z&)GeaG$%l4lvw8k)8C(%qttvFp^~!#8uz zwTJR-+}PBi%+j?53Ch{IxrGb@Ph=%WfN_kIb?to^LX4*rZHH5q?-SFldg%^5%zdsh z7`BM`mX6poBINiL6All2GJY2sl5<(J@r?+9=Q#ez>>I*}yM7dS!@gqmK!CNg0QHuJ?lZ^Lun? zR*0DD8A=+~*k7Oyn~uhS+Xp#u8cp9>nNitZD?JJbuwd1#Uw)r&l+WDNL4U&1$Qg9D zo7Ig6C-3vDHMm1FnZ%D~8yEIh>Z8Yu8kNL~X+?P+KVv&poq(wfW%*l$X;MXf6_fH+Xf~cxnkk$VbUM<_#(od~0yfhe;DBR^ z6oT8}7#tE2rfqX8{~XHP`cSr%IY-$0;>k+{*sdAW_)vgrcD>UU^%11K?+@1$VP_mT0-bx7-{0%z_hdhaw%ST06o=QK?3 zI^}4s4b6H}O$09Lg({3pv44`4RdPWGMY>t(F&8KGk9vX3F$bsY{5sc+y(`%sCge`M@l=7Vkct-X5oOh%2d*75E2=^gis zgz(vgnoTS6wfV_f-Oq)W?Os^W*17kbhxFx93Q0?oP3sy5JxgtuO-}4*K9L)ym2e_I zN3%n-M>;#FOx@6EYiuynw@i;<@pu|l*6p`;K7n`NUj(W>LDVl~o#V5ZYN2^g)g}XDHnK6&`s$LSRGlHv$@%O}JGss@rREQlQ*{x-N}6t5 zw>Ec7$|PW8a(yTi^f}H)2})nW7EfJprSlNq}o{5+C>0Qek7a) zs-7J&Q&{%fx1+oZhGagoC=tWWU{n>g>qcJ-)R~VU^n1d}tz;=;R|?7U;j`#Gorc2| zPSjE4b5ei+<}slXXx#Y(25lMmR1&KQ(cG?R25WT@O>>)Dw`oJ@=K`F&dUXo-myL|O zZ&v+WEYBYzhmwHV{R2Y>#iM8pW)7)W*RE!V7c7FGOh`E+_;@E=wCyB;UtzvM4ienkfeGTpHN((*CDf=r-(;%>Z&!{*igY`Ho~T8 zf>8vvHtX<^kT6AB_-iz6ZDgGt)FaC(Jy+24|z=)Mz6iP)e>*+$sv*;zp$ePf{h&D{}cTNg~{crO{0o0+~Q{ED_go!TuF^4{^A%6J@w zB3IH;P*}JX4b>#(Zjs}!U)*Ev^ur7eULkqAuBaOM{dU(T!|aE3u6<(SBFijCKG12? zkh_u}qruvgJ9X+4tMh5^`>)mBrx~+DIyjE0N3$6HYVv_y>CV&_FA89IIyV^>w`}km zr`V=#?kk+=&*H}PaQi(s`X%HiJ#=w=(8kGzpjRYLF-4Cd(`}M z=Jx;mb@>e^9;qwUN;-%Ap1Svg;mecivhs9Sy;}$42sR6c$c&Y$N%m zy28IY8RyVXar7l^w5(6lPaN~9`7H{Lfr*}v0oQk__BDYC`hJUuzl(iL+MjFw{Rwlw ztHyt!e}DCqf9q^8!*vv>#lE<#it90smf#zmH{ZuO07jB^TJ)IdJK=@7d%17v+m3 zDQBXG$4!%yN>f#w>g#lG!C$pu-kfoM24x4YcBG(@;>z4dH~zS8YHlf`=@x;n+_oN^ zt#cMkMM@)5jf}J-#lv0enRfd@3uH6D zGQSuVl|K%;zV#tVd;mmNTTl9t=b|d1uvU8$hV5(L+_6NE+cAO@>N8xPQO%^W$B3lhI&! zWz2_1#=P%N))^0T#8e9Ej6o=`72vA+d7$X;Vrz76BF}CnZC4K)VU=^4Dls0I+2cmbel}cWjT4$ zq=!09fW`BXuRdq!wmXbzfR#W|Q8pJ`RlFbzdhx`>ydm@d>FnI2a!%Vl{y2^?In0P@ zB&Vb#WE9DyPzVp5ghmmfghC9Rgpn8HRMe=bl+u}s944U|i9sr&kS2{%4JPFf*`F)( z?zQ&2_CI^KtTj_TJI(nle zoj74d$xBa1$^+81H^}A{`&y5rSBzI&7~2}JJeL~b*xKZm=p@sG$wPr{wPHo`2W5)O zJcqMuj>!>KW11&tf+BbrQo~^UuFw16p97^3x9rHq$?VImPc7h4cp*{^)zq8>-*3l8 zW|y!y-|>+=Uq)7{YwC`}K7XCv`O{Cu0Q})O^ z%NtZuJG*~(qm;anDwW4gDkQi?^vNmr_~EB&tF`}P=V&c^RZjKNn;V6{a9R*Eow2#Q zT=N*4npxqt3`YH!b2MEsK{$`kwqARbfZPaRuZGYpu=v_BmTgO}L^-V6h3qXB@BwF} ztF1kS`3S3FONBAp$|{N)+HmyfXP9_SJe_+|Z#o4D+)V(7>UH1WwNZ8K`>#2_%yjvzZr9V{ zq!O)k2E{iN)V%S%us&zSN(+l^;xm&fQrI!t)W<-vN@QbYl)w$JxZ-xJk9kH9raRy* zu>TzvUj4)KbMQ%9QMOCJ8Z=o+7n1BV5n}u><#@x^%(k{(UEIx+F{*mGfiQLyN7TLH z&tZC5D~*3WEISge1)%vNln0}CJ?PfcjPrHdb1Oz$KIT3GPEYK#B{!{I=~$z}A>GVp z6xmIl90E3fc$W&8blHHf;*Oi1)nNY3+mnFQT+&mTEb>t*OsAW0lhI%h zA(6bHd{1$R*810*TPYDTObr0~E>LPvjaAw%p1ee&XC-No4<~7wnl3R_&=fjsv6$bbvwhk zQusQN3HF@5bkCt$3L!7^?d8vn`*cN0%CCIsnN!xGL)$hW9mCp@9`kyYw4LeK|Eqre z(&$2nK|R%C@i-Pf3P-#EGMO$^-ZJhSy8EG5b9h`r#!chtnEMNf*LHYQQvJ{V`Q(Y~ zgEOnou?HcOhLiR8Gp2;N455<8N*M$P2;S^T(x3)~M0AHO70!VTbElYcmfHif5b`b1 zv?Sh(p$Q#N=wfVnb`V%9xmNmWc3?81IC+!)mj{D`V_1n~tr>D*R29)yIF8+JNcRTm&3CXK;YdpnNBixmxUfwrYG7Ma&A%~Ed;6gUu@FGg@ zI>b*9pOcBLKV?CVQ(<(pE{OMz%o-dk%5|O3C^9KHT(JH%onQ8MOIl*OK$T7^I^!3luDakc`Go^O)WSuQH15DQ_ z6x{=-1{KxV+1M0Xm#J49zYbKEa2n5vual!fJI&nK|0|V_jiEX3E$A*X8$W_Wwwk7< z=3ck6*J$|Wj^J3IUO>ovMHqAEiH42$JI9LE%+;6ZAQv9#*K~-JiL*Zv#NcFNF_R0* zZmI;^5e@J1y&?VXVYOg9YK0r5#YY-&*RqgbH4=C(&6bo-mqmqVd?C{ zRh`=fb@iK29y6sI+*9`-AD4e4CnnBv%TfTKV)}iUDr3$gL zU=~XpJ+tU@$N7lI*)}8ugJd?uxeo2T`UCIy^6Ufsv<_DW!mJWl65@i+I)h`r ze%j_f%l4SX9nRt#3~#%c5NKkhwSDuPlOc)1-{>7mbL!Ei;5eE zMosCvH_zXnEG&(vs{Z_w!$VJbzvnsxN5H0WKHE;Vg$=bNeB8wkDP*vCvPo>g&T7WZ zbs2_O#i0Ta#}FmmSbM_QkWi&Sd+zt#XN^&xrjcQRNi4H!N^+^ip&IY3hy-~-T+6f5 z)ze$zq!!Uj<&Z?W08O>P0ioCLB<~+?NxjVWFDV-9R|Y!k3>YwhHqiU8R~aW%4%X6g z!##y*^e();YL6a8D}10%@Q?IVS09>HmV%1_4&GJp(8$Gse(zadu#-ap9!x|2Va{$X z!6jqp>L%W)JpXVN+v(&(5D}UxDZ<$iy1eO)R7&h?l*|nw-6Wj>7koY6b2A~GGok4O zT-Sh60ug|TM?uY~A#Fg?pC}K$US&ggdUg1@?-ZIACt;L2+kdqKT zH9wM44B4>i=u>~nm_5+6WEsBl!I|5SasWXhI6#1bI+nR{ED5u^n2I!W#r^bNuV+p< zA8P#fONL8|5!#+PoL`^9ZuDd-MS7B20dz`G_64AwkKj#CVJ(9(xu&lIT)m!7ny)Jv z4iQcA7IaMIBlSA0WARujn?e(hfV;vL^0lXX&z{G~qDjot8-0IZz>L5D=yc!UM)0!% zg`i$Zg`5?EF`bbVx_(B{ie57eJ~X`bC4d%Djtjf-j`2*Dtf z2#jC=!TZZ!+;-4evqT|9$olhImeL@Iw@6DX!4-ZKKMkV!1skJ2tC}Lr`uB&+A#3Wq|BxYv1=d5x!u_eetXBjwO{;}62$32bi$6{lv0o`**%M#;>w$-@c>~&O^pWej$6YI^m zK^z_Yju*|IKmS49J)WTqAO$^sC1Papihhsn26mUlrO*g7tz@t6Y!ZOU_Nh#wR`DR{ z6>N+ySW1Y^Rp)93`5;c_o3=&u&dWYyKrO^}I zqb(@!5XHyrsXMmjO$#VC#0A=frInfKd{qAg~u zr8UXr%el8cB?&?~A?3zU5 z!}*klg&Y-mhss|WIo^>vqKM5w&XKb=ZagcSwR~>w^E6uV`n{|7O0cbnGv?+xtZh=Y zH+#wP0-QBk?eK})3+UQ-M2_?tWGPcdHa#N9JwxVnKk30qWh_hIYkN#M1`CErNpv)A zsWe?OFN6>eKq0g;PJ4|{9(Pugr_YbjrFJ>%Z%5FG5Z<2J}!FBfKm*CXqg+=h(>y zxtb>UlC}st8vcD37e@l-?I0^4uS7z_X+_FSij6g=H9#>h5AV`*Y%d;=un-i)O66{- z>edqZ0N)~|ThDPAsk9YogOTmYhvSy$&~|gL=5GR{sTqC7J`iAj=W*VPQ!GH=ji%pQ?p_1~KpgZScyT6)8299|JP z_+VBFd4)3i*p@9hSEr;a6l%X%noqE6n=<$0(cgZJFO1&d%-O5!z~9dxZiLZjyE%Zm zjgSW^-jPLf9b^hUAExiTB{iqTTY2QW`{QXHZ-e|q5I-0erVG_bnfZaEjO~s3oZfyF z>9B^j4J)npD6?k@5+{@k%gUjvufA%7{NUT8#j33$z?Q?smNO1Pv2bPXlTM}Ba zF#3ol{p(8vVe`cK2acUXDgW-~4;NzCg2f{t+M}4;e1yZgbMM~qh5GmEe7ik;xj_`~ z*Ugf~ctx{QDl=9dFr;5RTZETGmXsT*b~5_%3UkKIL{Y6uj2FvY(Yw6#nzFFCaO%Q> z@dk#m;ofR^8;{eoIsVD1_!)r?0h^P9)vUy3VVUPVz=Qz`9{)wgdZ z=CG^jdVnD+DFAcX)579WRWJ0Thq%JLp4`-RdoBz(X)Mp+P@=OM>nl^+xl6~b1R~d$ zRklU`%G||agCkcy^TYg$Tgc^>a?Kmv(cl?qA8Hf%gGmu_i(&7ZU!FU6E;w}x!3ges zwEE55AK%vp|HDVGGY22=^(Js(6iZyYSZ5c&(JidJw;7a8Olp6$^j$lq?!9}y(zC+z z&CgBa!r~NvE_scbR_@Kg+9&Sh+qc_nmedffi0{mt;mda`Fc&oa^i1R&IyHMbMQLb? zC{a+)Cq+y{Cu1^k)ZzHQo{sKf+ooXrm#s3##WAj7=Bj2-7ukH$I--)0GUWXfj%Z;4 zGq>%y&i}tq{=BxU@;}6sDBI}IApie|f^xWXc_;qd5_#|UVS&9$+It$IxA1j%4*}n( zPh9{0H3h#mlP`QX1}^>dhF%+#T^`1LeCIo!1vON)v$c_91foe|BE;Xy#;^$`Rk5vi z=ruUd8IG82p9on>)yN)PyIloOUUcMW+XMF>jm-K!M2i{vsaiM`=e9sSz`TFks9@)0 zq%Fr#XEk!vs#jrg32cTUQi^t+uGj2T@nZ67_t)K4JbzObp4x^jFr0(@*+8=%|6KSq z+eveS9(G^V*}UMCQJ=1qV=&Wt-3O>`=FPdYs2*c~37u-&?w*12^1k7|CVg7cYDSuU z3U39Ut6$pQ?eGAV3UAl?k8MPHYUx3%+O299rTo6m@QlKzdl0wBSrO^ zR#i+dMYOfYbM+H+6%i9OT)w(@v)b#&WyQ;ykMoO9k8;_?EW-%5xsfe_uPa=9(|7;v zkvQU+P5IoL%Bo5F+;3@b=3C}TP4%nHdgkVjy^8~#PkhiR%SqV0GAxc_(*BBeX@Api z=d#PM$-UqGd(RUqrn)=Z>8q`<@2hPqSD@WmPjpo;ZFozbV1=L;!m4|JmFZmhpz@_G zXiBRamv>gK+&AXVA(weDE1v{*x0l9KIu1OWDTbV+1Kt(M7JSoj=6l?l`TfiJxR3v4?p z6q!BweAmUKE!EEX&tKcBE&G{+ohgAwzp9#B`{KpN$rcvYKWkI1T{Tc{0g4y=+4@{G zqRae>`gATg*sohU*;Z}Mx4TzgPY+WT?5zCd%dv~v0(ZHXJ_8k=9Sh#n_E|T<9)WdYWT?;?w-iFB7 z28c^QEQB=7bzgVCP*XhwEJ2siEl2#{xrH>FD0j=HdFhE_dNB3xE)Cr_y_qBeJ~fFQ zEdDe9I5$Di; znZ)9gt9rR1EPFjY=h-1RAg#nbv_5LW*06(9Y@hEW0|M==DR0H@roS*iKZmZc0YCv*da$_7T{14M-|vMi)G z5;aL8ju9^Z=x=B35!G<0IJO@cKMe@&g_e~>K58)M6Uy>xS5P&JM32>iE_BsF(}!D6 zo3>LBp-IEcrwx9UjRa3Kl8);bl7!*H zivf!tm4nlRm4sA22mV^BX3&RPb=354E0YgZ@x9Ie;O^S&g`S4k?rZ zJL>Ayt4lBCGgGMR3hLehJ0PlqVxbc7Kz$$LBHcp(v%)unJxz*rd7tCQr^55Otsc(K zE9j{M&T7w!;`g$4c)%d{pT~57qozzLJ<=+oz5~{#EY#OYsESSe1bge(XKiSCX|S~2 z<^b{7vUf?Oyq5QGgh=SHhc0vgknaR05Ruy_2as0YXrAWNYik=KP+gntoZE{y~F*H~Qz;CbZOqx|BJ ztE-Je?&V>vY;yX14vU0@8*wyn$(#+5yfKLNy9%?axuQbj6p*+iz>=-dj{J$tWjVvk zkMOYm>}$;E(#6TB&s_i&5P03C4qxjG9V*6jB5MIyN(}NhBF5Uv$_Ub$?ggVRR(gUN zR^GK4ufI`OPm-e_n>K#dw#_gOjG$%K^7F@c*%}UUwf%;+BJ#(i0KnV&>XR5zSplWZ z+S=OUCe7N^wS8Ne?J|!!4tv2r2+|PuCKsC!6=fzG0gpONV+`>W+VN!hbgq_TsvGH^ zb87DXf921jo@4}~rr*cLCf+m0HThbtcoT?=eQ&zxIzo}qI?stK;aj2hfZ!=WRQCRh zms|);h_V>CP@wCu1sCR{1f4{IKCpj(G&{Pc2Z_Q-#lAEz6$XpLHtGiS#T@{1aX9s- z@XH+$dN2S`tz?xAqhQgR9^%SW3Tn}afUmE5^5kB$g}z#*&pPH{4UO4s!HR5{Pl1PX zXDy3{g)DlUZqsFHyD(%f_%26V)Ga>c<>b`=O;@z z>AOqc@8$+N3q&r#AAAh)L7b)HyzMz>el$K0@w3w42ATf=VvC?qA^@ud#0w^_#f`VG z{P`TX9EmVoPc4oK;d+tS7LR$i*VlB@o7{c}Xo!$dn=)j{i?_bsNTOmhhwIkG2O<`v zrntwy;-te!WaH=Omr+7#C-s=K8i3+1_CgBxc%rczjX1^FD8|-SXQ)bttrH{@lT%FM z)~;~)5NHL=@bVgLf%U6K*YVx=K9N*QDD7gI7XQWv(%^Wlh847fs^uuWJA(09)5js~ z>F!?u)7K^0tmg?>&V_Y8<Y`*=f@38AOP$M!$p=Lk?Vw2$RzKg58a^=c1ZPT|q z{F^c&Ymzf=qEF7@9YshXH4J6Ol0I%+do?4(!zXP4<=jT0GL56|_P&f9`0h@czf0Pc zbho0x48ueEMG!8veUoVx!)CkcEnf^TxV5QeEgtV{&tDH^>$1q2E-uH&-4e;z9!arM z11kk;1UlLCfc@VUMN0J~cE5+?DrlNnLd;GX@Apopd#7re9Im=s7M-xa&db#j#yh)NZn=oIE z>=HvXsyzIvr0g!T4N2S~jC<3dC}4{>hEuVOz~~u_^RUE!bz5`qcZ+UqUGwI|PRuk^ zzvpf5ET9CHWKR{Nfi1T%+DbAT+;V79&4F7_izxIOp{!0D|1R7e>@v9Jc4W&d?Z*1D zIjm^p6GEkU<x+32||gC9Y?<913?D)xDD|;i0J#$^fY`F*%t@snxI@5HjStk-Mu}l#_ah@2>hR3%O6%p=v76$n@F|PP```r;;!Yee`fwlSJjtpw5#~ zQ^h`XmrCy8(U)&O`N2bB>{yvN6zkCJ$&)8%n0BXvqQQr338MNu5D}3~CyLBB znh4r#u*m;y&CY@V)3>+uOlB$+7Z1sl)hIx$NEB|7ifLHyC%_>JGYGO_L5*-*49+w< z7nTn(7jWYyk-E(=$8&Z922cz>+^bl-&EQ7SYNH|pF)!d13JUtFvlO_Fz~z9M$A)%s zyhppG`0%-znv1UH^Dc>!!Yq-pj{l9MHsCI-Se%3{?N4`pvq6(r@#OMkg1NS8l3O zXd6xHvN}Ha;H_H*oPu2#{jXL}YK;D@eZW&4)ua7cx8bd9k=FsIuh}9&pp45;s~F|@ znf9nBzv-)xQ7C1xf^=>)B7ZVBTg9e`L(LNqS4-_}E6afG#8&E1)oJQjss$U&A6_yf zVHS)G>NeX&Hdlrd5(a4r)MM3!-j0?+LG=$z4t%>8kX+QaV{DETaiWN4P0@>}ye zueAG&pW+H{#mtA|Ha_T))YmCg*;s>c!TD5&;)ZZOg`@wZ`v4}wEDK_6pFKT<3Wfi*ezljM&=^0MZ z9F>LFBu7ql?Ay|t?X1qDxFnv2_SRMk=F5rOG}Q~0rZM&EPqu&b z{dV1u{JtGs=Jg7$I_=EnGDU<=>+tWMU^&cN?eXu$?bh8tS_CYkWmPw?u1BF{99PVGyd%$3PQ)sM+xShmda z09!1Hms9y&;CF7XaysO9n-w?(M*5Op4f)o+4o<@2YwbM$<24`Q;%C|h(?&8T& zDk$goqoch^-Bk-LNf+b;@Raj*Qeq> zJ-56rfmrFfJ?6&c?mM__?IQc!Ibr^m9GDyUJ1R literal 0 HcmV?d00001 diff --git a/media/devserver.png b/media/devserver.png new file mode 100644 index 0000000000000000000000000000000000000000..003e4e0d6029ef78376eda327877062753e3cddd GIT binary patch literal 73249 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 E#(qm4RXZ}{RcCHLb?%@4t@m{l*TV|; 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Ν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 z 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 B0tx^C literal 0 HcmV?d00001 diff --git a/media/esp12e.jpg b/media/esp12e.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b9b58ca6804aca5f02d4665c510a4ba3259daf2 GIT binary patch literal 17509 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 SrH}srhmZ4rD(Wy?ng7{xPy!DC literal 0 HcmV?d00001 diff --git a/media/esp32.jpg b/media/esp32.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1da1222488a40c7a8a848412f4aeda5bcbaad40 GIT binary patch literal 26212 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�%d0c>oV_YpXmkd zO@9eHy3#nfLxdz{H`>sF`0g#Q}@{vQdx{F@833P$6Uj8lNv49+)eOQa8n=R1ISP$#mQj zA>5GPG9ZRJOM{=v>Uo*rSG^e_KG8_c!-Ng?0zSALsTx0#sCElzD4XXEuKX>cro zGWWRIuSe&}F7q2!UV3F^&3zG|gd#1&0u!W5xDifNm2`R$aC`zuUd#s>*+J~?3qw_? zPpzA_Tq~cZzIw@i2IVi`Neq5J@JJG)CeC$DyBcj9#Z;sqzG*zzsxj}&l3lphW~!x? ze*^{o4F8_36gg((n*mt-#)JrYlW00){LHH@w%2%QMj9t5W@o>PucP|3w2$_9zt`6j zRkhhcy!2;;T$wr9G|Q!799j3WoSmcVy~Hvx7ZLQ-T&@=tW z;^7vJ`zf?}#j5(}bix4f=qAx|pRUTQCs0p|c3D;2cVaJPSZ-JPP?bflB&~QnljhrN+2cegNibt%)o?Hnj?+6_^><>izzIizNH$C1r zLqNWon_Xo3+$w`5KOZeG*7F8cdOEKp002qdnY$%JT0E5)g52hQ%xS$7kuDCXvXm5V z03Z%_Jo^h+LX~t}xoa3wQ^PVF|%sTcM1a)6*o> zBlP!fYO3h0)Stt3opd9m{UD*CGAdz2;qjJ z5_zE551sVy)x2p#0H2^Whp>R_u?6t-xIrr&Xn(^fc! z8yv6od-nm{iUPl8aPT!_9uNx9jve>YCVLmykMW7FUMP~Lx(iKKOiG7+lDNOYC^xRe zh>ZEbLId03AQf(M;oiR!F>0W+1I@kfhL*Z)4DOrEokaPuhmgi$qq)F%Bw(7ViN zx$VWAaHkeO6e#RXn#;tdUxK#J(0g0pU6#^6EXi-S{H8RZmr+C)5h&|-RvcZzSOO)3 z%A2G?M?n63l*jBGt%X;G4*p`wX*^zDG5hw%9lH&=$1fP05Y}U2Lk*_Fy9WB+hi6qk zC_1gtiB&0%M(J_+h3kY4^yrGzY9?x889WWP5WqpLjWTSEforntQw z_W9q_EYYKxRO=HENA5cf^((QTYfcXz{sMlZ#ZQlHTUzH*TS(JWPp{7^UgGx|eXT{C zaC4b+W$jOJ{ss8{X+Es7Kpq~}=*)lTj4isG@dTS18ZC>)*RFOWxa_232l!^wOMk}K zXB2UldC)~m^@HB`mNjqK)i!IYa?z{1zMWtP0D_mdmkS~TjEdBD>7_?1)79ICjXtGg zLgT=hnH!$hzI5F2rD+7F^x*IVIjC??r-4G}oJ?qpw}-PfnX9P2%j%$q8(W@}tj-;j zx+m8_NYe9hoxqc35ii(&Cc;t(Y>V~&()(9^Q5owwM zJtgyqIrflQ1evRZ9u=7h+MCTBUopIj^qf<7oMzZX?)Z;sspUWm;pb?L~X8u_1LRwHdpsaxKyI&x)^u` z{Um=rhOpdBdbQDD1OsX5*oh8zg!_1}4>uE^*9$bUqH!5HNbl_`Sk^3M^j{jdRc^$*$;(GOFC;CQ3p=EnHWw?52fs_ymG zTFH614MSqB`2CK1!v>yxyac$Z+XhyL4S$4L*l1q@D>4(Lvf4z6UFjCJ5X`@%IkM8o zm2SB;L^S1mjq3jyZA70>ihaDQrl0oj1Xg}f;PAciX0U#p&~WNsTMFl@Os_d8RkF(K z`N#v^koO_FmJgi1@m>jOTf}vB&v_#ir$zjh#>!3EC~1Ux2otA}M_P4S)Xiu3G#=ao z$>+X$@fUFXazvB4eR|{aRM#N5G`YNEbeoJ{S|GL{G-uK$co_08DXUHPu6oGJtzJ6K zpzwe?2@&tytAk${l>c$H_!L=$xt_GEUyHP(k0f&yTVyzwA<-B$I2H{w=y3!&c+}#= z{qq_u{fc>{DZHvVE3JCFk9!6$T1}_TsGaQM#!=`^WL)6p#cRQm9~i(?R_@75D4Zx( zw$on?4msOS5)KS7?MHg^m$%+2PY>-^FBSS`7M%4pH1Y6tY{_~b_a+Rem-*oTIuP%B z?w=;(%pzWGFiqk0xQd{UCz%Y}XWup-X{jox0ZRwQG z-pe6uLXg87SYp@+ zp#g>*K<-fajZ1tcbPhh}7j$VOq7#(ol_bBcfzDH@XR!da{j{lw1RY_ z*CW5gT{hbE0uP#>=K4t=|I&+AJqbKs(BLr7Yf2hnI4(ZEe!Q<|jyK5M>z`iD1_dWi zjOrvt8TsEu<+ob4X}V_Di;mDa_)mxq0RvyFkJxAS*`^+U%+CxIQl;`C+@mUR2uJ;n z6rT|=nGiQ1`%m!b6Xp=()p4EBpOgGs_fzMddFxZd#bF|ZKj8K0;ppcs=>wG60*m!&A&3lzQ>Tg_SMY5rsfANlusW@8dFweAc;%apGpU0j}uZJI4&(v z9{TyN-sDigWQ&(kk)xoQQ^-`%2_u&hYGxY)V3fYFf77=!&F?a|9qwq^u11qe=b-qR zXc<8&KROcGmPzj#ffNQ`vzF;>ea%fVYq{B(ZXR+B3QiNvw$Io}?+t$lm^;AvMShP0DFYyCgbQnx^afa2G_2nzqS_R)T$OhfeYB!iq*W z@h2^_Z_ki-_GTOtRgF#nssC? z0Ep2PuVthNFg7s=GQeUWIBb+809G?FJg9eowTg_#ed{CS*g8D9dG1+ZfIStzNdM!) zFs$j3MjOp8-QjJ^ZCMX7{$XLc-ocHR_yEt_ufuXN%Lnp-D%&CLm{=OU#^(+;V~V14C2xQqfUa@ijdJ0S6?736Df^U zR^KB?WvM`U3@Zd@%;7OlH}py(Q+6nOE{4$l%FgcyayW9xmv5w`aMp@Zar&B2Ij718 zOWqRTB+KOtDu^KRAwmB4(RnQi1lz)sGa(~1oBl@*E|V}f2n%8J7m&2?*&@#6Sec(t zam?rD+_}aJPIs=TPpz(b&y+;~0!ZTC>5ULDPL&^wNw$#aT*#ZyGD~|}fO7Z1`CoQm zDKVNRV`EG|G-aZr+R2|NmvTO6NmN?DsjM~*#aVx1WNoXNXVili;Zf3G-(j{z@ zrNRanSmW(f6P7)f?9nELq1LJPXqloS>&8UH=pT73#j}dkVrADL>wF~>>0Povs!~5k z7w|rS=ypep0(+YD>1YuC}YQpN>KW*dK@-MP(xhXM(k;cAl}m|U5VFzRwJ1 z`hMJh%gb;xI}w?=TWcAZH=d@XH~3;JCttzicG0Oz1!0H7PE8X-C<9T&ofGQQCF-7+ zLugHmV=0k`pOu+RvS2Mh)8meOPwT$0olsIF6_X;RBo4vyKi(1vAV}rLpGu7#sT1Ln zP5Un~-aXXcB>RUO8!JwK0lt_;W`rgh#xDJKul4y9aU1?gU_3V+M9zfc0pGs7nQMgi z2sxB?M3`@q4yRnS+d{9@cz}ot_z2)P)j{AwvDC)Fp8MP0;#;4?LrZ*~6)sKVlfh~k zE<;*FD_$G=`1B@Kdubd{>|rL7#D)tBeX(eSy=Wvlsvm4WslOLU`h&8~w_Ae_<n?|Si_JlpB`m_WT>b*!TT4~#%4Z9lR_L}_d!@+V86G~b;0 zcw7KJ82O}qg2jUiN7Fep6W_dbFX=&qxS;R>o*zZKo{C66pZZ*v zGEMOKZ>!g`TZ%S>y12M|(J0I0gJXu&;fgdsDcl-*`hJ3j)r@T_Wckye7bz}#LT2bU z37Sd_pdizeFz2-+S$)TFQ+T_Xt^kV_+T=O^KMOx;fI|LU6S)Qk)!w>M6Y}BhRHUw> zoLRUfC@_jYrQVo|!#>OTLP5in#ZUB)l55b_mjGJT44Ul;G|4R6Va+)CwFn|{9ib}x zIdZ-=A|0{lST5k+Z%&9BY*9XhG%}Ey_Vv8 ze!d+!|KARtr!=ixTm00z!E@74eY9Y$Q+ZeMPajGjt%~$?#m?)DJ91r%J68YLR(~M; zVE%r$)Fl0aP8ayawXCd-zxgSQq;X0og(Nf-uEfq-=o_Qg6YiOvFx>%EHa1f>CW15~ ztTkEmh<2ul(vQD{A`e5=%(z#qv1EaR@YrAX^aW5g}H|LZu-8BfNp^N0DWgso4iMwRCme!7gv zmYJvQfCN)%C!4D#P|=7?26FrJ5;~P7LvTw2vU%|c z$(4r)HTiEJ2MwJjXuMqdS{WI%hfI_^nzkp($5ea?lfJ$II8 z0d{1Y9L@Vz9X2*C*0uagTJD9t-o(hlyY%L?paIiYTSi29dPCF{HjdvWza_dCYM`{M zqb_7;zx%qVsPM zb@6UxAy$Wh*Ks2^2YQNHX zQdBmwzLbW`Ag@V3FcZOCaMYrm%7dH0qS%mVv>-08rB`B;-j&ih-chai@*k;ZnL-41 z*{gY<1|d=wWKm{b!67NKlaR;yIb1a++&Om`aV6#;M8E)K%wIP))RvjR;u;tj9i8!P zrz25E8cyIW$H-MR-@8rmfy6mAd%k&XOKo7Z&@95pI25X9K-<620pbM}p?u1XQdgX6 zpRK#?atXCHwA?J5tMCb>JkdBDRaTnVkv-FLT$WHU0JEReqR-8$BqY=90xnKUV^>O@O|fB^TI& zR+K*!t61&ruH;3>ghlEfmNN4h8gr!-O<9q8C3w?0^W`v?#K82M?KE$3P_^WmuI~gz z!d3AC!TIKk(z(3-6V$%%jk~_O@tL&qnHg%DUXDH`BMMZS{LkS|VmNBMx7BE3dm`=E zpQHzS3zzvuwCe#|#DaKQCGBCq}M4l!gMY$Z59WXjJ%j%+Gl0@Yfu2q`<_dcQw+ zfq_21_=*T7tkIzEv@X^;60H8Hmo1X~re3gMj4<$s-rbFNsG6R6$AQgL)6c-wJRLQ1 z!^rp1LIqqCL%*c`OFE(=6x?a|n{mO?t9JC@J7s;G?EU-W;|5z+QM6iJ!`lEU?w^`W|x0VLU-CUHmWJTWN1rL?md+e8yefnqj)LfbX zqtPZJdM*6vY~(M}SRHpSzrX1m7KSe`?$e^+A)39vl^Hd8?OLETJeD#2;Qh&!<%gJ! zGo+y-Nb`FE2zf-y3!XSD{&`k?bcd5p#hvTm;8|a7o4LmxYHwG5RRgrcI{nF*$)D(Y zc7^%%l22R6X)jbc=!$N4-7jqC>}K{iG}5}k+pf@|qh7?=+MZ5%zeu<_J<%H0F;exi zo5iQ5tfpt=YV^{G8?2S20VZ5a4RgL8PF_20vgj<$h+?6#eiFivQJ|Q-NiA(*mBXMf zv2sLC9!NBNYbknd)>u{~bEW3NS))Nm1k%!%P}(^yx&tnmC|E9eh?DtOU$~d#q|KFP z+oM9?QH{a##<(NwO}zL5OM=>GfCJw%NZov4_YU4L)3OAKYRizpo;nB^6ftyvA_jbV zGX1LLk};Tf6^Df7uN}M&>vp}9}BhD@qTy{4=obnWc_tstt_RwO^ z41evLiq(U1-yr|;89lq^`n_WuE2RaId!=zC6sk%S=M!d6)?w}X@Bd-bQi^0{L)6q? z>Nq4w8`_jjW1L^hZlmxY{D{=lJl$##6-A-g35bzA_#nUjQJ@;No@XlUANzm~4C|6t zVFYg4FPia~@oN3eBaHHqN=mnr|!_tXd~AKlT0H$We$+F zKR{zto^bR?Vopntz5qA-#!TNSHm>Qe?DrwENX+avD#-@?bBueUw7}JePDMFGKGHqX*@mpYA z2<&7Y0_P4CSO>gX)_&y3{En2FQ)vO+czx9Rz5_DMoc#Wyi}?5VP|-riC+paU788@A zgfHr8inhOspiOgRL;*EDpb^ZRy3^*V*{MXe0Jm&=}NpBh2V zBt1Dhuc?7PHpR;kC(WW0U?6`W(}kIcQvU02)RiG6&-72 zjJEKa@u=b$N_fExH;cl_j zpdJ7*npVUj@CZMW>9&Q3WQ9UDS@UZM&G)d%>2H{hU!5pAZm|K`3(isx+Dk1jfwpq* z=%g?4BB**pA*kvq0hPEBYJkG_lIhp~24n4@*bc1p?4iELe*qmf;=or2hs;>9q;=~;DqnE(!OpunBybzBpYTAKR{pp63h#1DV&yS&jc zKR@rf?9)45h`i}n^M0o*hw?Sd-g8ik zc~#jdY+#J%O^AeH=GE2a#)YE*@+#}q(xI;@#@agRPe7dUxCMpnQT3u)+l^UA@!c&l z2+~xBNRxy7)ZwQXM!tHi7+cnEZjbRvQKTV?Tu8Lgx}1B&`1m8%@ta1p&pze6joms` z3_@1M*#{E!7qB@?@vGo_iW^hBB=C+1)(8^u&Mn-TSHN>bs)KgmpZ;?o#4k$f*F* zd7l2TP`V_ZiOe^%Z{}i0mr&9*uE>{sZxf^lE_r026q&B(oci29z#m=Z6YWdUC1BF+w??wWPKIYvPmb#1!;%@fzi(z1N1O=+=1;zV${gJUdC#7dWhyy>upsPLr%*=JK)*IPgNZM#PW3>{AfhWZT!FAb zz#$@BHU>x_4V3pXi=1jYGWhM1U!#JS?L&F7yc5ZAE+n;~FCoKV$0T5GvMvuU`OmJ( zTaK@gQ(r20cJ&p?qKe$@8bu94#?y?WD3!T$%oK8#8P6!l2PZ{1F5zlRB-J(>K#Hft zF-Z}SyqExx&n7vFl^HytS7sR7O1}^+%qJIGYFHy#a?>R{9!_kN%mL|~?~hG9UlnLp zt%7b`O;=S(B@G-2W7 z2L)YEQX2q_XMWpbL1yAPU}~7?)+&f9>6IoGa01H3RLC+hkQ$Hq z*2b8;m`3vT2e8&8s*BBm&5(1eDA`qRWJPVdgV*|Rsg3^tL@OEwA&`y0$nT*y8dib% z`A8kdTpbr_ky8qtx(}|PmR6Mtz6$mov>w8N)RW_sZVK){wv1C!MA7^3p_FFe4zV0yCD*`Ol!~tk+}l=PmYgN63UeJyG(lJ+kLhNVO&+$_L^-4zv{2 zl2F&vgexN|I%E(wZ|$$B=(tMIzYnPEjFf38f+Db&Rz7769{~B6uHg6j>xFRywC4W+ zR}@YglsG}(lpOD_9N74yyBzrooI6cZ3?XOye8lb04HCOhn%XyjF+#&)I~`>`LNj1> z_toBT7bl?CIbw$l+aTaf77Hvc9SI!>IR{bO zJk*1}wy07No%Yoe0NwF(hg0Hz!wC4I+YCpDtpSZpNOJP0b?Lsq5uX15`)~7o8d}?j zWu59kxxrGZAdqb&EDxCuKM-I;1K6%RjdlM3h943sto&*yWM&lA5AyQ{ASvv6p5N0w zv=ja#_yR5#;&r{+DOg!9SdmJB$rPj#$_VHi1do1TI%@osHwn-(IDmLD~@fwH3U*Irf3*3MjXQjt~37nrpm+&=alx; zThUZnp@ZhCBZv`#;4$|90O)I=UHFnZOI0NprAC$*!gJ#T8S;&~ZT)nUVZ>AT&M=3| zpFz~0%lYcPbmp?QMkmW5+y4L@bkyXVMRCiEv#xOU+8O9$XmREl$D#DmnrNr0lg+T} zf_2Hb4(Mrat4mXmvM^oyHoIH}Ruv=5%iE^DQ_ROKSs&T-STd}zO%-oeN?Wy_Y8rqD zVY6d(Zp3}{#RZvQyj5AQ9MIK%7$nXUpF3yNH|e&!ZB=?i`H1tA+qRItB2cBmmF{dK zNuX1b+Xi1xuco>`#rYD&J`(AX^L$^)4r{atl4^P@O&k~cmV)6(z{B#SJpLFyRVO^C zcj|MH2B}>*n(a|avs!7I(?pXq8EFG4c^yb%Twr93>@nBAmnfx<3drV`o;rxqKB=qY(x}wP`v{w9XH0<*V886kDsACf@^4KxQYpG zRM6By{{XwpzlJtA!=It+p2VKIZsPdmzS~UFNfOk=e|DUpa$s(Nj-Y})M?yW)uNGSC zcr(cZnr?1Ylnk%7eF@d8PZGT+$)Tf(+6G}EErT>?mkLSfMjHfnJvP>jdkeE}5Wigb zJBeYq!m=Yrw6L(+R6U6A>JO;;>CyP6!!H?CyIYci$x|VgkCIlAAx7LUn|@Kgf78=& zGoYUk_?w4sR(eP+)RjLs9wZVRD#elJMm<}%O}6Xmj=n2}h!!9nmpcM=t{r9#v&&? zvAM~Omu8K!dir)ddW}`4hK<^3WMRoFF)7~=!i-#(wFtcK}G?ahknB<3s!{rFe- zy?K{!sQPO~{(&TWQxArQShiAefrEqGYAI!6#Dx)pH&r+tKhM62TFO;HBRi|8L*f8? z@|-Xob~w-b>neDD>q|i$bhI*fGDKun8|6n+fw<~E$2w>GG+&@vBgr5{R%Rps2IQR* zx!NnNlTnMsE7Pq?_<*qla%5zj9@`Q<#+dk)(_n&<)-B>#rkVw2ZxOQG!C747A5u9+ z2?Tm>{l|9uj|Oo)o~pc2-R(5+)7R3;PaiZBz)?a}1;%!LiZI7*!vn0M*vB*YnP|1z z?$of`IYIETBz)z$PQ)CaT;m`3oh&FT)SqLn!^O6>;(4noswt%$u{~4V;t~A4OwL+I zkaDVk8*G8PoRi#Zkrg6BGERGAI6L&vl1b7vo&s=p&$fwh{F5c#ji4Em$4me-oyYs? zy{>|;zNh8rsic}?ut?V@>+Ck`uE+3`;k{KQ{+8!?Xw{=^{JuH4N2?RIPoVYdpq1zj zNgYzA)fMvHM>Ts?EP^n^Ls0PykTdv5&a+LGw1N~*4bnis5rfm)S+8pw$rz<)lRQ|b zD{($2pyCV6QT(k1Wo&fsh48~3RUNQ34UVPH5XJL6=f&ny=X`<=b=$rPd?^0_oNS3* zNU1+RM`A*t9gccwJB;{Zp2={EH`-{W!?J>-nNAJ?_t%w^9F%RIq-3QkLM4t1gf(*| zPC|yj$<9bSoijXT;N=Gdj=I&%LZg0A&A;^3q}XejBwSwM%Volr=PT4m8X}|*bDV?x z^yLU42h&udo-o|HArS-vosP25S_j-y6(O)UT|}EHz}2g&fMRajjaNVp-L;sbEr9dW zk=I~#a#YSnhj7_EoShCdT2;p9PPzl^Ts%2%H$iY%0G~X>?~MB6rghgiR-WI-d>L23 zSF-*ir!^d-@hM%#J;C4q0KIaHweFVNQjt#ltlN!`O*C-b+3D&j>**y4JWjGk>T%Ol z!zC9)^23x)GWIy^yjxqtTu$;)%>qjtGXaR!P`O57f_ygvVlqcCJ&4drBS(XtF@mE9 z`|Ifs_>19aIP-+z_=RVQMb3r}Ta-w5c)=OK1FDip_U0a%`L3P$2q%5;!#zf;k~Ps7 z%JyA)nn7XkR3Dr109EA16#gTht~4|cI)RLnfHjj~$l^YL>`2#?@tG$@#yN-uk8gcJ zm5B53`EB%(NpQHs8I(tu zJydK4g~3RMCaHSlr%ZE3TRWbFZQOrda(O;F%#vqkjpV#Cv^d>(xzo!@Ou>%a(hmN^ zQdCr=Hk)jxHt{K?Q6)T>{7Bo6zinHw zaSYbGb!`cvq^Mez9u%`7FH0yOi6dY~DaKTd!3S`0t9)I2qpzWghK7+NNC@PW#s~ml zs2zt+zMV9!QO)2NQZNqs?7Dh5y&V$g$F%i)AZ?Fm=ct-L4r9-Vfggp(a&v=?ut!~U zzEVz3=R{gBmYgABJv4|JBp=4UzgOdfzeZQ`S8J5*#mR9i?CIjic4|bUW&|3B z^G?9_=IEpU09{+*YcvmC4Q<*;DDBa@$jv@UkOPvuqkIrC>!|p)TRfaYQuZX4JA94J z8cLx`IkT1Oihv1SqV8&wg@EWAaQ{qQIZ!wPJ>PM{xz*O z`&GW@Q(aR!m7+ z$?7ZTmM&3$y9KGQQ*Wj_pA-J!`*!>OTFy=NpgANZ!zFZ~ zXsKGKl1B2u8!--l^&L*S4+s1!xYm@by%R@Fz+xpJ%KP{0f%*Nl*Z3oV?L0XG%R@&K z%rVbVDs#JjeFl!oQaQ0H8E)rtbx7iMY@5mH0xTRSYO~Q8Es%;#sl%Yl^M9z5)PuhI z(}ZmIJ3>4))n>8FoscIN%JuChmC*vXIZY8+g*@!newN@UyOJD4zM+bA{vz(n8Nv3XQ(88E%JBi zoi1^g8&+`@X{w)@PcSDwUj4Nv0dT|L=^dj7#Z$QhIRx#imu?hlO2-WgP2rwd2?Gjo z(_9n$jvMIii;9-J16R~lrxSPz38!Jqn`{9Y&*!EnGSO!zrlKhvo*5uyC<9kxPEZH7 zxoEwM6);_wh$E6bwLd!U4#9hZKRr57gW(M7x(NA)HZ!ZyW0YeU_R)%_0=><1P7kAM zlsNM#>ZIxEh&h94nb&vJ-|60 z*z`E)mpX{;@JUfCg-FIp({;71zZyOiRq)WNAGK%zl9il!flx{xH*UXBSa#Q3T5F3r zaw>e6UeB5Mo|4TS@}ic@UGubVi6j#dgXU1&r`%@;-&HtvS|}@Kir}g;gaYHr4mx`u zO;fF;s*5iKDZytN;ZBSzi|+nt(K(28oL>}a)Xo;j$(1?u*vq-{w3oIh-fM8RLKO; zB}!B}$ei5Vy%7HZ;(LzzaJJPRBDYgqrty+53@XBcGM#xS=oOwv~8tFI7^*ydpOHT)lBK|Bk0*~*ZR~o7w zBc^&&4=qpyqVYO&W7HqhL2~V_8OA*!4unaQLhQjm6i1glj7Lvkbu}sZqZv4(rK-^jn75E9+>XR*kecX}pa^7je+`k9 z$52M#=(UT7u6LRFXz8So55&NEN7atnvum^6uCg^{PlZ87e{Tejg73>@VZlG0~?I(=ma~Rowxzil& zPS*J->8YZQos^-<0x*36+faPLotUWRVchio+J|{lDNs_W;q29L!YLpsErp5=3~Cywbb~U!uLB2uTY6kQvvZQu=@dzGM{7o z_tLipa1Hl~AH}Ao@F@TVsw7eu9^KFK_tW-sOH5SVw;N}$8g$`q0J>cx6_wIQYN16g z^3-`xC>huupL~7w*LXYO#g@ckm%LBaMNwAXU9(N@z4D=8wC0R#s?KtFv| zVr^`jm*`&L4h-SjN{50KmR?+Z!}*=_-zQ)`njP^r<-`^{t-RXMHNBAM_hwAU3G$JS z;O&ABT|Har5+TbNI}KQ=fIMMjK)~;Vt0;U#zmew*-DPSt5=KENIf3dn>7>7jv|LK} zsw(RxM1r4?tD>9*aB>R_jDinM`f1jR1zajFI}KW%E>*)1u5{GgC>E5h75IL#p=s1U z#EtNK>2Hj9a=x#MsPFU>kKM*2nkOe6bIdf?LWt}_0rb_HsLUz*!OA_(hZf<)Yf4sY zYMyA~*^c_ndqnZb2~shv(T4uzrbyL_p2Uut@WC8|4guBb zSXMO{>8zH*x;Cg#)bc6rr$Nw+X!j@}jQ~-~aC;mbX#gW@d{nNSdd3f^(oG8iI-h+z z(vbAX-r6x>V16mJe%7^1NF*_{W0l8Z4t;&JKZ0x(Hh7(8sCk*6nI*Z|bjPPam_Js`Y&RIhe0P+HMzym!` zT^D#tZ?*{7>KZGJC(nGbmNMgVyu#<~($Y?QXBt^WWL+!aq(Lrw7t$xjiDkVSG- zL61P>W2*B3p18-RxU6(m)5CPPAzhlas(5NCq*d`0<0{MQgmpV$>+7x-o{{J(tkvL4 zL2-=6%HttP80qiRUoL!D;Md@8E}F{Vv^?eM=3)5aJqP~)9*69E>eEZJnji5L-isAc z#G{xu-F+#OSfI-1Ej5HzpTZT|Y@ zXu6RHH!y7P&DUKs;X_=jE!9*@6q2nHc&u@s4m{wo_6Gy+rOp`PX1v`}%?#>msvvU; zg)9RFBxl=fXQob>z7%m2aP7?|YH|Bch1wd*S5QRpeiu`nv($SK4w+#5orCi5=o7?t zTKJM`(2Ve;ys|zs%Eu>vudaclj}I)$Pdc_&9dp}VtBfra=xOV%vzaXyD8$sVa*>5Q zn3x~pUWe(Wh&XnJDuk+$Lo)f7KZGA#dg(GvMR6+_w(WEPzu2ad;|0c!Jj&duJb4Nn zeNHt|t16&`*Oq`qM=~tbXrPdcagyCLov=O6Z8}L;ZJJpr+IZZoMowG;2nQG)iT2V> z%ZC@{=a%=x_PP{}&x-@2c+u`Kq6A#$1RMd=JL*`m%0p$z7^)ZemX@xTr94`>YH8SJvS#K*G)eLua>)a5yMG;hDj}x{_a+b{^VeS3n#b)?c8K&FB@DaYi6Ri z+66(j+hO^7cbElvw=D9q_AJa!I}8kMt@uZTZ@0>XY6@3aff=ZLsxP=b@$IWgQ_%%0 zM^B!DN35t-swr++7(uXCl02SPZlDq|u+FVp>134*7Mc(dK@U5rSk!}!+j4%u>8peI z5@m)NtE!}{k~PM5NQT(RT#`@R{j|lzTssYK4^`Thc_3EK+-B zd3_;Mhd54#x~XNWuZHH~nM$x83SjO6^dxlOJv(W>`xP~k-7M`VED)h`bFc&3rjouM zaJ6>~__5Dc^E0?P$;R7f@BOsvb*75xYo6U&zAO{O(MY7@Dn<_dbzD_jM5lMyD}%U( z-*_x(=U3%yGUIXS`TFSJ6;DlVwA5Tznd62gk%F#H!zXU~N#O1bgN7uSQO_)bLN|8o zGwI)RzMUCNl;$Z^IymKJZNUeqBhycgPMTqzU7=Uu-x<;0<&>(tZxI32x)5`M57_KL z>EBK~Q&O?n>T4*WEi7;|2-hc_lxOwQ#hZogc6zxax6`a5LzCtw9r3y8rbyKIc*(}L zHqvQ=X*Xy`_+`cw7lx2k(|B@5LC6FK1fQvZ+rlMhfWkA4xv{tO z(3ovBl=Uq&JZTY;xt&!&41IK66U*OQ8*0-us?$05!mHm9OD$A)c(;YrBbCEs{v~07 z(_#-@`|F``A)fDHsHK8$0(oI%j!-`X5wX=%1VUbJKpVNy2;wF_U^dXkr5i&@r?FFm z7UNAq)b{|(Bz{mC@<;2_S*A%j75u~l>UElng$>I0N6CK&?NHtL)`o@G#1qP@k+v|$ zeEuQ^-G9EjSH?~Vws6%oD=kD*$l37_9I9n=xftI&V_!E=R8&!fs-luu-WfU7)ZnWQ z74}E%JXlx z$xsxr7yu7aa5c9I-J0W0WWiD&m4|O#TB)Q;s2VAdI<~|Sk*(~um?%M5BM7Crjys)a zb`%#;pmh+)Dy71lbD!s*>!uY$fwxV0MNYEb0x(}TF`uTim4N}NX{RowP>>I(+fKH{ zCXIS*J8OHTrV46xl0JTO_<=iXdrsf(H>3)F%&&+L?3LrcWXB}218 z%*D=jWhC;CZrbTCr_4GHMu@!NwlmXD#=&KpXLqGleb26uDtJcXILKU~t0JAI6BD^{ z>Z7&~PrkYwRO}Qm+;%$jym2rtzG0gtfNdPoGYbH;gxe{Ef~-Twe$R;=={@JRwiJqZ5*4z9G0c`MrN`Dcdg za^3GzS<&Kxtx{7QQ=B}knaqBi_y+*vaigZeLBrJe;+u)LmQeoyvuFy*T`#ko^1?p5 z>9_tN_%Pb<5b=$fTI#VrraJxjMlXcg#AGgVa50?r#<${I9ok!kJryIz zG$I6<<%UrtPF(>gSZqq1sQ{h98s~fqex$aFn_cN;p2u20>LZMK<8U&vCjS74U=4Lk zXC77Y7Y9;s#}8S)T_|fD!%z-qiWX1=MX}3{BefG|TaV161;zju??L0m5aYYiq8E$AZ znPP%CqKpB^v5m3m?WixbFi=?MdMJW2y2$O5%;b4_i93^n)SjAHg6mRcRc08^eP>Y@ z`6I0G^M|1ddV$kg*T=hWs$3a4ctYeI7O!1(r^*LARUv9wVoIJyVa@5HLW!D`%%dQF zFKu$3F|u)79}y$ETk0989gu;}08zIxk?FDZ>#m(?uAk*XOvU`T-1gMrC2caYT1^3} z?o?E_6`+=)C7rhjSOR{7snZoTAgH7=CN^B-Jw~}_#2yE&x^Zkb+8Wl4aDqfGM(K6Z9gdl;5j{LWXQ05}K}o6o8Kls$ z#++kGVB#n(wGm1c)mX^A03`44j1ql;>!|p zN#$@zIL>fzdT0FKL~XE`6e5x_wz6$c=*=e|u`A*~6WsWJiRr1Kpfl0DVT%L1d9c6| za1Yl#M!G$Q5iO z-Es)&ucVjaPYvEUC*Trq@`vF7Bejx%Yui*>=J1OUmp zgSXd5?X^%;w2uUhS<)j)zQH_10n)c>`2ubY*gsA!_|#F3iyaunL)woHqx)fBYlc0S*-$7 z7-Qo2BQB@0#zxzIqfNAMh}80c26be{t}x0Q*y^b_8YbS#e-CReM$b-eLlp);IOW0X z+;%v|e)_BNKGRuyu$U+u2^GVXB!M6uv;K7Zh6*@UKnS6AWzetU^wm;)Xhzp7Dts!W zmgB$@@MjbRnT&3b6VxF)A#9xEvHE&zg7NEyj6U?x{_Js z{w`J7ec1E^>#wA0I6H#tORV;Kb$4!NDuqe=jUBgH?bdoErnb?;O%66xTz&n|zNDim zG1QUEI6vVfEL@cwLqE(v{{Y2^kcFMeO zJe!l)e!4i32`RjE9#OIO)u8}3FGXflulb=QuOS%Axnc*mrkJVJtYL6)27+BLbe7us zYH8%ewG0+D1r?NLWLy;oBk8~N(Mp&lbOyUXYAw|;^5ncspn8%Hxr}EH z4}EpXz*fK+*DJcfX|A;poOvW=`i$-RYI&2PvHLm)15SLPdTGkNd6YL(jdPv`n1_rH zrn*dno|#X!uYufXhDA~UTq9C^+KQ4PCdfvD{9CWMTDV4{y4tE{jh7^lFr!H62 zc!sj!ZSgBqG>GOh!)|SX&OZ7LsLF;(xY*BJf)!?bC>xS><+GBbWFY-DQ{r3|w;mU* zOH7^(VL-@p*8~zi<3FC1J`_}5si@s<6Fj`KkqbLy^5AED^v-epwWTDbLq;~NeY&dA zLh{bb8X)FoCjbpru~pMtc}+aYA~5o@upp1Nw&NOO#2h`{0ahdmnu#@P7%X4b3t^Q1Xcg zIcy974h9F*{(9LY(@hN&nsz&JjP&-4MPm!KeiQ`}$ zTYO|}LGCs_oixoM6H+uY0P#ANWnqv(7$E2kn}?_@?CU`ngpS!^l27JNhDkQlMuk&M daismMx4|Jfa=Jf;8u literal 0 HcmV?d00001 diff --git a/media/framework.png b/media/framework.png new file mode 100644 index 0000000000000000000000000000000000000000..e157dda6d65320dd1b10ae6e35b0c85537dbb44e GIT binary patch literal 58594 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

oHGZ6>iJeRH8|2!=IYW!Q01%mJr*#5A{ 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 pw*tSYh0oAKlLNT=e?8zW2UjCWQIii> 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 literal 0 HcmV?d00001 diff --git a/media/uploadfs.png b/media/uploadfs.png new file mode 100644 index 0000000000000000000000000000000000000000..5b5ee688d8f4102d58cc8a61916845adfb5e695b GIT binary patch literal 8644 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 z z>ap&E-#bCKVU$GAiF6U~B;mBCn9QFWk(?*!)$J}v%`x2`ga~q_qPv|w*spUjg?z!A z_RUF{B3Y=3bz}hBi7y){sSO6B&vyi=2V_FE}Su6RqWN?k{agghpyt*c+1mAc~d%kcgsMFoC#L0;eK2uN@7lr|J@ zh@823qCi2sLnrH+X=moy>lF^MT&KT&x#G+IZ1g<8dx=_ML_rwQKL?H1cmYxM!9mOP3@kOJASW zgj8hYH+22o-?(wIh{LWBi>V5j91?U3QKI7>d7*sNg%69MFP#~xF2MYQCBv-$ewAm^ z=n!M_0mW(x>Ja)O`P_*W?;=hyK{+SqpPSbyIQ>nAW!@{-bph?~?I#?8W>9b)*@3&# z5Q37lLHXdrFCCUgwJz^_!0`R5hS^Q6*Ijbr8j}r+wPU>}b{}?oJc`;m`)>KTnn>>S z?}BdrDs*;>{wv%&Lmb~JFyMVbHv+^T>^cJ}cZgDIMSsgjbjzHOI{Vp@RduR*%&=UC zmBf+w>y7=9e@ct%^sl0IWBaF~&d2;)kN*^V^%0T+=1^XY43v0|Lj-@-q?<12*HPh1 z2!P(!s7H%-+oBcmy14}QA@|`}!?A}Vkj^Z>)$O?qshXtd1s(drn}YPif4fBt*$cYL zzkK*-*hY_hSjmeAmm88!yzCYazB;VNS_aZr`9!ZAKz|uRT7{9R(f9vgS4!2mH{o{nrnaI7rrGDk0&Yl*BGYSqm8h=D@E>*qRO1~z0 zHc8&>mwNQEX$U)T^>>~VIhty7<==z<5u_nSOz6ruc5fY6|Eq?j`yL+yEhn$??PIG} zpL-TAxB+s zkizyWE@<)Yx%bVJK}JwmIyBu+DGY0=YDQX9^X znbn!cp_i3+W22|U9e?X?rQIOPh3(_NA~jLMiQ!|~`{rS@2D_JoqcmF&x(35a&;CP zd%P*{m>m^K(tMxSF@V1`6gGjEvj6Iu#9B2&-J}cyRY4u|Hb%@N`v4I4Iy^Do_ErC7 zcpIa^Ku^#~rEPPqxkd6(9i!J1)+&o>EXhzCU)vd7)AFbgW?pGBDL_0*@4;HTc7+vu zr%QPq^y!1JfNk8@*3zcNRU-PQO9lxmX!q=J0a8F9UoFsbs%w+KDV3g)ZS05ou@qJNU^lQ?Cj;)E}I-#|B>!(sYzO3!`d^uoUxg~ThP=<>y72zPZ?(W z9gJP)DRIu<=>!)w0yE(CY^qYq}@t!Y&J<|ef!8Sak; z6l@J=l?%9SUh%q>0p2i|1+UOJFJ<>thk z>hSI@8^}c;9v4NwsMf87trSJN_izRjdEE_ouRZ zWA51?wYQODAi;rc^Qqg?d5Pz0-fkzGi@8Y~KITJpyjp46bMgBT>SItNhw+KJ&ggj~ z;&f4kruOQO|(>eAOoGV8_C1U0-BR zY69iKPKz*Gu91gneCX`(EL~v5kVi z#0HvuA41n~y}2DZlqr|!n|Qx*jaeJ(3t@55Ocn_%OANezS}aK%s4W_+;MM4!08Ml4 zG^K{Hec#bPkm&73<)b-c_5lmL5x zi&)fK#n&VFod^gsIF|Zz=PY8W(}rBBDZor0pa8T7R0V;!XK=|#Q4$CfuNB(y#DvY= z2vbb&v1Tr^GDM*CpL&!zq#5X|6&YE9jWYn#BiL#Z!!ru?UImy@sl?v&#VO`se2{; zWoeq%CHH|2w~!#8^8FIBx$hvm8YNzu9RaP-OhDD>N{xs3iL}S7{g`V~@31dF(}3`J z)gTiFJLt*!C>o)+VIy@wS(T95+f1EIcgh5mAB`dV6moj_64c#RUAq&;r<+75^F1+Y z8|8?u;Jf6b00ZFtx; zStkC>MqZW1SCterJl~o&_wfH$idag=sFfnqC8haoi=(a7L_t8T~()dZI z$4Nw-zLHoeW!|O4%bz0zhTIqJWz=-?MbD~cpg4Zsb7j1gpc&{3IvDejqJK;#DNq`tW7i2v-*wLXbly}X(1!QNG2kst7gNe&d9K54?TtTH zX90Td7FFQ`ZL&P#Fsl!>_E*p=(PNcrcuGVgS&sh8_pB`w~r4y=jz?=Y} z&O{Ky{`hsnu#?E0l7_)uC5^6{8)$ZGMeq|NSYZlE!Tqi)Lp;Nf=Y_(eY-(QF`;+4C zKHLtPhEpXnakJMVskc@tVNuTTuV+rol}!D#7)E8Z&nYV4&SEeRPyfYlQCZXeyCllo z7rF*l&!G>rF5sIvY`~FYweE?vtxCTe0aDo5K#zYLcX~ioB2prwbp>xzdmRp*s6h5` zk5wSh)wnj|1j0Y12P-HLnpf>&I+`#Ljz1}IW;@~}JzUk*J(V$0@02%O!vu1ZK%kaXu$ zvdm2E?bY=U;xg&&{XmUw#`JJ@<*7d;N%-70QcEWjVtj9cFqr%qjnuVcj=gq&F2F0O zoruKN92*vn7CyIt`w=5xfCPA0VWbOfnp0kR9qq~(Up;6gX%evk7s|b*SWS{$gsDjM z)s1w=Dki{j{UFO1wLS!Gp%?atj}>}P3SCd z6Cjd_b1mkQ;cr=(v)w*C2xj<({dk5RuN(8KcKLXbf``UYM{7N88la3V(smYm(c7q{ zQICQr=lQl0n0L`>LC9?wrYoox!-5kaZ+3FEPlMkClE~~C!YoWq{2xSVWwx-nJ8j#u zDZTDCmrX{O3^P}vDC@nF%kzpVI+_fOcLC)ZQ`g~fYLx71g%h$avi3L-rc5;-s0p-# zXXD?5QgMxCK~#9qpOxY2*FQ1X{$t;=-HLgAjX1h8o0rZn}z`OK|)3Fi{gPQ zQYFc%;~kz=n!r0LX{%6_WcNHec)lvJn$z$OG?bF_)p(Cut|C4;@Vz6|^NWsViYgPi zRIdmtU>0&mKT3X*HE4)cu>INYvZCpZ^U-&&(6%TL|B`IV0fr-UArGaIx$l#hMO0?v2 z^bW3@SsEi-PB4T$?*#`+P^qQ7?ey$>A#{MGlXnBj6|Yhu0lwbjm>oqte)Rlc2D5q3 zlM5Db1F!=nl!cvc-gGqRc@O&1dAVr%qYD@tZSfFWKYx@CQ8tt;a^+%bN{dQv*Tr{( zv5G6WU75qyf!ay1!6*m{3EmMD!wzArXdYNXI1iWJCya@`5Ra1`<*JCsTp?%hfi8ID#9(Khfz653ELW&z;SJNg30uQX ztPLMj(n%;Ga`&g5-rynhlM~{SR9EG6j$D6Inki*x5(gJwKDVLp$}9n`pKxSc0ik(iJNAm47uom`DHVetsDnn4|xj&g#DplHdg2 zk$UT*M2{uz2Knt@d(?Yh1|xNRJ|lLJo)MhE@E|K~CiFQ*--&wj=e#&;i9UIrqN){Y zBIs^eeH{|@&8lU*|4L%rX<+bl84A~WMo4OOM-)ImGd4P}Ns|^hGc!Y3DQMRKrG`f? zd%J(E+hO&`rs_Zel2}Veiq;oP?S3D;pc&;g>FMe92n|Gz>icQ@hc|11!fx3Ww6}WJE(<-6oFZC~#pUgz16$T~AOuK-2QTb@&B9lDdOTpjr=7U_vnqIy4=!@0F<{`!g zUbfgOVSJRnZy?tRm72#6!b|s%E}ilSnC+uVfAro~R^@{o(QWaId^Gy=p}cNCEIZhf zSR4AqkT~tPGdpL{0wy&zflS)sQQ^#dM@7!xgnLtFB_p+7qxxU+^qR84M$6NRQcmxZ zbqb2zePSu~>@o9C6k^1&w<&t5kbPcgK6=T!(!BB$u_C|%dtZ1cHSJC6!&tut=T4aMW~d9Z_dh{v>+4BWdxm>?lnH)*G7&@Z5?oN^78 zX0=hP?d^EYc#6)4bo9u-LH2w?7*X|?WR9(Mg6ou9NbKyFbC1VEj5m2wwLElhWg4uH zRPBdEmGTs(s6`iYi^!nqKKkbM$}vAFR(bVB?C#||Y&Du)1Oi_BVUe~U9V?kTEG=Ij z0gzDV}L22Q0vLpledZgX{wTB^RdcD{!!#T_jFb z3nfzVDwNw?>Oi+d8Iz|67leT#EO4RK*hIaK^hb;CwW&bbtb|k6~>ev3`ph&fCH591X_Bxr24%-;C$>uOIM&~~m zg9p-7TA3hY1uDGDMJSKP(@@&U5{DM$`5eVb+P++tCcD;Xy?aFtlVP@(@F_4)o>x==R6S%sR-aD_1@uE30USht}1sX-GBl{G{sOC2;aMwHOQ zd*4)C)t*GsMOtVmMgg<6xh7y{5SVfCs4>i+1Hc0`+itq_9t1ehO}}*gYL)Wc#-+Dk zf*-?$Lxq^4%awGwzxMdPLs34T0T$cfvK_ca9hUsUdK|-#IX&$8n~0U#@uF?dwU`^F z%zs)qC@EqP0ISs0QNF@Q?sro%y7S_jQmPdIWsQQ^01G&kQ!I+U!H+lnc5Nbfr_KGs zcdvf)k#OWkSEf}^tb*>o*B2)?vcm*XKrs*F+|et$7!?#m7BxcJCmu}a=8WxP3orKD zm%Ay0xWB$?==<3DG$q!D9KdNSFysE#X7r9q(Ne}r9jM}@c!IvMymkIuCQpc*GUFvj4y0I%s^`V6#&L@vyX>U4Pnw-6)Z4F1l)3{zQ*$})-?Zga#x3K7RKIErhHPT=6q^TTF{kuqtu*TO;l$nA)<5w@H%_#K zty$c~G8?>zgFW;%iPh@O!~vW6U<>X2BIR=bxY7oA-w7PWGlf@Qrb}e1Vhs%Wca!O( z)C%dYukjw+8Y@2hU$dJ3U!?kI0`eu}C@iYs$8aASn9N;^|AFlt_}O$c+Xg&#apSYh zp&&>hU|VCJEsBU;>^m#_i;!?D9L8Z|mWy!8n5HBW@MDa*MMPun+ND>8_#z46^DkpH z6Ony8fsYR&Be#~H_cX`xW3u}COhwSI1S}KfW(tPi7Fj5y z5Sj=}?HgKNw26j*sjKsb5|UD91lVVudy= zvAC-Y>Welc=hkQyT51>n18lQjl9E`8@Zr-4PrlareNEs}8RRm`GWaSzze0%ApI;MN z=lLvG#28@=f!?<=u`dWhSTV)8r_UMwIN%zJ(~_{T84pVmqpHDZ#IOu&8v?7xDKEM5 zeT=zB_POYhUMK;qYx!nyMW}u6eXptgR96p68yGnY@5Sm6S-UrZ^`mzXO~?m&sSUn9 zM1tZweES}g-Ewe5{1ZjwWgVo8D}wr%L(;xJ)cOjX`lAx@co_=S(5|YxXU^>|kS+4v ztCBA?qCX~bDHqXQaR*W4T(#Y_rvbU>Kj5RdI^>XDgtrX8JMY)VI}JGz(iR0CSu;3> z5(Z1{?Cdh{x%k~;P%6w%b(E6g#1xs3SPWkza{bU8^^CoC)lXp(*Y&+ArV%V<9)jCV zAC!tp^Kt&zwp{bKaODlIWuoi!n+rP^Jy0kDgR}^_B8B`i2q{@XD&!zqhRcdoR2DQd z4Yo!XT&R&eqYQEboDK%MQGxpCOlt4cdl)udXZORrL-aZqQ=>-u-AY%Qc3o=3 zAJmcNu4M<9jGoF4AJJ|6hSU8lDdM3N0xE9W!d~LWZ8np^HSTS#@0x8l1CI0$N@olrj?bYaQQlbH#^xbGW3lIh6VfWMN<8~bb7#e&)>5Vjd%ygS zUpm!6Y2y3g*ZDPX^+)fsdS({3QX}|Q)BqIbfVZ7;z(sfsRMyxQold~(jF3>cw|EIQ z*8{}P;1MLY>FC}lu9aEZynoQLt533Ws_4Irt|%{B{yr~eO%>WMMbJ;-I|rB|k96nk zB6ks=GQq;wH3lEo+Wdh#2letwN z7!#LN-TXfA2fKyeSPx(1)GLv87r)&o)QOB?o3 zwU+W&IyJiE(5wU7SD+3RctpB75YRi zx*u8?W7Es$_@Go6dFvQ>xPmGhY@2R-KB3WHZv-cL&ZhFsKtet2#FE2JAC|Op+-9n| zO96K^+eV5DY+R(S=g1sthTnWYM14d5l0Hz+*pImxBcHJGI6z;sFxGj>Y-D5jOsT$d zgu}LOBJQ09kCGUjYWXLf>=3a_?`d=(`xr=E_zM`>*(uz5zYWFo3U)s?d(+&y;9GW^0Yf;t~5p ztWL`c;Y#zO9u(FE>*4#<=EwZ@{IPQP(35e@0M{SY3T) z*RRaCks=3?U;=c?|Fent?{ndjBmCvqo`EVjoCe;}=6.0.0,<7.0.0 + ESP Async WebServer@>=1.2.0,<2.0.0 + AsyncMqttClient@>=0.8.2,<1.0.0 + bertmelis/DHT@1.0.1 + +[env:esp12e] +platform = espressif8266 +board = esp12e +board_build.f_cpu = 160000000L +board_build.filesystem = littlefs + +[env:node32s] +; Comment out min_spiffs.csv setting if disabling PROGMEM_WWW with ESP32 +board_build.partitions = min_spiffs.csv +platform = espressif32 +board = node32s diff --git a/scripts/build_interface.py b/scripts/build_interface.py new file mode 100644 index 0000000..84b7c1d --- /dev/null +++ b/scripts/build_interface.py @@ -0,0 +1,34 @@ +from pathlib import Path +from shutil import copytree +from shutil import rmtree +from subprocess import check_output, Popen, PIPE, STDOUT, CalledProcessError +from os import chdir + +Import("env") + +def flagExists(flag): + buildFlags = env.ParseFlags(env["BUILD_FLAGS"]) + for define in buildFlags.get("CPPDEFINES"): + if (define == flag or (isinstance(define, list) and define[0] == flag)): + return True + +def buildWeb(): + chdir("interface") + print("Building interface with npm") + try: + env.Execute("npm install") + env.Execute("npm run build") + buildPath = Path("build") + wwwPath = Path("../data/www") + if wwwPath.exists() and wwwPath.is_dir(): + rmtree(wwwPath) + if not flagExists("PROGMEM_WWW"): + print("Copying interface to data directory") + copytree(buildPath, wwwPath) + finally: + chdir("..") + +if (len(BUILD_TARGETS) == 0 or "upload" in BUILD_TARGETS): + buildWeb() +else: + print("Skipping build interface step for target(s): " + ", ".join(BUILD_TARGETS)) diff --git a/src/GeneralInfoService.cpp b/src/GeneralInfoService.cpp new file mode 100644 index 0000000..431ac61 --- /dev/null +++ b/src/GeneralInfoService.cpp @@ -0,0 +1,48 @@ +// +// Created by lukas on 06.12.20. +// + +#include "GeneralInfoService.h" +#include "Pins.h" + +GeneralInfoService::GeneralInfoService(AsyncWebServer *server, float *lasthum, float *lasttemp) : + hum(lasthum), + temp(lasttemp), + lastPumpTime(0), + lastWaterOutage(0), + lastPumpDuration(0) { + server->on(GENERALINFO_SERVICE_PATH, HTTP_GET, std::bind(&GeneralInfoService::reply, this, std::placeholders::_1)); +} + +void GeneralInfoService::reply(AsyncWebServerRequest *request) { + AsyncJsonResponse *response = new AsyncJsonResponse(false, MAX_FEATURES_SIZE); + JsonObject root = response->getRoot(); + + root["temp"] = *temp; + root["hum"] = *hum; + + root["lastpumptime"] = lastPumpTime != 0 ? (millis() - lastPumpTime) / 1000 : 0; + root["lastWaterOutage"] = lastWaterOutage != 0 ? (millis() - lastWaterOutage) / 1000 : 0; + root["lastPumpDuration"] = lastPumpDuration != 0 ? lastPumpDuration / 1000 : 0; + root["runtime"] = millis() / 1000; + + root["watersensor"] = digitalRead(WasserSensorPin) ? true : false; + root["pressuresensor"] = digitalRead(DruckSensorPin) ? true : false; + + root["version"] = VERSION; + + response->setLength(); + request->send(response); +} + +void GeneralInfoService::setlastPumpTime(unsigned long lastPumpTime) { + this->lastPumpTime = lastPumpTime; +} + +void GeneralInfoService::setlastWaterOutage(unsigned long lastWaterOutage) { + this->lastWaterOutage = lastWaterOutage; +} + +void GeneralInfoService::setPumpDuration(unsigned long lastPumpDuration) { + this->lastPumpDuration = lastPumpDuration; +} diff --git a/src/WifiManager.h b/src/GeneralInfoService.h similarity index 50% rename from src/WifiManager.h rename to src/GeneralInfoService.h index 979d0d0..fee1adf 100644 --- a/src/WifiManager.h +++ b/src/GeneralInfoService.h @@ -1,33 +1,23 @@ // -// Created by lukas on 10.04.20. +// Created by lukas on 06.12.20. // -#pragma once +#ifndef PUMPENSTEUERUNG_GENERALINFOSERVICE_H +#define PUMPENSTEUERUNG_GENERALINFOSERVICE_H -#include #include -#include +#include -class WifiManager { +#include +#include +#include + +#define MAX_FEATURES_SIZE 256 +#define GENERALINFO_SERVICE_PATH "/rest/generalinfo" // set the api backend path + +class GeneralInfoService { public: - WifiManager(); - - /** - * initialize the webserver - */ - void init(float* hum, float* temp); - - /** - * handles new web requests and holds the webserver alive - * call as often as possible - */ - void holdAlive(); - - /** - * reads the max-wait-time out of eeprom - * @return max-wait-time in seconds - */ - int getWaitTime(); + GeneralInfoService(AsyncWebServer* server, float* lasthum, float* lasttemp); /** * sets the last time when the pump was on @@ -48,17 +38,14 @@ public: void setPumpDuration(unsigned long lastPumpDuration); private: + void reply(AsyncWebServerRequest* request); - ESP8266WebServer server; - - void handleRoot(); - - void handleNotFound(); - - void handleGet(); + float * hum; + float * temp; unsigned long lastPumpTime, lastWaterOutage, lastPumpDuration; - float* hum; - float* temp; }; + + +#endif //PUMPENSTEUERUNG_GENERALINFOSERVICE_H diff --git a/src/Heating.cpp b/src/Heating.cpp index 723db27..06ea111 100644 --- a/src/Heating.cpp +++ b/src/Heating.cpp @@ -5,7 +5,8 @@ #include "Heating.h" #include "Pins.h" -void Heating::init(unsigned mode) { + +void Heating::init(unsigned mode, const SettingState* settings) { switch (mode) { case TIME: { const unsigned percentOn = 20; @@ -42,15 +43,15 @@ void Heating::init(unsigned mode) { sensor.setPin(TempSensorPin); - sensor.onData([this](float hum, float temp) { - schedule_function([hum, temp, this]() { + sensor.onData([this, settings](float hum, float temp) { + schedule_function([hum, temp, settings, this]() { Serial.printf("Temp: %gdegC\n", temp); Serial.printf("Humid: %g%%\n", hum); this->lasttemp = temp; this->lasthum = hum; - if (hum > 70.0) { + if (hum > (float)settings->heatUp) { // turn off active turnoff timers mLuefterTicker.detach(); Serial.println("heating should run now!"); @@ -58,14 +59,14 @@ void Heating::init(unsigned mode) { digitalWrite(LuefterPin, HIGH); digitalWrite(HeizungPin, HIGH); mHeatingStatus = true; - } else if (hum < 65.0) { + } else if (hum < (float)settings->heatLow) { // if humidity too low turn off heating and fan after 60secs digitalWrite(HeizungPin, LOW); Serial.println("heating should NOT run now!"); // if heating status in on set ticker to turn of fan in 60sec if (mHeatingStatus) { - mLuefterTicker.once(60, []() { + mLuefterTicker.once((float)settings->fanRuntime, []() { // turn off fan digitalWrite(LuefterPin, LOW); schedule_function([]() { diff --git a/src/Heating.h b/src/Heating.h index 64985d8..428b440 100644 --- a/src/Heating.h +++ b/src/Heating.h @@ -7,12 +7,13 @@ #include #include #include "Pins.h" +#include "SettingsService.h" class Heating { public: Heating(); - void init(unsigned mode); + void init(unsigned mode, const SettingState* settings); float* getLastHum(); float* getLastTemp(); diff --git a/src/Pins.h b/src/Pins.h index 9dd3fe8..9a1355b 100644 --- a/src/Pins.h +++ b/src/Pins.h @@ -15,4 +15,7 @@ #define HeizungPin D1 #define TempSensorPin D4 +// version info +#define VERSION "v1.2.0" + #endif //PUMPENSTEUERUNG_PINS_H diff --git a/src/SettingsService.cpp b/src/SettingsService.cpp new file mode 100644 index 0000000..0a646a3 --- /dev/null +++ b/src/SettingsService.cpp @@ -0,0 +1,70 @@ +// +// Created by lukas on 06.12.20. +// + +#include "SettingsService.h" +#include + +SettingsService::SettingsService(AsyncWebServer *server, SecurityManager *securityManager) : + _httpEndpoint(SettingState::read, + SettingState::update, + this, + server, + SETTINGS_ENDPOINT_PATH, + securityManager, + AuthenticationPredicates::IS_AUTHENTICATED) { + addUpdateHandler([&](const String &originId) { onConfigUpdated(); }, false); +} + +void SettingsService::onConfigUpdated() { + Serial.println("switching led!"); + + File settingsFile = ESPFS.open("settings.json", "w+"); + + if (settingsFile) { + Serial.println("writing config file!"); + StaticJsonDocument<256> doc; + + doc["waterOutageWaitDuration"] = _state.waterOutageWaitDuration; + doc["maxpumpduration"] = _state.maxpumpduration; + doc["heatUp"] = _state.heatUp; + doc["heatLow"] = _state.heatLow; + doc["fanRuntime"] = _state.fanRuntime; + + serializeJson(doc, settingsFile); + + settingsFile.close(); + } +} + +void SettingsService::begin() { + File settingsFile = ESPFS.open("settings.json", "r"); + + if (settingsFile) { + StaticJsonDocument<512> doc; + + // Deserialize the JSON document + DeserializationError error = deserializeJson(doc, settingsFile); + if (error) { + Serial.println(F("Failed to read file, using default configuration")); + onConfigUpdated(); + return; + } + + + // Copy values from the JsonDocument to the Config + _state.waterOutageWaitDuration = doc["waterOutageWaitDuration"] | 3600; + _state.maxpumpduration = doc["maxpumpduration"] | 300; + _state.heatUp = doc["heatUp"] | 70; + _state.heatLow = doc["heatLow"] | 65; + _state.fanRuntime = doc["fanRuntime"] | 60; + + Serial.println("read config file!"); + + settingsFile.close(); + } +} + +const SettingState* SettingsService::getSettings() { + return &_state; +} diff --git a/src/SettingsService.h b/src/SettingsService.h new file mode 100644 index 0000000..a467610 --- /dev/null +++ b/src/SettingsService.h @@ -0,0 +1,111 @@ +// +// Created by lukas on 06.12.20. +// + +#ifndef PUMPENSTEUERUNG_SETTINGSSERVICE_H +#define PUMPENSTEUERUNG_SETTINGSSERVICE_H + +#include + +#define SETTINGS_ENDPOINT_PATH "/rest/settings" + +class SettingState { +public: + int maxpumpduration; + int waterOutageWaitDuration; + int heatUp; + int heatLow; + int fanRuntime; + + SettingState() : maxpumpduration(600), waterOutageWaitDuration(3600), heatUp(65), heatLow(60), fanRuntime(60) {} + + static void read(SettingState &settings, JsonObject &root) { + // read currently defined values + Serial.println("read called"); + root["maxpumpduration"] = settings.maxpumpduration; + root["waterOutageWaitDuration"] = settings.waterOutageWaitDuration; + root["heatUp"] = settings.heatUp; + root["heatLow"] = settings.heatLow; + root["fanRuntime"] = settings.fanRuntime; + } + + static StateUpdateResult update(JsonObject &root, SettingState &settings) { + // store new values defined in ui + Serial.println("update called"); + + int newMaxPump = root["maxpumpduration"]; + int newWaterOutDur = root["waterOutageWaitDuration"]; + int newHeatUp = root["heatUp"]; + int newHeatLow = root["heatLow"]; + int newfanRuntime = root["fanRuntime"]; + + bool change = false; + + if (newMaxPump != settings.maxpumpduration) { + settings.maxpumpduration = newMaxPump; + change = true; + } + + if (newWaterOutDur != settings.waterOutageWaitDuration) { + settings.waterOutageWaitDuration = newWaterOutDur; + change = true; + } + + if (newHeatUp != settings.heatUp) { + settings.heatUp = newHeatUp; + change = true; + } + + if (newHeatLow != settings.heatLow) { + settings.heatLow = newHeatLow; + change = true; + } + + if (newfanRuntime != settings.fanRuntime) { + settings.fanRuntime = newfanRuntime; + change = true; + } + + return change ? StateUpdateResult::CHANGED : StateUpdateResult::UNCHANGED; + } + + static void haRead(SettingState &settings, JsonObject &root) { + Serial.println("haRead called"); +// root["state"] = settings.ledOn ? "ON" : "OFF"; + } + + static StateUpdateResult haUpdate(JsonObject &root, SettingState &lightState) { + Serial.println("haupdate called"); + String state = root["state"]; +// // parse new led state +// boolean newState = false; +// if (state.equals("ON")) { +// newState = true; +// } else if (!state.equals("OFF")) { +// return StateUpdateResult::ERROR; +// } +// // change the new state, if required +// if (lightState.ledOn != newState) { +// lightState.ledOn = newState; +// return StateUpdateResult::CHANGED; +// } + return StateUpdateResult::UNCHANGED; + } +}; + +class SettingsService : public StatefulService { +public: + SettingsService(AsyncWebServer *server, SecurityManager *securityManager); + + void begin(); + + const SettingState* getSettings(); + +private: + HttpEndpoint _httpEndpoint; + + void onConfigUpdated(); +}; + + +#endif //PUMPENSTEUERUNG_SETTINGSSERVICE_H diff --git a/src/WifiManager.cpp b/src/WifiManager.cpp deleted file mode 100644 index 4fa4d97..0000000 --- a/src/WifiManager.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// -// Created by lukas on 10.04.20. -// - -#include -#include "WifiManager.h" -#include "Pins.h" - -void WifiManager::init(float* hum, float* temp) { - this->hum = hum; - this->temp = temp; - - Serial.print("Setting up Access Point"); - // start softap - const bool result = WiFi.softAP("PumpenSteuerung-Heiligenbrunner", "1qayxsw2"); - if (result == true) { - Serial.println("Wifi Ready"); - Serial.println(WiFi.softAPIP()); - - - server.on("/", HTTP_GET, [this]() { - handleRoot(); - }); - - server.on("/get", [this]() { - handleGet(); - }); - server.onNotFound([this]() { - handleNotFound(); - }); - - // server available at 192.168.4.1 - server.begin(); - } else { - Serial.println("Wifi Setup failed!"); - } -} - -WifiManager::WifiManager() : server(80), lastPumpTime(0), lastWaterOutage(0), lastPumpDuration(0) {} - -void WifiManager::handleRoot() { - Serial.println("HomePage called"); - - // read maxpumptime from eeprom - int value = 0; - EEPROM.begin(4096); // init the eeprom - EEPROM.get(0, value); - EEPROM.end(); // stop the eeprom communication - - const bool pumptimeset = this->lastPumpTime != 0; - const bool wateroutageset = this->lastWaterOutage != 0; - const bool pumpdurationset = this->lastPumpDuration != 0; - - const unsigned long pumptime = pumptimeset ? (millis() - this->lastPumpTime) / 1000 : 0; // in sec - const unsigned long wateroutagetime = wateroutageset ? (millis() - this->lastWaterOutage) / 1000 : 0; // in sec - const unsigned long pumpduration = pumpdurationset ? (this->lastPumpDuration) / 1000 : 0; // in sec - - - String index_html = "\n" - " Wastinfoboard-ConfigurationPage\n" - " \n" - " \n" - "

Aktuelle Max-Pumpzeit: " + String(value / 60) + - " Minuten
\n" - "
\n" - " Zeit setzen: \n" - " \n" - "

\n"; - - // append last pump pump cycle - if (pumptimeset) { - index_html += "
Zeit seit letztem einschalten: " + - String(pumptime / (60 * 60)) + "Stunden " + - String((pumptime % 3600) / 60) + "Minuten " + - String((pumptime % 60)) + "Sekunden
"; - } else { - index_html += "
Zeit seit letztem einschalten: -
"; - } - - // append last water outage info - if (wateroutageset) { - index_html += "
Zeit seit letzem Wasserausfall: " + - String(wateroutagetime / (60 * 60 * 24)) + "Tage " + - String((wateroutagetime % 86400) / (60 * 60)) + "Stunden " + - String((wateroutagetime % 3600) / 60) + "Minuten
"; - } else { - index_html += "
Zeit seit letzem Wasserausfall: -
"; - } - - // append pump run duration - if (pumpdurationset) { - index_html += "
Pumpe lief zuletzt: " + - String(pumpduration / 60) + "Minuten " + - String((pumpduration % 60)) + "Sekunden
"; - } else { - index_html += "
Pumpe lief zuletzt: -
"; - } - - // append chip alive time - const unsigned long currtime = millis() / 1000; - index_html += "
Chip laeuft seit: " + - String(currtime / (60 * 60 * 24)) + "Tage " + - String((currtime % 86400) / (60 * 60)) + "Stunden " + - String((currtime % 3600) / 60) + "Minuten " + - String((currtime % 60)) + "Sekunden

"; - - // read live sensor values - index_html += "
Drucksensor: " + String((digitalRead(DruckSensorPin) ? "EIN" : "AUS")) + "
"; - index_html += "
Wassersensor: " + String((digitalRead(WasserSensorPin) ? "EIN" : "AUS")) + "
"; - - index_html += "
Temperatur: " + String(*temp) + "C
"; - index_html += "
Relative Luftfeuchtigkeit: " + String(*hum) + "%
"; - - index_html += ""; - - server.send(200, "text/html", index_html); -} - -void WifiManager::handleNotFound() { - server.send(404, "text/plain", - "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request -} - -void WifiManager::handleGet() { - Serial.println("get called"); - const String s = "\n" - " Wastinfoboard-ConfigurationPage\n" - " \n" - " \n" - " \n" - ""; - - Serial.println(server.arg("time")); - - if (server.arg("time") != "") { - // should be hours - int time = (int) (server.arg("time").toFloat() * 3600.0 + 0.5); - //manager.setSSID(message); - if (time == 0) { - time = 7200; - } - EEPROM.begin(4096); // init the eeprom - EEPROM.put(0, time); - EEPROM.commit(); // write the changes to the eeprom - EEPROM.end(); // stop the eeprom communication - } - - server.send(200, "text/html", s); //Send web page -} - -void WifiManager::holdAlive() { - server.handleClient(); -} - -int WifiManager::getWaitTime() { - int value = 0; - EEPROM.begin(4096); // init the eeprom - EEPROM.get(0, value); - EEPROM.end(); // stop the eeprom communication - return value; -} - -void WifiManager::setlastPumpTime(unsigned long lastPumpTime) { - this->lastPumpTime = lastPumpTime; -} - -void WifiManager::setlastWaterOutage(unsigned long lastWaterOutage) { - this->lastWaterOutage = lastWaterOutage; -} - -void WifiManager::setPumpDuration(unsigned long lastPumpDuration) { - this->lastPumpDuration = lastPumpDuration; -} diff --git a/src/main.cpp b/src/main.cpp index 6d8b120..47f7452 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,47 +1,46 @@ #include #include - -#include "WifiManager.h" +#include #include "Heating.h" - #include "Pins.h" - -#define VERSION "v1.1.1" +#include "GeneralInfoService.h" +#include "SettingsService.h" bool allow; bool error = false; - - -/** time config */ -static const int maxpumpdauer = 600; //sek - // ticker fuer kein-wasser abschaltung Ticker status; //pumpendauer maximum ticker Ticker pumpendauer; -WifiManager mang; +//WifiManager mang; Heating mHeat; -long turnontime = -1; +unsigned long turnontime = 0; + +AsyncWebServer server(80); +ESP8266React esp8266React(&server); + +GeneralInfoService generalinfo = GeneralInfoService(&server, mHeat.getLastHum(), mHeat.getLastTemp()); +SettingsService settingsservice = SettingsService(&server, esp8266React.getSecurityManager()); void pumpeSchalten(bool on) { // digitalWrite(4,on); if (on) { Serial.println("versuche Pumpe EIN zuschalten"); // refresh last pump counter - mang.setlastPumpTime(millis()); + generalinfo.setlastPumpTime(millis()); } else { Serial.println("versuche Pumpe AUS zuschalten"); } if (allow && !error) { if (on) { - pumpendauer.once(maxpumpdauer + 1, []() { + pumpendauer.once((float)settingsservice.getSettings()->maxpumpduration + 1, []() { //erlaube keine einschaltung von mehr als 60 sek - if (millis() - turnontime >= maxpumpdauer * 1000 && turnontime != -1) { + if (millis() - turnontime >= (unsigned)settingsservice.getSettings()->maxpumpduration * 1000 && turnontime != 0) { //error zu lange Serial.println("\n\npumpe lief mehr als 10 Minuten durchgaengig"); pumpeSchalten(false); @@ -49,7 +48,7 @@ void pumpeSchalten(bool on) { } }); } else { - mang.setPumpDuration(millis() - turnontime); + generalinfo.setPumpDuration(millis() - turnontime); } // save pump start time @@ -62,8 +61,6 @@ void pumpeSchalten(bool on) { turnontime = -1; digitalWrite(SchuetzPin, LOW); } - - } ICACHE_RAM_ATTR void DruckschalterInt() { @@ -84,14 +81,16 @@ ICACHE_RAM_ATTR void DruckschalterInt() { } } -int i = mang.getWaitTime(); //todo better +// time counter to wait +int wateroutagewaitduration; + void WasserSensorCheck() { if (digitalRead(WasserSensorPin) == LOW) { Serial.println("Wasser Sensor AUS"); //kein Wasser dh timer auf 10min stellen // refresh wateroutage counter - mang.setlastWaterOutage(millis()); + generalinfo.setlastWaterOutage(millis()); allow = false; Serial.println("Schalte pumpe aus"); @@ -101,14 +100,14 @@ void WasserSensorCheck() { status.detach(); - i = mang.getWaitTime(); + wateroutagewaitduration = settingsservice.getSettings()->waterOutageWaitDuration; status.attach(5, []() { - i -= 5; + wateroutagewaitduration -= 5; Serial.print("noch "); - Serial.print(i); + Serial.print(wateroutagewaitduration); Serial.println(" Sekunden verbleibend"); - if (i <= 0) { + if (wateroutagewaitduration <= 0) { if (digitalRead(WasserSensorPin)) { allow = true; Serial.println("Einschalten der Pumpe wieder erlaubt."); @@ -142,7 +141,7 @@ void setup() { pinMode(DruckSensorPin, INPUT); // initialize pins - digitalWrite(LED_BUILTIN, LOW); + digitalWrite(LED_BUILTIN, HIGH); digitalWrite(SchuetzPin, LOW); //pumpe anfangs sofort abschalten digitalWrite(LuefterPin, LOW); digitalWrite(HeizungPin, LOW); @@ -159,12 +158,11 @@ void setup() { //allow = digitalRead(WasserSensorPin); allow = true; - int value = mang.getWaitTime(); - Serial.print("read value from eeprom: "); - Serial.println(value); WasserSensorCheck(); DruckschalterInt(); + // reset the pumpduration settings maybe set by pressureint function above if pressure pin not high... + generalinfo.setPumpDuration(0); @@ -173,19 +171,20 @@ void setup() { attachInterrupt(digitalPinToInterrupt(WasserSensorPin), WasserSensorInt, CHANGE); - // initialize heating control - Serial.println("initializing heating service"); - mHeat.init(Heating::HUMIDITY); - // initialize wifi Serial.println("Initializing wifi"); - mang.init(mHeat.getLastHum(), mHeat.getLastTemp()); + esp8266React.begin(); + settingsservice.begin(); + server.begin(); + + // initialize heating control + Serial.println("initializing heating service"); + mHeat.init(Heating::HUMIDITY, settingsservice.getSettings()); Serial.println("startup sequence complete!\n"); - digitalWrite(LED_BUILTIN, HIGH); } void loop() { - mang.holdAlive(); + esp8266React.loop(); } \ No newline at end of file