From fc7933b005b5dbe322823bb3194d7dcd492308ba Mon Sep 17 00:00:00 2001 From: Nico Melone Date: Thu, 29 Apr 2021 19:19:19 -0400 Subject: [PATCH] initial commit --- AmazonRootCA1.pem | 20 + Device/.gitattributes | 2 + Device/LICENSE | 674 + Device/README.md | 2 + .../AWSIoTPythonSDK/MQTTLib.py | 1779 ++ .../AWSIoTPythonSDK/__init__.py | 3 + .../AWSIoTPythonSDK/__init__.pyc | Bin 0 -> 267 bytes .../AWSIoTPythonSDK/core/__init__.py | 0 .../core/greengrass/__init__.py | 0 .../core/greengrass/discovery/__init__.py | 0 .../core/greengrass/discovery/models.py | 466 + .../core/greengrass/discovery/providers.py | 426 + .../AWSIoTPythonSDK/core/jobs/__init__.py | 0 .../core/jobs/thingJobManager.py | 156 + .../AWSIoTPythonSDK/core/protocol/__init__.py | 0 .../core/protocol/connection/__init__.py | 0 .../core/protocol/connection/alpn.py | 63 + .../core/protocol/connection/cores.py | 699 + .../core/protocol/internal/__init__.py | 0 .../core/protocol/internal/clients.py | 244 + .../core/protocol/internal/defaults.py | 20 + .../core/protocol/internal/events.py | 29 + .../core/protocol/internal/queues.py | 87 + .../core/protocol/internal/requests.py | 27 + .../core/protocol/internal/workers.py | 296 + .../core/protocol/mqtt_core.py | 373 + .../core/protocol/paho/__init__.py | 0 .../core/protocol/paho/client.py | 2445 ++ .../AWSIoTPythonSDK/core/shadow/__init__.py | 0 .../core/shadow/deviceShadow.py | 430 + .../core/shadow/shadowManager.py | 83 + .../AWSIoTPythonSDK/core/util/__init__.py | 0 .../AWSIoTPythonSDK/core/util/enums.py | 19 + .../AWSIoTPythonSDK/core/util/providers.py | 92 + .../exception/AWSIoTExceptions.py | 153 + .../AWSIoTPythonSDK/exception/__init__.py | 0 .../exception/operationError.py | 19 + .../exception/operationTimeoutException.py | 19 + .../AWSIoTPythonSDK/MQTTLib.py | 1779 ++ .../AWSIoTPythonSDK/__init__.py | 3 + .../AWSIoTPythonSDK/core/__init__.py | 0 .../core/greengrass/__init__.py | 0 .../core/greengrass/discovery/__init__.py | 0 .../core/greengrass/discovery/models.py | 466 + .../core/greengrass/discovery/providers.py | 426 + .../AWSIoTPythonSDK/core/jobs/__init__.py | 0 .../core/jobs/thingJobManager.py | 156 + .../AWSIoTPythonSDK/core/protocol/__init__.py | 0 .../core/protocol/connection/__init__.py | 0 .../core/protocol/connection/alpn.py | 63 + .../core/protocol/connection/cores.py | 699 + .../core/protocol/internal/__init__.py | 0 .../core/protocol/internal/clients.py | 244 + .../core/protocol/internal/defaults.py | 20 + .../core/protocol/internal/events.py | 29 + .../core/protocol/internal/queues.py | 87 + .../core/protocol/internal/requests.py | 27 + .../core/protocol/internal/workers.py | 296 + .../core/protocol/mqtt_core.py | 373 + .../core/protocol/paho/__init__.py | 0 .../core/protocol/paho/client.py | 2445 ++ .../AWSIoTPythonSDK/core/shadow/__init__.py | 0 .../core/shadow/deviceShadow.py | 430 + .../core/shadow/shadowManager.py | 83 + .../AWSIoTPythonSDK/core/util/__init__.py | 0 .../AWSIoTPythonSDK/core/util/enums.py | 19 + .../AWSIoTPythonSDK/core/util/providers.py | 92 + .../exception/AWSIoTExceptions.py | 153 + .../AWSIoTPythonSDK/exception/__init__.py | 0 .../exception/operationError.py | 19 + .../exception/operationTimeoutException.py | 19 + Device/aws-iot-device-sdk-python/setup.cfg | 2 + Device/aws-iot-device-sdk-python/setup.py | 34 + Device/data_points.py | 153 + Device/data_points.pyc | Bin 0 -> 5556 bytes Device/device1Cert.key | 27 + Device/device1Cert.pem | 23 + Device/device1CertAndCACert.pem | 47 + Device/driver.py | 129 + Device/driver.pyc | Bin 0 -> 4144 bytes Device/logs/device1.log | 93 + Device/logs/test.log | 15 + Device/main.py | 127 + Device/minimalmodbus.py | 4028 ++++ Device/minimalmodbus.pyc | Bin 0 -> 102806 bytes Device/pycomm/__init__.py | 1 + Device/pycomm/__init__.pyc | Bin 0 -> 139 bytes Device/pycomm/ab_comm/__init__.py | 2 + Device/pycomm/ab_comm/__init__.pyc | Bin 0 -> 178 bytes Device/pycomm/ab_comm/clx.py | 912 + Device/pycomm/ab_comm/clx.pyc | Bin 0 -> 25189 bytes Device/pycomm/ab_comm/slc.py | 574 + Device/pycomm/cip/__init__.py | 1 + Device/pycomm/cip/__init__.pyc | Bin 0 -> 143 bytes Device/pycomm/cip/cip_base.py | 896 + Device/pycomm/cip/cip_base.pyc | Bin 0 -> 25861 bytes Device/pycomm/cip/cip_const.py | 483 + Device/pycomm/cip/cip_const.pyc | Bin 0 -> 10688 bytes Device/pycomm/common.py | 7 + Device/pycomm/common.pyc | Bin 0 -> 394 bytes Device/root-CA.crt | 20 + Device/rootCA.key | 27 + Device/rootCA.pem | 24 + Device/rootCA.srl | 1 + Device/server.conf | 14 + Device/start.sh | 39 + Device/start.sh.old | 36 + Device/utilities.py | 0 Device/utilities.pyc | Bin 0 -> 1323 bytes Diagrams/Henry Pump IoT Diagrams.drawio | 1 + Event Formats.json | 257 + ...B-ad8c7c21-125e-4177-80a2-fe869216131c.zip | Bin 0 -> 1071 bytes ...t-d3e57d2b-a312-42c9-a50c-730acabd0f17.zip | Bin 0 -> 550 bytes ...t-d8964309-3c8f-49e8-ab4a-bf87b36b4263.zip | Bin 0 -> 468 bytes ...r-f69b226a-412b-4db7-9193-6afdddbb002c.zip | Bin 0 -> 184794 bytes ...a-6e76fe04-8523-46f3-aa65-2c1bd257135d.zip | Bin 0 -> 1130 bytes ...a-35e8720b-7195-449e-aa91-16a0c0597cbd.zip | Bin 0 -> 671 bytes .../Websocket Authorizer/ecdsa/__init__.py | 17 + .../Websocket Authorizer/ecdsa/_version.py | 11 + Lambdas/Websocket Authorizer/ecdsa/curves.py | 46 + Lambdas/Websocket Authorizer/ecdsa/der.py | 231 + Lambdas/Websocket Authorizer/ecdsa/ecdsa.py | 576 + .../ecdsa/ellipticcurve.py | 293 + Lambdas/Websocket Authorizer/ecdsa/keys.py | 307 + .../ecdsa/numbertheory.py | 613 + Lambdas/Websocket Authorizer/ecdsa/rfc6979.py | 103 + Lambdas/Websocket Authorizer/ecdsa/six.py | 394 + .../Websocket Authorizer/ecdsa/test_der.py | 88 + .../ecdsa/test_malformed_sigs.py | 87 + .../ecdsa/test_pyecdsa.py | 832 + Lambdas/Websocket Authorizer/ecdsa/util.py | 267 + Lambdas/Websocket Authorizer/jose/__init__.py | 11 + .../jose/backends/__init__.py | 13 + .../jose/backends/_asn1.py | 82 + .../jose/backends/base.py | 21 + .../jose/backends/cryptography_backend.py | 371 + .../jose/backends/ecdsa_backend.py | 144 + .../jose/backends/pycrypto_backend.py | 212 + .../jose/backends/rsa_backend.py | 263 + .../Websocket Authorizer/jose/constants.py | 39 + .../Websocket Authorizer/jose/exceptions.py | 36 + Lambdas/Websocket Authorizer/jose/jwk.py | 142 + Lambdas/Websocket Authorizer/jose/jws.py | 273 + Lambdas/Websocket Authorizer/jose/jwt.py | 507 + Lambdas/Websocket Authorizer/jose/utils.py | 134 + .../Websocket Authorizer/lambda_function.py | 82 + .../Websocket Authorizer/lambda_function.zip | Bin 0 -> 184410 bytes .../Websocket Authorizer/pyasn1/__init__.py | 7 + .../pyasn1/codec/__init__.py | 1 + .../pyasn1/codec/ber/__init__.py | 1 + .../pyasn1/codec/ber/decoder.py | 1654 ++ .../pyasn1/codec/ber/encoder.py | 890 + .../pyasn1/codec/ber/eoo.py | 28 + .../pyasn1/codec/cer/__init__.py | 1 + .../pyasn1/codec/cer/decoder.py | 114 + .../pyasn1/codec/cer/encoder.py | 313 + .../pyasn1/codec/der/__init__.py | 1 + .../pyasn1/codec/der/decoder.py | 94 + .../pyasn1/codec/der/encoder.py | 107 + .../pyasn1/codec/native/__init__.py | 1 + .../pyasn1/codec/native/decoder.py | 213 + .../pyasn1/codec/native/encoder.py | 256 + .../pyasn1/compat/__init__.py | 1 + .../pyasn1/compat/binary.py | 33 + .../pyasn1/compat/calling.py | 20 + .../pyasn1/compat/dateandtime.py | 22 + .../pyasn1/compat/integer.py | 110 + .../pyasn1/compat/octets.py | 46 + .../pyasn1/compat/string.py | 26 + Lambdas/Websocket Authorizer/pyasn1/debug.py | 157 + Lambdas/Websocket Authorizer/pyasn1/error.py | 75 + .../pyasn1/type/__init__.py | 1 + .../Websocket Authorizer/pyasn1/type/base.py | 707 + .../Websocket Authorizer/pyasn1/type/char.py | 335 + .../pyasn1/type/constraint.py | 702 + .../Websocket Authorizer/pyasn1/type/error.py | 11 + .../pyasn1/type/namedtype.py | 561 + .../pyasn1/type/namedval.py | 192 + .../pyasn1/type/opentype.py | 104 + .../Websocket Authorizer/pyasn1/type/tag.py | 335 + .../pyasn1/type/tagmap.py | 96 + .../Websocket Authorizer/pyasn1/type/univ.py | 3321 +++ .../pyasn1/type/useful.py | 191 + Lambdas/Websocket Authorizer/rsa/__init__.py | 42 + Lambdas/Websocket Authorizer/rsa/_compat.py | 162 + Lambdas/Websocket Authorizer/rsa/asn1.py | 53 + Lambdas/Websocket Authorizer/rsa/cli.py | 288 + Lambdas/Websocket Authorizer/rsa/common.py | 188 + Lambdas/Websocket Authorizer/rsa/core.py | 57 + Lambdas/Websocket Authorizer/rsa/key.py | 791 + .../Websocket Authorizer/rsa/machine_size.py | 74 + Lambdas/Websocket Authorizer/rsa/parallel.py | 101 + Lambdas/Websocket Authorizer/rsa/pem.py | 126 + Lambdas/Websocket Authorizer/rsa/pkcs1.py | 439 + Lambdas/Websocket Authorizer/rsa/pkcs1_v2.py | 103 + Lambdas/Websocket Authorizer/rsa/prime.py | 201 + Lambdas/Websocket Authorizer/rsa/randnum.py | 98 + Lambdas/Websocket Authorizer/rsa/transform.py | 215 + Lambdas/Websocket Authorizer/rsa/util.py | 79 + Lambdas/Websocket Authorizer/six.py | 952 + Lambdas/Websocket Authorizer/six.pyc | Bin 0 -> 29688 bytes ...r-f1faee29-85ed-443a-9247-4c77e82f9af6.zip | Bin 0 -> 793 bytes Test M1/365f390157-certificate.pem.crt | 20 + Test M1/365f390157-private.pem.key | 27 + Test M1/365f390157-public.pem.key | 9 + Website/Back Home Files/home.component.html | 130 + Website/Back Home Files/home.component.scss | 21 + .../Back Home Files/home.component.spec.ts | 25 + Website/Back Home Files/home.component.ts | 174 + Website/Backup Home D3/home.component.html | 20 + Website/Backup Home D3/home.component.scss | 43 + Website/Backup Home D3/home.component.spec.ts | 25 + Website/Backup Home D3/home.component.ts | 222 + Website/HPIoTWebApp/.editorconfig | 13 + Website/HPIoTWebApp/.gitignore | 58 + Website/HPIoTWebApp/.vscode/settings.json | 3 + Website/HPIoTWebApp/README.md | 27 + .../amplify/.config/project-config.json | 17 + ...webapp78e5977f-cloudformation-template.yml | 366 + .../auth/hpiotwebapp78e5977f/parameters.json | 52 + .../amplify/backend/backend-config.json | 21 + .../hosting/S3AndCloudFront/parameters.json | 3 + .../hosting/S3AndCloudFront/template.json | 271 + .../storage/hpiotuserstorage/parameters.json | 34 + .../s3-cloudformation-template.json | 631 + .../amplify/team-provider-info.json | 31 + Website/HPIoTWebApp/angular.json | 139 + Website/HPIoTWebApp/browserslist | 12 + Website/HPIoTWebApp/e2e/protractor.conf.js | 32 + Website/HPIoTWebApp/e2e/src/app.e2e-spec.ts | 23 + Website/HPIoTWebApp/e2e/src/app.po.ts | 11 + Website/HPIoTWebApp/e2e/tsconfig.json | 13 + Website/HPIoTWebApp/karma.conf.js | 32 + Website/HPIoTWebApp/ngsw-config.json | 29 + Website/HPIoTWebApp/package-lock.json | 16280 +++++++++++++ Website/HPIoTWebApp/package.json | 54 + .../HPIoTWebApp/src/app/app-routing.module.ts | 43 + .../HPIoTWebApp/src/app/app.component.html | 99 + .../HPIoTWebApp/src/app/app.component.scss | 106 + .../HPIoTWebApp/src/app/app.component.spec.ts | 35 + Website/HPIoTWebApp/src/app/app.component.ts | 79 + Website/HPIoTWebApp/src/app/app.module.ts | 56 + .../src/app/auth/auth.component.html | 2 + .../src/app/auth/auth.component.scss | 9 + .../src/app/auth/auth.component.spec.ts | 25 + .../src/app/auth/auth.component.ts | 37 + .../src/app/auth/auth.guard.spec.ts | 15 + .../HPIoTWebApp/src/app/auth/auth.guard.ts | 20 + .../src/app/auth/auth.service.spec.ts | 12 + .../HPIoTWebApp/src/app/auth/auth.service.ts | 75 + .../confirm-code/confirm-code.component.html | 12 + .../confirm-code/confirm-code.component.scss | 0 .../confirm-code.component.spec.ts | 25 + .../confirm-code/confirm-code.component.ts | 60 + .../country-code-select.component.html | 10 + .../country-code-select.component.scss | 10 + .../country-code-select.component.spec.ts | 25 + .../country-code-select.component.ts | 21 + .../country-code-select/country-codes.spec.ts | 7 + .../auth/country-code-select/country-codes.ts | 1213 + .../country-code-select/filter.pipe.spec.ts | 8 + .../auth/country-code-select/filter.pipe.ts | 19 + .../auth/profile/avatar/avatar.component.html | 33 + .../auth/profile/avatar/avatar.component.scss | 71 + .../profile/avatar/avatar.component.spec.ts | 25 + .../auth/profile/avatar/avatar.component.ts | 162 + .../app/auth/profile/profile.component.html | 38 + .../app/auth/profile/profile.component.scss | 26 + .../auth/profile/profile.component.spec.ts | 25 + .../src/app/auth/profile/profile.component.ts | 117 + .../app/auth/sign-in/sign-in.component.html | 23 + .../app/auth/sign-in/sign-in.component.scss | 0 .../auth/sign-in/sign-in.component.spec.ts | 25 + .../src/app/auth/sign-in/sign-in.component.ts | 80 + .../app/auth/sign-up/sign-up.component.html | 27 + .../app/auth/sign-up/sign-up.component.scss | 0 .../auth/sign-up/sign-up.component.spec.ts | 25 + .../src/app/auth/sign-up/sign-up.component.ts | 92 + .../src/app/auth/unauth.guard.spec.ts | 15 + .../HPIoTWebApp/src/app/auth/unauth.guard.ts | 27 + .../src/app/configs/configs.component.html | 83 + .../src/app/configs/configs.component.scss | 32 + .../src/app/configs/configs.component.spec.ts | 25 + .../src/app/configs/configs.component.ts | 172 + .../app/dashboard/dashboard.component.html | 4 + .../app/dashboard/dashboard.component.scss | 31 + .../app/dashboard/dashboard.component.spec.ts | 25 + .../src/app/dashboard/dashboard.component.ts | 124 + .../src/app/loader/loader.component.html | 4 + .../src/app/loader/loader.component.scss | 7 + .../src/app/loader/loader.component.spec.ts | 25 + .../src/app/loader/loader.component.ts | 24 + .../src/app/loader/loader.service.spec.ts | 12 + .../src/app/loader/loader.service.ts | 30 + .../src/app/material/material.module.ts | 81 + .../app/services/compressor.service.spec.ts | 12 + .../src/app/services/compressor.service.ts | 41 + .../src/app/services/data.service.spec.ts | 16 + .../src/app/services/data.service.ts | 122 + .../app/services/notification.service.spec.ts | 12 + .../src/app/services/notification.service.ts | 57 + Website/HPIoTWebApp/src/assets/.gitkeep | 0 .../src/assets/icons/icon-128x128.png | Bin 0 -> 2743 bytes .../src/assets/icons/icon-144x144.png | Bin 0 -> 2984 bytes .../src/assets/icons/icon-152x152.png | Bin 0 -> 3111 bytes .../src/assets/icons/icon-192x192.png | Bin 0 -> 3859 bytes .../src/assets/icons/icon-384x384.png | Bin 0 -> 7279 bytes .../src/assets/icons/icon-512x512.png | Bin 0 -> 9498 bytes .../src/assets/icons/icon-72x72.png | Bin 0 -> 1739 bytes .../src/assets/icons/icon-96x96.png | Bin 0 -> 2248 bytes Website/HPIoTWebApp/src/aws-exports.js | 18 + .../src/environments/environment.ts | 20 + Website/HPIoTWebApp/src/favicon.ico | Bin 0 -> 3230 bytes Website/HPIoTWebApp/src/index.html | 19 + Website/HPIoTWebApp/src/main.ts | 21 + Website/HPIoTWebApp/src/manifest.webmanifest | 51 + Website/HPIoTWebApp/src/polyfills.ts | 64 + Website/HPIoTWebApp/src/styles.scss | 4 + Website/HPIoTWebApp/src/test.ts | 20 + Website/HPIoTWebApp/tsconfig.app.json | 18 + Website/HPIoTWebApp/tsconfig.json | 26 + Website/HPIoTWebApp/tsconfig.spec.json | 18 + Website/HPIoTWebApp/tslint.json | 92 + Website/hpiot-react/.gitignore | 24 + Website/hpiot-react/README.md | 68 + .../#current-cloud-backend/amplify-meta.json | 56 + ...treact8c9024fb-cloudformation-template.yml | 369 + .../auth/hpiotreact8c9024fb/parameters.json | 53 + .../backend-config.json | 16 + .../hosting/S3AndCloudFront/parameters.json | 3 + .../hosting/S3AndCloudFront/template.json | 113 + .../amplify/.config/local-aws-info.json | 7 + .../amplify/.config/local-env-info.json | 5 + .../amplify/.config/project-config.json | 17 + .../amplify/backend/amplify-meta.json | 56 + ...treact8c9024fb-cloudformation-template.yml | 369 + .../auth/hpiotreact8c9024fb/parameters.json | 53 + .../nested-cloudformation-stack.yml | 371 + .../amplify/backend/backend-config.json | 16 + .../hosting/S3AndCloudFront/parameters.json | 3 + .../hosting/S3AndCloudFront/template.json | 113 + .../amplify/team-provider-info.json | 20 + Website/hpiot-react/package-lock.json | 19010 ++++++++++++++++ Website/hpiot-react/package.json | 40 + Website/hpiot-react/public/favicon.ico | Bin 0 -> 3230 bytes Website/hpiot-react/public/icon-512x512.png | Bin 0 -> 9498 bytes Website/hpiot-react/public/index.html | 43 + Website/hpiot-react/public/logo192.png | Bin 0 -> 5347 bytes Website/hpiot-react/public/logo512.png | Bin 0 -> 9664 bytes Website/hpiot-react/public/manifest.json | 25 + Website/hpiot-react/public/robots.txt | 3 + Website/hpiot-react/src/App.css | 19 + Website/hpiot-react/src/App.js | 119 + Website/hpiot-react/src/App.test.js | 9 + Website/hpiot-react/src/aws-exports-old.js | 16 + Website/hpiot-react/src/aws-exports.js | 18 + Website/hpiot-react/src/charts/BarChart.js | 37 + Website/hpiot-react/src/charts/LineChart.js | 144 + Website/hpiot-react/src/index.css | 13 + Website/hpiot-react/src/index.js | 12 + Website/hpiot-react/src/logo.svg | 7 + Website/hpiot-react/src/serviceWorker.js | 141 + Website/hpiot-react/src/setupTests.js | 5 + Website/hpiot-react/yarn.lock | 12884 +++++++++++ Website/package.json | 15 + desktop.ini | Bin 0 -> 176 bytes example config.json | 109 + favicon.ico | Bin 0 -> 3230 bytes hen_rgb.png | Bin 0 -> 4952 bytes hen_rgb.xcf | Bin 0 -> 19401 bytes hpicon-1408x1408.png | Bin 0 -> 14920 bytes hpicon-1408x1408.xcf | Bin 0 -> 139936 bytes icon-128x128.png | Bin 0 -> 2743 bytes icon-144x144.png | Bin 0 -> 2984 bytes icon-152x152.png | Bin 0 -> 3111 bytes icon-192x192.png | Bin 0 -> 3859 bytes icon-384x384.png | Bin 0 -> 7279 bytes icon-512x512.png | Bin 0 -> 9498 bytes icon-72x72.png | Bin 0 -> 1739 bytes icon-96x96.png | Bin 0 -> 2248 bytes jitp_template.json | 6 + 381 files changed, 102837 insertions(+) create mode 100644 AmazonRootCA1.pem create mode 100644 Device/.gitattributes create mode 100644 Device/LICENSE create mode 100644 Device/README.md create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/MQTTLib.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/__init__.pyc create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/greengrass/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/greengrass/discovery/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/greengrass/discovery/models.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/greengrass/discovery/providers.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/jobs/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/jobs/thingJobManager.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/alpn.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/cores.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/clients.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/defaults.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/events.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/queues.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/requests.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/workers.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/mqtt_core.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/paho/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/paho/client.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/deviceShadow.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/shadowManager.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/enums.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/providers.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/AWSIoTExceptions.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationError.py create mode 100644 Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationTimeoutException.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/MQTTLib.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/models.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/providers.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/jobs/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/jobs/thingJobManager.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/alpn.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/cores.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/clients.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/defaults.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/events.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/queues.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/requests.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/workers.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/mqtt_core.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/paho/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/paho/client.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/deviceShadow.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/shadowManager.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/enums.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/providers.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/AWSIoTExceptions.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/__init__.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationError.py create mode 100644 Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationTimeoutException.py create mode 100644 Device/aws-iot-device-sdk-python/setup.cfg create mode 100644 Device/aws-iot-device-sdk-python/setup.py create mode 100644 Device/data_points.py create mode 100644 Device/data_points.pyc create mode 100644 Device/device1Cert.key create mode 100644 Device/device1Cert.pem create mode 100644 Device/device1CertAndCACert.pem create mode 100644 Device/driver.py create mode 100644 Device/driver.pyc create mode 100644 Device/logs/device1.log create mode 100644 Device/logs/test.log create mode 100644 Device/main.py create mode 100644 Device/minimalmodbus.py create mode 100644 Device/minimalmodbus.pyc create mode 100644 Device/pycomm/__init__.py create mode 100644 Device/pycomm/__init__.pyc create mode 100644 Device/pycomm/ab_comm/__init__.py create mode 100644 Device/pycomm/ab_comm/__init__.pyc create mode 100644 Device/pycomm/ab_comm/clx.py create mode 100644 Device/pycomm/ab_comm/clx.pyc create mode 100644 Device/pycomm/ab_comm/slc.py create mode 100644 Device/pycomm/cip/__init__.py create mode 100644 Device/pycomm/cip/__init__.pyc create mode 100644 Device/pycomm/cip/cip_base.py create mode 100644 Device/pycomm/cip/cip_base.pyc create mode 100644 Device/pycomm/cip/cip_const.py create mode 100644 Device/pycomm/cip/cip_const.pyc create mode 100644 Device/pycomm/common.py create mode 100644 Device/pycomm/common.pyc create mode 100644 Device/root-CA.crt create mode 100644 Device/rootCA.key create mode 100644 Device/rootCA.pem create mode 100644 Device/rootCA.srl create mode 100644 Device/server.conf create mode 100644 Device/start.sh create mode 100644 Device/start.sh.old create mode 100644 Device/utilities.py create mode 100644 Device/utilities.pyc create mode 100644 Diagrams/Henry Pump IoT Diagrams.drawio create mode 100644 Event Formats.json create mode 100644 Lambdas/HPIoT-Core-To-DDB-ad8c7c21-125e-4177-80a2-fe869216131c.zip create mode 100644 Lambdas/HPIoTConnect-d3e57d2b-a312-42c9-a50c-730acabd0f17.zip create mode 100644 Lambdas/HPIoTDisconnect-d8964309-3c8f-49e8-ab4a-bf87b36b4263.zip create mode 100644 Lambdas/HPIoTWSAuthorizer-f69b226a-412b-4db7-9193-6afdddbb002c.zip create mode 100644 Lambdas/HPIoTgetDashboardData-6e76fe04-8523-46f3-aa65-2c1bd257135d.zip create mode 100644 Lambdas/HPIoTgetData-35e8720b-7195-449e-aa91-16a0c0597cbd.zip create mode 100644 Lambdas/Websocket Authorizer/ecdsa/__init__.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/_version.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/curves.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/der.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/ecdsa.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/ellipticcurve.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/keys.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/numbertheory.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/rfc6979.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/six.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/test_der.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/test_malformed_sigs.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/test_pyecdsa.py create mode 100644 Lambdas/Websocket Authorizer/ecdsa/util.py create mode 100644 Lambdas/Websocket Authorizer/jose/__init__.py create mode 100644 Lambdas/Websocket Authorizer/jose/backends/__init__.py create mode 100644 Lambdas/Websocket Authorizer/jose/backends/_asn1.py create mode 100644 Lambdas/Websocket Authorizer/jose/backends/base.py create mode 100644 Lambdas/Websocket Authorizer/jose/backends/cryptography_backend.py create mode 100644 Lambdas/Websocket Authorizer/jose/backends/ecdsa_backend.py create mode 100644 Lambdas/Websocket Authorizer/jose/backends/pycrypto_backend.py create mode 100644 Lambdas/Websocket Authorizer/jose/backends/rsa_backend.py create mode 100644 Lambdas/Websocket Authorizer/jose/constants.py create mode 100644 Lambdas/Websocket Authorizer/jose/exceptions.py create mode 100644 Lambdas/Websocket Authorizer/jose/jwk.py create mode 100644 Lambdas/Websocket Authorizer/jose/jws.py create mode 100644 Lambdas/Websocket Authorizer/jose/jwt.py create mode 100644 Lambdas/Websocket Authorizer/jose/utils.py create mode 100644 Lambdas/Websocket Authorizer/lambda_function.py create mode 100644 Lambdas/Websocket Authorizer/lambda_function.zip create mode 100644 Lambdas/Websocket Authorizer/pyasn1/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/ber/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/ber/decoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/ber/encoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/ber/eoo.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/cer/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/cer/decoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/cer/encoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/der/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/der/decoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/der/encoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/native/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/native/decoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/codec/native/encoder.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/compat/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/compat/binary.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/compat/calling.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/compat/dateandtime.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/compat/integer.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/compat/octets.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/compat/string.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/debug.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/error.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/__init__.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/base.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/char.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/constraint.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/error.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/namedtype.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/namedval.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/opentype.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/tag.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/tagmap.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/univ.py create mode 100644 Lambdas/Websocket Authorizer/pyasn1/type/useful.py create mode 100644 Lambdas/Websocket Authorizer/rsa/__init__.py create mode 100644 Lambdas/Websocket Authorizer/rsa/_compat.py create mode 100644 Lambdas/Websocket Authorizer/rsa/asn1.py create mode 100644 Lambdas/Websocket Authorizer/rsa/cli.py create mode 100644 Lambdas/Websocket Authorizer/rsa/common.py create mode 100644 Lambdas/Websocket Authorizer/rsa/core.py create mode 100644 Lambdas/Websocket Authorizer/rsa/key.py create mode 100644 Lambdas/Websocket Authorizer/rsa/machine_size.py create mode 100644 Lambdas/Websocket Authorizer/rsa/parallel.py create mode 100644 Lambdas/Websocket Authorizer/rsa/pem.py create mode 100644 Lambdas/Websocket Authorizer/rsa/pkcs1.py create mode 100644 Lambdas/Websocket Authorizer/rsa/pkcs1_v2.py create mode 100644 Lambdas/Websocket Authorizer/rsa/prime.py create mode 100644 Lambdas/Websocket Authorizer/rsa/randnum.py create mode 100644 Lambdas/Websocket Authorizer/rsa/transform.py create mode 100644 Lambdas/Websocket Authorizer/rsa/util.py create mode 100644 Lambdas/Websocket Authorizer/six.py create mode 100644 Lambdas/Websocket Authorizer/six.pyc create mode 100644 Lambdas/testDynamoDBTrigger-f1faee29-85ed-443a-9247-4c77e82f9af6.zip create mode 100644 Test M1/365f390157-certificate.pem.crt create mode 100644 Test M1/365f390157-private.pem.key create mode 100644 Test M1/365f390157-public.pem.key create mode 100644 Website/Back Home Files/home.component.html create mode 100644 Website/Back Home Files/home.component.scss create mode 100644 Website/Back Home Files/home.component.spec.ts create mode 100644 Website/Back Home Files/home.component.ts create mode 100644 Website/Backup Home D3/home.component.html create mode 100644 Website/Backup Home D3/home.component.scss create mode 100644 Website/Backup Home D3/home.component.spec.ts create mode 100644 Website/Backup Home D3/home.component.ts create mode 100644 Website/HPIoTWebApp/.editorconfig create mode 100644 Website/HPIoTWebApp/.gitignore create mode 100644 Website/HPIoTWebApp/.vscode/settings.json create mode 100644 Website/HPIoTWebApp/README.md create mode 100644 Website/HPIoTWebApp/amplify/.config/project-config.json create mode 100644 Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/hpiotwebapp78e5977f-cloudformation-template.yml create mode 100644 Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/parameters.json create mode 100644 Website/HPIoTWebApp/amplify/backend/backend-config.json create mode 100644 Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/parameters.json create mode 100644 Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/template.json create mode 100644 Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/parameters.json create mode 100644 Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/s3-cloudformation-template.json create mode 100644 Website/HPIoTWebApp/amplify/team-provider-info.json create mode 100644 Website/HPIoTWebApp/angular.json create mode 100644 Website/HPIoTWebApp/browserslist create mode 100644 Website/HPIoTWebApp/e2e/protractor.conf.js create mode 100644 Website/HPIoTWebApp/e2e/src/app.e2e-spec.ts create mode 100644 Website/HPIoTWebApp/e2e/src/app.po.ts create mode 100644 Website/HPIoTWebApp/e2e/tsconfig.json create mode 100644 Website/HPIoTWebApp/karma.conf.js create mode 100644 Website/HPIoTWebApp/ngsw-config.json create mode 100644 Website/HPIoTWebApp/package-lock.json create mode 100644 Website/HPIoTWebApp/package.json create mode 100644 Website/HPIoTWebApp/src/app/app-routing.module.ts create mode 100644 Website/HPIoTWebApp/src/app/app.component.html create mode 100644 Website/HPIoTWebApp/src/app/app.component.scss create mode 100644 Website/HPIoTWebApp/src/app/app.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/app.component.ts create mode 100644 Website/HPIoTWebApp/src/app/app.module.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.component.html create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.component.scss create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.component.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.guard.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.guard.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.service.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/auth.service.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.html create mode 100644 Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.scss create mode 100644 Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.html create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.scss create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.html create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.scss create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/profile.component.html create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/profile.component.scss create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/profile.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/profile/profile.component.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.html create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.scss create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.html create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.scss create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/unauth.guard.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/auth/unauth.guard.ts create mode 100644 Website/HPIoTWebApp/src/app/configs/configs.component.html create mode 100644 Website/HPIoTWebApp/src/app/configs/configs.component.scss create mode 100644 Website/HPIoTWebApp/src/app/configs/configs.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/configs/configs.component.ts create mode 100644 Website/HPIoTWebApp/src/app/dashboard/dashboard.component.html create mode 100644 Website/HPIoTWebApp/src/app/dashboard/dashboard.component.scss create mode 100644 Website/HPIoTWebApp/src/app/dashboard/dashboard.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/dashboard/dashboard.component.ts create mode 100644 Website/HPIoTWebApp/src/app/loader/loader.component.html create mode 100644 Website/HPIoTWebApp/src/app/loader/loader.component.scss create mode 100644 Website/HPIoTWebApp/src/app/loader/loader.component.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/loader/loader.component.ts create mode 100644 Website/HPIoTWebApp/src/app/loader/loader.service.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/loader/loader.service.ts create mode 100644 Website/HPIoTWebApp/src/app/material/material.module.ts create mode 100644 Website/HPIoTWebApp/src/app/services/compressor.service.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/services/compressor.service.ts create mode 100644 Website/HPIoTWebApp/src/app/services/data.service.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/services/data.service.ts create mode 100644 Website/HPIoTWebApp/src/app/services/notification.service.spec.ts create mode 100644 Website/HPIoTWebApp/src/app/services/notification.service.ts create mode 100644 Website/HPIoTWebApp/src/assets/.gitkeep create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-128x128.png create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-144x144.png create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-152x152.png create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-192x192.png create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-384x384.png create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-512x512.png create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-72x72.png create mode 100644 Website/HPIoTWebApp/src/assets/icons/icon-96x96.png create mode 100644 Website/HPIoTWebApp/src/aws-exports.js create mode 100644 Website/HPIoTWebApp/src/environments/environment.ts create mode 100644 Website/HPIoTWebApp/src/favicon.ico create mode 100644 Website/HPIoTWebApp/src/index.html create mode 100644 Website/HPIoTWebApp/src/main.ts create mode 100644 Website/HPIoTWebApp/src/manifest.webmanifest create mode 100644 Website/HPIoTWebApp/src/polyfills.ts create mode 100644 Website/HPIoTWebApp/src/styles.scss create mode 100644 Website/HPIoTWebApp/src/test.ts create mode 100644 Website/HPIoTWebApp/tsconfig.app.json create mode 100644 Website/HPIoTWebApp/tsconfig.json create mode 100644 Website/HPIoTWebApp/tsconfig.spec.json create mode 100644 Website/HPIoTWebApp/tslint.json create mode 100644 Website/hpiot-react/.gitignore create mode 100644 Website/hpiot-react/README.md create mode 100644 Website/hpiot-react/amplify/#current-cloud-backend/amplify-meta.json create mode 100644 Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml create mode 100644 Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/parameters.json create mode 100644 Website/hpiot-react/amplify/#current-cloud-backend/backend-config.json create mode 100644 Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/parameters.json create mode 100644 Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/template.json create mode 100644 Website/hpiot-react/amplify/.config/local-aws-info.json create mode 100644 Website/hpiot-react/amplify/.config/local-env-info.json create mode 100644 Website/hpiot-react/amplify/.config/project-config.json create mode 100644 Website/hpiot-react/amplify/backend/amplify-meta.json create mode 100644 Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml create mode 100644 Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/parameters.json create mode 100644 Website/hpiot-react/amplify/backend/awscloudformation/nested-cloudformation-stack.yml create mode 100644 Website/hpiot-react/amplify/backend/backend-config.json create mode 100644 Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/parameters.json create mode 100644 Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/template.json create mode 100644 Website/hpiot-react/amplify/team-provider-info.json create mode 100644 Website/hpiot-react/package-lock.json create mode 100644 Website/hpiot-react/package.json create mode 100644 Website/hpiot-react/public/favicon.ico create mode 100644 Website/hpiot-react/public/icon-512x512.png create mode 100644 Website/hpiot-react/public/index.html create mode 100644 Website/hpiot-react/public/logo192.png create mode 100644 Website/hpiot-react/public/logo512.png create mode 100644 Website/hpiot-react/public/manifest.json create mode 100644 Website/hpiot-react/public/robots.txt create mode 100644 Website/hpiot-react/src/App.css create mode 100644 Website/hpiot-react/src/App.js create mode 100644 Website/hpiot-react/src/App.test.js create mode 100644 Website/hpiot-react/src/aws-exports-old.js create mode 100644 Website/hpiot-react/src/aws-exports.js create mode 100644 Website/hpiot-react/src/charts/BarChart.js create mode 100644 Website/hpiot-react/src/charts/LineChart.js create mode 100644 Website/hpiot-react/src/index.css create mode 100644 Website/hpiot-react/src/index.js create mode 100644 Website/hpiot-react/src/logo.svg create mode 100644 Website/hpiot-react/src/serviceWorker.js create mode 100644 Website/hpiot-react/src/setupTests.js create mode 100644 Website/hpiot-react/yarn.lock create mode 100644 Website/package.json create mode 100644 desktop.ini create mode 100644 example config.json create mode 100644 favicon.ico create mode 100644 hen_rgb.png create mode 100644 hen_rgb.xcf create mode 100644 hpicon-1408x1408.png create mode 100644 hpicon-1408x1408.xcf create mode 100644 icon-128x128.png create mode 100644 icon-144x144.png create mode 100644 icon-152x152.png create mode 100644 icon-192x192.png create mode 100644 icon-384x384.png create mode 100644 icon-512x512.png create mode 100644 icon-72x72.png create mode 100644 icon-96x96.png create mode 100644 jitp_template.json diff --git a/AmazonRootCA1.pem b/AmazonRootCA1.pem new file mode 100644 index 0000000..a6f3e92 --- /dev/null +++ b/AmazonRootCA1.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- diff --git a/Device/.gitattributes b/Device/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/Device/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/Device/LICENSE b/Device/LICENSE new file mode 100644 index 0000000..e62ec04 --- /dev/null +++ b/Device/LICENSE @@ -0,0 +1,674 @@ +GNU 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. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Device/README.md b/Device/README.md new file mode 100644 index 0000000..706dc63 --- /dev/null +++ b/Device/README.md @@ -0,0 +1,2 @@ +# AWS-Device + The files for using AWS IoT and collecting data from various data generators diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/MQTTLib.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/MQTTLib.py new file mode 100644 index 0000000..2a2527a --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/MQTTLib.py @@ -0,0 +1,1779 @@ +# +#/* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +from AWSIoTPythonSDK.core.util.providers import CertificateCredentialsProvider +from AWSIoTPythonSDK.core.util.providers import IAMCredentialsProvider +from AWSIoTPythonSDK.core.util.providers import EndpointProvider +from AWSIoTPythonSDK.core.jobs.thingJobManager import jobExecutionTopicType +from AWSIoTPythonSDK.core.jobs.thingJobManager import jobExecutionTopicReplyType +from AWSIoTPythonSDK.core.protocol.mqtt_core import MqttCore +import AWSIoTPythonSDK.core.shadow.shadowManager as shadowManager +import AWSIoTPythonSDK.core.shadow.deviceShadow as deviceShadow +import AWSIoTPythonSDK.core.jobs.thingJobManager as thingJobManager + +# Constants +# - Protocol types: +MQTTv3_1 = 3 +MQTTv3_1_1 = 4 + +DROP_OLDEST = 0 +DROP_NEWEST = 1 + +class AWSIoTMQTTClient: + + def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True): + """ + + The client class that connects to and accesses AWS IoT over MQTT v3.1/3.1.1. + + The following connection types are available: + + - TLSv1.2 Mutual Authentication + + X.509 certificate-based secured MQTT connection to AWS IoT + + - Websocket SigV4 + + IAM credential-based secured MQTT connection over Websocket to AWS IoT + + It provides basic synchronous MQTT operations in the classic MQTT publish-subscribe + model, along with configurations of on-top features: + + - Auto reconnect/resubscribe + + - Progressive reconnect backoff + + - Offline publish requests queueing with draining + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Create an AWS IoT MQTT Client using TLSv1.2 Mutual Authentication + myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient("testIoTPySDK") + # Create an AWS IoT MQTT Client using Websocket SigV4 + myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient("testIoTPySDK", useWebsocket=True) + + **Parameters** + + *clientID* - String that denotes the client identifier used to connect to AWS IoT. + If empty string were provided, client id for this connection will be randomly generated + n server side. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + :code:`AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient` object + + """ + self._mqtt_core = MqttCore(clientID, cleanSession, protocolType, useWebsocket) + + # Configuration APIs + def configureLastWill(self, topic, payload, QoS, retain=False): + """ + **Description** + + Used to configure the last will topic, payload and QoS of the client. Should be called before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0) + + **Parameters** + + *topic* - Topic name that last will publishes to. + + *payload* - Payload to publish for last will. + + *QoS* - Quality of Service. Could be 0 or 1. + + **Returns** + + None + + """ + self._mqtt_core.configure_last_will(topic, payload, QoS, retain) + + def clearLastWill(self): + """ + **Description** + + Used to clear the last will configuration that is previously set through configureLastWill. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.clearLastWill() + + **Parameter** + + None + + **Returns** + + None + + """ + self._mqtt_core.clear_last_will() + + def configureEndpoint(self, hostName, portNumber): + """ + **Description** + + Used to configure the host name and port number the client tries to connect to. Should be called + before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureEndpoint("random.iot.region.amazonaws.com", 8883) + + **Parameters** + + *hostName* - String that denotes the host name of the user-specific AWS IoT endpoint. + + *portNumber* - Integer that denotes the port number to connect to. Could be :code:`8883` for + TLSv1.2 Mutual Authentication or :code:`443` for Websocket SigV4 and TLSv1.2 Mutual Authentication + with ALPN extension. + + **Returns** + + None + + """ + endpoint_provider = EndpointProvider() + endpoint_provider.set_host(hostName) + endpoint_provider.set_port(portNumber) + self._mqtt_core.configure_endpoint(endpoint_provider) + if portNumber == 443 and not self._mqtt_core.use_wss(): + self._mqtt_core.configure_alpn_protocols() + + def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSessionToken=""): + """ + **Description** + + Used to configure/update the custom IAM credentials for Websocket SigV4 connection to + AWS IoT. Should be called before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureIAMCredentials(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken) + + .. note:: + + Hard-coding credentials into custom script is NOT recommended. Please use AWS Cognito identity service + or other credential provider. + + **Parameters** + + *AWSAccessKeyID* - AWS Access Key Id from user-specific IAM credentials. + + *AWSSecretAccessKey* - AWS Secret Access Key from user-specific IAM credentials. + + *AWSSessionToken* - AWS Session Token for temporary authentication from STS. + + **Returns** + + None + + """ + iam_credentials_provider = IAMCredentialsProvider() + iam_credentials_provider.set_access_key_id(AWSAccessKeyID) + iam_credentials_provider.set_secret_access_key(AWSSecretAccessKey) + iam_credentials_provider.set_session_token(AWSSessionToken) + self._mqtt_core.configure_iam_credentials(iam_credentials_provider) + + def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth certs config and Websocket rootCA config + """ + **Description** + + Used to configure the rootCA, private key and certificate files. Should be called before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureCredentials("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE") + + **Parameters** + + *CAFilePath* - Path to read the root CA file. Required for all connection types. + + *KeyPath* - Path to read the private key. Required for X.509 certificate based connection. + + *CertificatePath* - Path to read the certificate. Required for X.509 certificate based connection. + + **Returns** + + None + + """ + cert_credentials_provider = CertificateCredentialsProvider() + cert_credentials_provider.set_ca_path(CAFilePath) + cert_credentials_provider.set_key_path(KeyPath) + cert_credentials_provider.set_cert_path(CertificatePath) + self._mqtt_core.configure_cert_credentials(cert_credentials_provider) + + def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond): + """ + **Description** + + Used to configure the auto-reconnect backoff timing. Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure the auto-reconnect backoff to start with 1 second and use 128 seconds as a maximum back off time. + # Connection over 20 seconds is considered stable and will reset the back off time back to its base. + myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 128, 20) + + **Parameters** + + *baseReconnectQuietTimeSecond* - The initial back off time to start with, in seconds. + Should be less than the stableConnectionTime. + + *maxReconnectQuietTimeSecond* - The maximum back off time, in seconds. + + *stableConnectionTimeSecond* - The number of seconds for a connection to last to be considered as stable. + Back off time will be reset to base once the connection is stable. + + **Returns** + + None + + """ + self._mqtt_core.configure_reconnect_back_off(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond) + + def configureOfflinePublishQueueing(self, queueSize, dropBehavior=DROP_NEWEST): + """ + **Description** + + Used to configure the queue size and drop behavior for the offline requests queueing. Should be + called before connect. Queueable offline requests include publish, subscribe and unsubscribe. + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Configure the offline queue for publish requests to be 20 in size and drop the oldest + request when the queue is full. + myAWSIoTMQTTClient.configureOfflinePublishQueueing(20, AWSIoTPyMQTT.DROP_OLDEST) + + **Parameters** + + *queueSize* - Size of the queue for offline publish requests queueing. + If set to 0, the queue is disabled. If set to -1, the queue size is set to be infinite. + + *dropBehavior* - the type of drop behavior when the queue is full. + Could be :code:`AWSIoTPythonSDK.core.util.enums.DropBehaviorTypes.DROP_OLDEST` or + :code:`AWSIoTPythonSDK.core.util.enums.DropBehaviorTypes.DROP_NEWEST`. + + **Returns** + + None + + """ + self._mqtt_core.configure_offline_requests_queue(queueSize, dropBehavior) + + def configureDrainingFrequency(self, frequencyInHz): + """ + **Description** + + Used to configure the draining speed to clear up the queued requests when the connection is back. + Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure the draining speed to be 2 requests/second + myAWSIoTMQTTClient.configureDrainingFrequency(2) + + .. note:: + + Make sure the draining speed is fast enough and faster than the publish rate. Slow draining + could result in inifinite draining process. + + **Parameters** + + *frequencyInHz* - The draining speed to clear the queued requests, in requests/second. + + **Returns** + + None + + """ + self._mqtt_core.configure_draining_interval_sec(1/float(frequencyInHz)) + + def configureConnectDisconnectTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the time in seconds to wait for a CONNACK or a disconnect to complete. + Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure connect/disconnect timeout to be 10 seconds + myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a CONNACK or a disconnect to complete. + + **Returns** + + None + + """ + self._mqtt_core.configure_connect_disconnect_timeout_sec(timeoutSecond) + + def configureMQTTOperationTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the timeout in seconds for MQTT QoS 1 publish, subscribe and unsubscribe. + Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure MQTT operation timeout to be 5 seconds + myAWSIoTMQTTClient.configureMQTTOperationTimeout(5) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a PUBACK/SUBACK/UNSUBACK. + + **Returns** + + None + + """ + self._mqtt_core.configure_operation_timeout_sec(timeoutSecond) + + def configureUsernamePassword(self, username, password=None): + """ + **Description** + + Used to configure the username and password used in CONNECT packet. + + **Syntax** + + .. code:: python + + # Configure user name and password + myAWSIoTMQTTClient.configureUsernamePassword("myUsername", "myPassword") + + **Parameters** + + *username* - Username used in the username field of CONNECT packet. + + *password* - Password used in the password field of CONNECT packet. + + **Returns** + + None + + """ + self._mqtt_core.configure_username_password(username, password) + + def configureSocketFactory(self, socket_factory): + """ + **Description** + + Configure a socket factory to custom configure a different socket type for + mqtt connection. Creating a custom socket allows for configuration of a proxy + + **Syntax** + + .. code:: python + + # Configure socket factory + custom_args = {"arg1": "val1", "arg2": "val2"} + socket_factory = lambda: custom.create_connection((host, port), **custom_args) + myAWSIoTMQTTClient.configureSocketFactory(socket_factory) + + **Parameters** + + *socket_factory* - Anonymous function which creates a custom socket to spec. + + **Returns** + + None + + """ + self._mqtt_core.configure_socket_factory(socket_factory) + + def enableMetricsCollection(self): + """ + **Description** + + Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name + and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.enableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._mqtt_core.enable_metrics_collection() + + def disableMetricsCollection(self): + """ + **Description** + + Used to disable SDK metrics collection. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.disableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._mqtt_core.disable_metrics_collection() + + # MQTT functionality APIs + def connect(self, keepAliveIntervalSecond=600): + """ + **Description** + + Connect to AWS IoT, with user-specific keepalive interval configuration. + + **Syntax** + + .. code:: python + + # Connect to AWS IoT with default keepalive set to 600 seconds + myAWSIoTMQTTClient.connect() + # Connect to AWS IoT with keepalive interval set to 1200 seconds + myAWSIoTMQTTClient.connect(1200) + + **Parameters** + + *keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request. + A shorter keep-alive interval allows the client to detect disconnects more quickly. + Default set to 600 seconds. + + **Returns** + + True if the connect attempt succeeded. False if failed. + + """ + self._load_callbacks() + return self._mqtt_core.connect(keepAliveIntervalSecond) + + def connectAsync(self, keepAliveIntervalSecond=600, ackCallback=None): + """ + **Description** + + Connect asynchronously to AWS IoT, with user-specific keepalive interval configuration and CONNACK callback. + + **Syntax** + + .. code:: python + + # Connect to AWS IoT with default keepalive set to 600 seconds and a custom CONNACK callback + myAWSIoTMQTTClient.connectAsync(ackCallback=my_connack_callback) + # Connect to AWS IoT with default keepalive set to 1200 seconds and a custom CONNACK callback + myAWSIoTMQTTClient.connectAsync(keepAliveInternvalSecond=1200, ackCallback=myConnackCallback) + + **Parameters** + + *keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request. + Default set to 600 seconds. + + *ackCallback* - Callback to be invoked when the client receives a CONNACK. Should be in form + :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the connect request + and :code:`data` is the connect result code. + + **Returns** + + Connect request packet id, for tracking purpose in the corresponding callback. + + """ + self._load_callbacks() + return self._mqtt_core.connect_async(keepAliveIntervalSecond, ackCallback) + + def _load_callbacks(self): + self._mqtt_core.on_online = self.onOnline + self._mqtt_core.on_offline = self.onOffline + self._mqtt_core.on_message = self.onMessage + + def disconnect(self): + """ + **Description** + + Disconnect from AWS IoT. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.disconnect() + + **Parameters** + + None + + **Returns** + + True if the disconnect attempt succeeded. False if failed. + + """ + return self._mqtt_core.disconnect() + + def disconnectAsync(self, ackCallback=None): + """ + **Description** + + Disconnect asynchronously to AWS IoT. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.disconnectAsync(ackCallback=myDisconnectCallback) + + **Parameters** + + *ackCallback* - Callback to be invoked when the client finishes sending disconnect and internal clean-up. + Should be in form :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect + request and :code:`data` is the disconnect result code. + + **Returns** + + Disconnect request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.disconnect_async(ackCallback) + + def publish(self, topic, payload, QoS): + """ + **Description** + + Publish a new message to the desired topic with QoS. + + **Syntax** + + .. code:: python + + # Publish a QoS0 message "myPayload" to topic "myTopic" + myAWSIoTMQTTClient.publish("myTopic", "myPayload", 0) + # Publish a QoS1 message "myPayloadWithQos1" to topic "myTopic/sub" + myAWSIoTMQTTClient.publish("myTopic/sub", "myPayloadWithQos1", 1) + + **Parameters** + + *topic* - Topic name to publish to. + + *payload* - Payload to publish. + + *QoS* - Quality of Service. Could be 0 or 1. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + return self._mqtt_core.publish(topic, payload, QoS, False) # Disable retain for publish by now + + def publishAsync(self, topic, payload, QoS, ackCallback=None): + """ + **Description** + + Publish a new message asynchronously to the desired topic with QoS and PUBACK callback. Note that the ack + callback configuration for a QoS0 publish request will be ignored as there are no PUBACK reception. + + **Syntax** + + .. code:: python + + # Publish a QoS0 message "myPayload" to topic "myTopic" + myAWSIoTMQTTClient.publishAsync("myTopic", "myPayload", 0) + # Publish a QoS1 message "myPayloadWithQos1" to topic "myTopic/sub", with custom PUBACK callback + myAWSIoTMQTTClient.publishAsync("myTopic/sub", "myPayloadWithQos1", 1, ackCallback=myPubackCallback) + + **Parameters** + + *topic* - Topic name to publish to. + + *payload* - Payload to publish. + + *QoS* - Quality of Service. Could be 0 or 1. + + *ackCallback* - Callback to be invoked when the client receives a PUBACK. Should be in form + :code:`customCallback(mid)`, where :code:`mid` is the packet id for the disconnect request. + + **Returns** + + Publish request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.publish_async(topic, payload, QoS, False, ackCallback) + + def subscribe(self, topic, QoS, callback): + """ + **Description** + + Subscribe to the desired topic and register a callback. + + **Syntax** + + .. code:: python + + # Subscribe to "myTopic" with QoS0 and register a callback + myAWSIoTMQTTClient.subscribe("myTopic", 0, customCallback) + # Subscribe to "myTopic/#" with QoS1 and register a callback + myAWSIoTMQTTClient.subscribe("myTopic/#", 1, customCallback) + + **Parameters** + + *topic* - Topic name or filter to subscribe to. + + *QoS* - Quality of Service. Could be 0 or 1. + + *callback* - Function to be called when a new message for the subscribed topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + **Returns** + + True if the subscribe attempt succeeded. False if failed. + + """ + return self._mqtt_core.subscribe(topic, QoS, callback) + + def subscribeAsync(self, topic, QoS, ackCallback=None, messageCallback=None): + """ + **Description** + + Subscribe to the desired topic and register a message callback with SUBACK callback. + + **Syntax** + + .. code:: python + + # Subscribe to "myTopic" with QoS0, custom SUBACK callback and a message callback + myAWSIoTMQTTClient.subscribe("myTopic", 0, ackCallback=mySubackCallback, messageCallback=customMessageCallback) + # Subscribe to "myTopic/#" with QoS1, custom SUBACK callback and a message callback + myAWSIoTMQTTClient.subscribe("myTopic/#", 1, ackCallback=mySubackCallback, messageCallback=customMessageCallback) + + **Parameters** + + *topic* - Topic name or filter to subscribe to. + + *QoS* - Quality of Service. Could be 0 or 1. + + *ackCallback* - Callback to be invoked when the client receives a SUBACK. Should be in form + :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect request and + :code:`data` is the granted QoS for this subscription. + + *messageCallback* - Function to be called when a new message for the subscribed topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + **Returns** + + Subscribe request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.subscribe_async(topic, QoS, ackCallback, messageCallback) + + def unsubscribe(self, topic): + """ + **Description** + + Unsubscribe to the desired topic. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.unsubscribe("myTopic") + + **Parameters** + + *topic* - Topic name or filter to unsubscribe to. + + **Returns** + + True if the unsubscribe attempt succeeded. False if failed. + + """ + return self._mqtt_core.unsubscribe(topic) + + def unsubscribeAsync(self, topic, ackCallback=None): + """ + **Description** + + Unsubscribe to the desired topic with UNSUBACK callback. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.unsubscribe("myTopic", ackCallback=myUnsubackCallback) + + **Parameters** + + *topic* - Topic name or filter to unsubscribe to. + + *ackCallback* - Callback to be invoked when the client receives a UNSUBACK. Should be in form + :code:`customCallback(mid)`, where :code:`mid` is the packet id for the disconnect request. + + **Returns** + + Unsubscribe request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.unsubscribe_async(topic, ackCallback) + + def onOnline(self): + """ + **Description** + + Callback that gets called when the client is online. The callback registration should happen before calling + connect/connectAsync. + + **Syntax** + + .. code:: python + + # Register an onOnline callback + myAWSIoTMQTTClient.onOnline = myOnOnlineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + def onOffline(self): + """ + **Description** + + Callback that gets called when the client is offline. The callback registration should happen before calling + connect/connectAsync. + + **Syntax** + + .. code:: python + + # Register an onOffline callback + myAWSIoTMQTTClient.onOffline = myOnOfflineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + def onMessage(self, message): + """ + **Description** + + Callback that gets called when the client receives a new message. The callback registration should happen before + calling connect/connectAsync. This callback, if present, will always be triggered regardless of whether there is + any message callback registered upon subscribe API call. It is for the purpose to aggregating the processing of + received messages in one function. + + **Syntax** + + .. code:: python + + # Register an onMessage callback + myAWSIoTMQTTClient.onMessage = myOnMessageCallback + + **Parameters** + + *message* - Received MQTT message. It contains the source topic as :code:`message.topic`, and the payload as + :code:`message.payload`. + + **Returns** + + None + + """ + pass + +class _AWSIoTMQTTDelegatingClient(object): + + def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None): + """ + + This class is used internally by the SDK and should not be instantiated directly. + + It delegates to a provided AWS IoT MQTT Client or creates a new one given the configuration + parameters and exposes core operations for subclasses provide convenience methods + + **Syntax** + + None + + **Parameters** + + *clientID* - String that denotes the client identifier used to connect to AWS IoT. + If empty string were provided, client id for this connection will be randomly generated + n server side. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + AWSIoTPythonSDK.MQTTLib._AWSIoTMQTTDelegatingClient object + + """ + # AWSIOTMQTTClient instance + self._AWSIoTMQTTClient = awsIoTMQTTClient if awsIoTMQTTClient is not None else AWSIoTMQTTClient(clientID, protocolType, useWebsocket, cleanSession) + + # Configuration APIs + def configureLastWill(self, topic, payload, QoS): + """ + **Description** + + Used to configure the last will topic, payload and QoS of the client. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0) + myJobsClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0) + + **Parameters** + + *topic* - Topic name that last will publishes to. + + *payload* - Payload to publish for last will. + + *QoS* - Quality of Service. Could be 0 or 1. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureLastWill(srcTopic, srcPayload, srcQos) + self._AWSIoTMQTTClient.configureLastWill(topic, payload, QoS) + + def clearLastWill(self): + """ + **Description** + + Used to clear the last will configuration that is previously set through configureLastWill. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill() + myJobsClient.clearLastWill() + + **Parameter** + + None + + **Returns** + + None + + """ + # AWSIoTMQTTClient.clearLastWill() + self._AWSIoTMQTTClient.clearLastWill() + + def configureEndpoint(self, hostName, portNumber): + """ + **Description** + + Used to configure the host name and port number the underneath AWS IoT MQTT Client tries to connect to. Should be called + before connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill("random.iot.region.amazonaws.com", 8883) + myJobsClient.clearLastWill("random.iot.region.amazonaws.com", 8883) + + **Parameters** + + *hostName* - String that denotes the host name of the user-specific AWS IoT endpoint. + + *portNumber* - Integer that denotes the port number to connect to. Could be :code:`8883` for + TLSv1.2 Mutual Authentication or :code:`443` for Websocket SigV4 and TLSv1.2 Mutual Authentication + with ALPN extension. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureEndpoint + self._AWSIoTMQTTClient.configureEndpoint(hostName, portNumber) + + def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken=""): + """ + **Description** + + Used to configure/update the custom IAM credentials for the underneath AWS IoT MQTT Client + for Websocket SigV4 connection to AWS IoT. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken) + myJobsClient.clearLastWill(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken) + + .. note:: + + Hard-coding credentials into custom script is NOT recommended. Please use AWS Cognito identity service + or other credential provider. + + **Parameters** + + *AWSAccessKeyID* - AWS Access Key Id from user-specific IAM credentials. + + *AWSSecretAccessKey* - AWS Secret Access Key from user-specific IAM credentials. + + *AWSSessionToken* - AWS Session Token for temporary authentication from STS. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureIAMCredentials + self._AWSIoTMQTTClient.configureIAMCredentials(AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken) + + def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth and Websocket + """ + **Description** + + Used to configure the rootCA, private key and certificate files. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE") + myJobsClient.clearLastWill("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE") + + **Parameters** + + *CAFilePath* - Path to read the root CA file. Required for all connection types. + + *KeyPath* - Path to read the private key. Required for X.509 certificate based connection. + + *CertificatePath* - Path to read the certificate. Required for X.509 certificate based connection. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureCredentials + self._AWSIoTMQTTClient.configureCredentials(CAFilePath, KeyPath, CertificatePath) + + def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond): + """ + **Description** + + Used to configure the auto-reconnect backoff timing. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure the auto-reconnect backoff to start with 1 second and use 128 seconds as a maximum back off time. + # Connection over 20 seconds is considered stable and will reset the back off time back to its base. + myShadowClient.clearLastWill(1, 128, 20) + myJobsClient.clearLastWill(1, 128, 20) + + **Parameters** + + *baseReconnectQuietTimeSecond* - The initial back off time to start with, in seconds. + Should be less than the stableConnectionTime. + + *maxReconnectQuietTimeSecond* - The maximum back off time, in seconds. + + *stableConnectionTimeSecond* - The number of seconds for a connection to last to be considered as stable. + Back off time will be reset to base once the connection is stable. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureBackoffTime + self._AWSIoTMQTTClient.configureAutoReconnectBackoffTime(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond) + + def configureConnectDisconnectTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the time in seconds to wait for a CONNACK or a disconnect to complete. + Should be called before connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure connect/disconnect timeout to be 10 seconds + myShadowClient.configureConnectDisconnectTimeout(10) + myJobsClient.configureConnectDisconnectTimeout(10) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a CONNACK or a disconnect to complete. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureConnectDisconnectTimeout + self._AWSIoTMQTTClient.configureConnectDisconnectTimeout(timeoutSecond) + + def configureMQTTOperationTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the timeout in seconds for MQTT QoS 1 publish, subscribe and unsubscribe. + Should be called before connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure MQTT operation timeout to be 5 seconds + myShadowClient.configureMQTTOperationTimeout(5) + myJobsClient.configureMQTTOperationTimeout(5) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a PUBACK/SUBACK/UNSUBACK. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureMQTTOperationTimeout + self._AWSIoTMQTTClient.configureMQTTOperationTimeout(timeoutSecond) + + def configureUsernamePassword(self, username, password=None): + """ + **Description** + + Used to configure the username and password used in CONNECT packet. This is a public facing API + inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure user name and password + myShadowClient.configureUsernamePassword("myUsername", "myPassword") + myJobsClient.configureUsernamePassword("myUsername", "myPassword") + + **Parameters** + + *username* - Username used in the username field of CONNECT packet. + + *password* - Password used in the password field of CONNECT packet. + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.configureUsernamePassword(username, password) + + def configureSocketFactory(self, socket_factory): + """ + **Description** + + Configure a socket factory to custom configure a different socket type for + mqtt connection. Creating a custom socket allows for configuration of a proxy + + **Syntax** + + .. code:: python + + # Configure socket factory + custom_args = {"arg1": "val1", "arg2": "val2"} + socket_factory = lambda: custom.create_connection((host, port), **custom_args) + myAWSIoTMQTTClient.configureSocketFactory(socket_factory) + + **Parameters** + + *socket_factory* - Anonymous function which creates a custom socket to spec. + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.configureSocketFactory(socket_factory) + + def enableMetricsCollection(self): + """ + **Description** + + Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name + and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default. + This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.enableMetricsCollection() + myJobsClient.enableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.enableMetricsCollection() + + def disableMetricsCollection(self): + """ + **Description** + + Used to disable SDK metrics collection. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.disableMetricsCollection() + myJobsClient.disableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.disableMetricsCollection() + + # Start the MQTT connection + def connect(self, keepAliveIntervalSecond=600): + """ + **Description** + + Connect to AWS IoT, with user-specific keepalive interval configuration. This is a public facing API inherited + by application level public clients. + + **Syntax** + + .. code:: python + + # Connect to AWS IoT with default keepalive set to 600 seconds + myShadowClient.connect() + myJobsClient.connect() + # Connect to AWS IoT with keepalive interval set to 1200 seconds + myShadowClient.connect(1200) + myJobsClient.connect(1200) + + **Parameters** + + *keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request. + Default set to 30 seconds. + + **Returns** + + True if the connect attempt succeeded. False if failed. + + """ + self._load_callbacks() + return self._AWSIoTMQTTClient.connect(keepAliveIntervalSecond) + + def _load_callbacks(self): + self._AWSIoTMQTTClient.onOnline = self.onOnline + self._AWSIoTMQTTClient.onOffline = self.onOffline + + # End the MQTT connection + def disconnect(self): + """ + **Description** + + Disconnect from AWS IoT. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.disconnect() + myJobsClient.disconnect() + + **Parameters** + + None + + **Returns** + + True if the disconnect attempt succeeded. False if failed. + + """ + return self._AWSIoTMQTTClient.disconnect() + + # MQTT connection management API + def getMQTTConnection(self): + """ + **Description** + + Retrieve the AWS IoT MQTT Client used underneath, making it possible to perform + plain MQTT operations along with specialized operations using the same single connection. + This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Retrieve the AWS IoT MQTT Client used in the AWS IoT MQTT Delegating Client + thisAWSIoTMQTTClient = myShadowClient.getMQTTConnection() + thisAWSIoTMQTTClient = myJobsClient.getMQTTConnection() + # Perform plain MQTT operations using the same connection + thisAWSIoTMQTTClient.publish("Topic", "Payload", 1) + ... + + **Parameters** + + None + + **Returns** + + AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient object + + """ + # Return the internal AWSIoTMQTTClient instance + return self._AWSIoTMQTTClient + + def onOnline(self): + """ + **Description** + + Callback that gets called when the client is online. The callback registration should happen before calling + connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Register an onOnline callback + myShadowClient.onOnline = myOnOnlineCallback + myJobsClient.onOnline = myOnOnlineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + def onOffline(self): + """ + **Description** + + Callback that gets called when the client is offline. The callback registration should happen before calling + connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Register an onOffline callback + myShadowClient.onOffline = myOnOfflineCallback + myJobsClient.onOffline = myOnOfflineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + +class AWSIoTMQTTShadowClient(_AWSIoTMQTTDelegatingClient): + + def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None): + """ + + The client class that manages device shadow and accesses its functionality in AWS IoT over MQTT v3.1/3.1.1. + + It delegates to the AWS IoT MQTT Client and exposes devive shadow related operations. + It shares the same connection types, synchronous MQTT operations and partial on-top features + with the AWS IoT MQTT Client: + + - Auto reconnect/resubscribe + + Same as AWS IoT MQTT Client. + + - Progressive reconnect backoff + + Same as AWS IoT MQTT Client. + + - Offline publish requests queueing with draining + + Disabled by default. Queueing is not allowed for time-sensitive shadow requests/messages. + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Create an AWS IoT MQTT Shadow Client using TLSv1.2 Mutual Authentication + myAWSIoTMQTTShadowClient = AWSIoTPyMQTT.AWSIoTMQTTShadowClient("testIoTPySDK") + # Create an AWS IoT MQTT Shadow Client using Websocket SigV4 + myAWSIoTMQTTShadowClient = AWSIoTPyMQTT.AWSIoTMQTTShadowClient("testIoTPySDK", useWebsocket=True) + + **Parameters** + + *clientID* - String that denotes the client identifier used to connect to AWS IoT. + If empty string were provided, client id for this connection will be randomly generated + n server side. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTShadowClient object + + """ + super(AWSIoTMQTTShadowClient, self).__init__(clientID, protocolType, useWebsocket, cleanSession, awsIoTMQTTClient) + #leave passed in clients alone + if awsIoTMQTTClient is None: + # Configure it to disable offline Publish Queueing + self._AWSIoTMQTTClient.configureOfflinePublishQueueing(0) # Disable queueing, no queueing for time-sensitive shadow messages + self._AWSIoTMQTTClient.configureDrainingFrequency(10) + # Now retrieve the configured mqttCore and init a shadowManager instance + self._shadowManager = shadowManager.shadowManager(self._AWSIoTMQTTClient._mqtt_core) + + # Shadow management API + def createShadowHandlerWithName(self, shadowName, isPersistentSubscribe): + """ + **Description** + + Create a device shadow handler using the specified shadow name and isPersistentSubscribe. + + **Syntax** + + .. code:: python + + # Create a device shadow handler for shadow named "Bot1", using persistent subscription + Bot1Shadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("Bot1", True) + # Create a device shadow handler for shadow named "Bot2", using non-persistent subscription + Bot2Shadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("Bot2", False) + + **Parameters** + + *shadowName* - Name of the device shadow. + + *isPersistentSubscribe* - Whether to unsubscribe from shadow response (accepted/rejected) topics + when there is a response. Will subscribe at the first time the shadow request is made and will + not unsubscribe if isPersistentSubscribe is set. + + **Returns** + + AWSIoTPythonSDK.core.shadow.deviceShadow.deviceShadow object, which exposes the device shadow interface. + + """ + # Create and return a deviceShadow instance + return deviceShadow.deviceShadow(shadowName, isPersistentSubscribe, self._shadowManager) + # Shadow APIs are accessible in deviceShadow instance": + ### + # deviceShadow.shadowGet + # deviceShadow.shadowUpdate + # deviceShadow.shadowDelete + # deviceShadow.shadowRegisterDelta + # deviceShadow.shadowUnregisterDelta + +class AWSIoTMQTTThingJobsClient(_AWSIoTMQTTDelegatingClient): + + def __init__(self, clientID, thingName, QoS=0, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None): + """ + + The client class that specializes in handling jobs messages and accesses its functionality in AWS IoT over MQTT v3.1/3.1.1. + + It delegates to the AWS IoT MQTT Client and exposes jobs related operations. + It shares the same connection types, synchronous MQTT operations and partial on-top features + with the AWS IoT MQTT Client: + + - Auto reconnect/resubscribe + + Same as AWS IoT MQTT Client. + + - Progressive reconnect backoff + + Same as AWS IoT MQTT Client. + + - Offline publish requests queueing with draining + + Same as AWS IoT MQTT Client + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Create an AWS IoT MQTT Jobs Client using TLSv1.2 Mutual Authentication + myAWSIoTMQTTJobsClient = AWSIoTPyMQTT.AWSIoTMQTTThingJobsClient("testIoTPySDK") + # Create an AWS IoT MQTT Jobs Client using Websocket SigV4 + myAWSIoTMQTTJobsClient = AWSIoTPyMQTT.AWSIoTMQTTThingJobsClient("testIoTPySDK", useWebsocket=True) + + **Parameters** + + *clientID* - String that denotes the client identifier and client token for jobs requests + If empty string is provided, client id for this connection will be randomly generated + on server side. If an awsIotMQTTClient is specified, this will not override the client ID + for the existing MQTT connection and only impact the client token for jobs request payloads + + *thingName* - String that represents the thingName used to send requests to proper topics and subscribe + to proper topics. + + *QoS* - QoS used for all requests sent through this client + + *awsIoTMQTTClient* - An instance of AWSIoTMQTTClient to use if not None. If not None, clientID, protocolType, useWebSocket, + and cleanSession parameters are not used. Caller is expected to invoke connect() prior to calling the pub/sub methods on this client. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTJobsClient object + + """ + # AWSIOTMQTTClient instance + super(AWSIoTMQTTThingJobsClient, self).__init__(clientID, protocolType, useWebsocket, cleanSession, awsIoTMQTTClient) + self._thingJobManager = thingJobManager.thingJobManager(thingName, clientID) + self._QoS = QoS + + def createJobSubscription(self, callback, jobExecutionType=jobExecutionTopicType.JOB_WILDCARD_TOPIC, jobReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None): + """ + **Description** + + Synchronously creates an MQTT subscription to a jobs related topic based on the provided arguments + + **Syntax** + + .. code:: python + + #Subscribe to notify-next topic to monitor change in job referred to by $next + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) + #Subscribe to notify topic to monitor changes to jobs in pending list + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_NOTIFY_TOPIC) + #Subscribe to receive messages for job execution updates + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE) + #Subscribe to receive messages for describing a job execution + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE, jobId) + + **Parameters** + + *callback* - Function to be called when a new message for the subscribed job topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + *jobExecutionType* - Member of the jobExecutionTopicType class specifying the jobs topic to subscribe to + Defaults to jobExecutionTopicType.JOB_WILDCARD_TOPIC + + *jobReplyType* - Member of the jobExecutionTopicReplyType class specifying the (optional) reply sub-topic to subscribe to + Defaults to jobExecutionTopicReplyType.JOB_REQUEST_TYPE which indicates the subscription isn't intended for a jobs reply topic + + *jobId* - JobId string if the topic type requires one. + Defaults to None + + **Returns** + + True if the subscribe attempt succeeded. False if failed. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionType, jobReplyType, jobId) + return self._AWSIoTMQTTClient.subscribe(topic, self._QoS, callback) + + def createJobSubscriptionAsync(self, ackCallback, callback, jobExecutionType=jobExecutionTopicType.JOB_WILDCARD_TOPIC, jobReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None): + """ + **Description** + + Asynchronously creates an MQTT subscription to a jobs related topic based on the provided arguments + + **Syntax** + + .. code:: python + + #Subscribe to notify-next topic to monitor change in job referred to by $next + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) + #Subscribe to notify topic to monitor changes to jobs in pending list + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_NOTIFY_TOPIC) + #Subscribe to receive messages for job execution updates + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE) + #Subscribe to receive messages for describing a job execution + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE, jobId) + + **Parameters** + + *ackCallback* - Callback to be invoked when the client receives a SUBACK. Should be in form + :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect request and + :code:`data` is the granted QoS for this subscription. + + *callback* - Function to be called when a new message for the subscribed job topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + *jobExecutionType* - Member of the jobExecutionTopicType class specifying the jobs topic to subscribe to + Defaults to jobExecutionTopicType.JOB_WILDCARD_TOPIC + + *jobReplyType* - Member of the jobExecutionTopicReplyType class specifying the (optional) reply sub-topic to subscribe to + Defaults to jobExecutionTopicReplyType.JOB_REQUEST_TYPE which indicates the subscription isn't intended for a jobs reply topic + + *jobId* - JobId of the topic if the topic type requires one. + Defaults to None + + **Returns** + + Subscribe request packet id, for tracking purpose in the corresponding callback. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionType, jobReplyType, jobId) + return self._AWSIoTMQTTClient.subscribeAsync(topic, self._QoS, ackCallback, callback) + + def sendJobsQuery(self, jobExecTopicType, jobId=None): + """ + **Description** + + Publishes an MQTT jobs related request for a potentially specific jobId (or wildcard) + + **Syntax** + + .. code:: python + + #send a request to describe the next job + myAWSIoTMQTTJobsClient.sendJobsQuery(jobExecutionTopicType.JOB_DESCRIBE_TOPIC, '$next') + #send a request to get list of pending jobs + myAWSIoTMQTTJobsClient.sendJobsQuery(jobExecutionTopicType.JOB_GET_PENDING_TOPIC) + + **Parameters** + + *jobExecutionType* - Member of the jobExecutionTopicType class that correlates the jobs topic to publish to + + *jobId* - JobId string if the topic type requires one. + Defaults to None + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecTopicType, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId) + payload = self._thingJobManager.serializeClientTokenPayload() + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) + + def sendJobsStartNext(self, statusDetails=None, stepTimeoutInMinutes=None): + """ + **Description** + + Publishes an MQTT message to the StartNextJobExecution topic. This will attempt to get the next pending + job execution and change its status to IN_PROGRESS. + + **Syntax** + + .. code:: python + + #Start next job (set status to IN_PROGRESS) and update with optional statusDetails + myAWSIoTMQTTJobsClient.sendJobsStartNext({'StartedBy': 'myClientId'}) + + **Parameters** + + *statusDetails* - Dictionary containing the key value pairs to use for the status details of the job execution + + *stepTimeoutInMinutes - Specifies the amount of time this device has to finish execution of this job. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_START_NEXT_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE) + payload = self._thingJobManager.serializeStartNextPendingJobExecutionPayload(statusDetails, stepTimeoutInMinutes) + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) + + def sendJobsUpdate(self, jobId, status, statusDetails=None, expectedVersion=0, executionNumber=0, includeJobExecutionState=False, includeJobDocument=False, stepTimeoutInMinutes=None): + """ + **Description** + + Publishes an MQTT message to a corresponding job execution specific topic to update its status according to the parameters. + Can be used to change a job from QUEUED to IN_PROGRESS to SUCEEDED or FAILED. + + **Syntax** + + .. code:: python + + #Update job with id 'jobId123' to succeeded state, specifying new status details, with expectedVersion=1, executionNumber=2. + #For the response, include job execution state and not the job document + myAWSIoTMQTTJobsClient.sendJobsUpdate('jobId123', jobExecutionStatus.JOB_EXECUTION_SUCCEEDED, statusDetailsMap, 1, 2, True, False) + + + #Update job with id 'jobId456' to failed state + myAWSIoTMQTTJobsClient.sendJobsUpdate('jobId456', jobExecutionStatus.JOB_EXECUTION_FAILED) + + **Parameters** + + *jobId* - JobID String of the execution to update the status of + + *status* - job execution status to change the job execution to. Member of jobExecutionStatus + + *statusDetails* - new status details to set on the job execution + + *expectedVersion* - The expected current version of the job execution. IoT jobs increments expectedVersion each time you update the job execution. + If the version of the job execution stored in Jobs does not match, the update is rejected with a VersionMismatch error, and an ErrorResponse + that contains the current job execution status data is returned. (This makes it unnecessary to perform a separate DescribeJobExecution request + n order to obtain the job execution status data.) + + *executionNumber* - A number that identifies a particular job execution on a particular device. If not specified, the latest job execution is used. + + *includeJobExecutionState* - When included and set to True, the response contains the JobExecutionState field. The default is False. + + *includeJobDocument* - When included and set to True, the response contains the JobDocument. The default is False. + + *stepTimeoutInMinutes - Specifies the amount of time this device has to finish execution of this job. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId) + payload = self._thingJobManager.serializeJobExecutionUpdatePayload(status, statusDetails, expectedVersion, executionNumber, includeJobExecutionState, includeJobDocument, stepTimeoutInMinutes) + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) + + def sendJobsDescribe(self, jobId, executionNumber=0, includeJobDocument=True): + """ + **Description** + + Publishes a method to the describe topic for a particular job. + + **Syntax** + + .. code:: python + + #Describe job with id 'jobId1' of any executionNumber, job document will be included in response + myAWSIoTMQTTJobsClient.sendJobsDescribe('jobId1') + + #Describe job with id 'jobId2', with execution number of 2, and includeJobDocument in the response + myAWSIoTMQTTJobsClient.sendJobsDescribe('jobId2', 2, True) + + **Parameters** + + *jobId* - jobID to describe. This is allowed to be a wildcard such as '$next' + + *executionNumber* - A number that identifies a particular job execution on a particular device. If not specified, the latest job execution is used. + + *includeJobDocument* - When included and set to True, the response contains the JobDocument. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId) + payload = self._thingJobManager.serializeDescribeJobExecutionPayload(executionNumber, includeJobDocument) + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/__init__.py new file mode 100644 index 0000000..eda1560 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/__init__.py @@ -0,0 +1,3 @@ +__version__ = "1.4.8" + + diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/__init__.pyc b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67b596c4c62a5942619feffac4b1d5285a9beb59 GIT binary patch literal 267 zcmYL^!D<3A5Qd{76t(Y=Q`sJN2f>4fQYtK^Qfh@=5j+^Sn}G&5nPro;^*#EgzJRk* zFz|nwKlvGE2Iu<`P9FB9_&+_qUs!&`&_e8(J&{HI?rq4JCbML|in?4FGn6`F;|)2b zBDUfN|Hl@r3sAzwa|l+ZB>90AIfS&K`ip*L^oFiE$#rY%N4V8;(FU?b;Knk?!pc{w zG&Zo number_of_crlf * 2 - 1 + if has_enough_bytes: + end_of_received = response[number_bytes_read - number_of_crlf * 2 : number_bytes_read] + expected_end_of_response = b"\r\n" * number_of_crlf + return end_of_received == expected_end_of_response + else: + return False + + def _handle_discovery_response_header(self, rc, response): + self._raise_on_timeout(rc) + http_status_code_matcher = re.compile(self.HTTP_RESPONSE_CODE_PATTERN) + http_status_code_matched_groups = http_status_code_matcher.match(response) + content_length_matcher = re.compile(self.CONTENT_LENGTH_PATTERN) + content_length_matched_groups = content_length_matcher.search(response) + return http_status_code_matched_groups.group(1), content_length_matched_groups.group(1) + + def _handle_discovery_response_body(self, rc, response): + self._raise_on_timeout(rc) + return response + + def _raise_on_timeout(self, rc): + if rc == self.LOW_LEVEL_RC_TIMEOUT: + raise DiscoveryTimeoutException() + + def _raise_if_not_200(self, status_code, response_body): # response_body here is str in Py3 + if status_code != self.HTTP_SC_200: + expected_exception = self._expected_exception_map.get(status_code) + if expected_exception: + raise expected_exception + else: + raise DiscoveryFailure(response_body) + return DiscoveryInfo(response_body) diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/jobs/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/jobs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/jobs/thingJobManager.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/jobs/thingJobManager.py new file mode 100644 index 0000000..d2396b2 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/jobs/thingJobManager.py @@ -0,0 +1,156 @@ +# /* +# * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import json + +_BASE_THINGS_TOPIC = "$aws/things/" +_NOTIFY_OPERATION = "notify" +_NOTIFY_NEXT_OPERATION = "notify-next" +_GET_OPERATION = "get" +_START_NEXT_OPERATION = "start-next" +_WILDCARD_OPERATION = "+" +_UPDATE_OPERATION = "update" +_ACCEPTED_REPLY = "accepted" +_REJECTED_REPLY = "rejected" +_WILDCARD_REPLY = "#" + +#Members of this enum are tuples +_JOB_ID_REQUIRED_INDEX = 1 +_JOB_OPERATION_INDEX = 2 + +_STATUS_KEY = 'status' +_STATUS_DETAILS_KEY = 'statusDetails' +_EXPECTED_VERSION_KEY = 'expectedVersion' +_EXEXCUTION_NUMBER_KEY = 'executionNumber' +_INCLUDE_JOB_EXECUTION_STATE_KEY = 'includeJobExecutionState' +_INCLUDE_JOB_DOCUMENT_KEY = 'includeJobDocument' +_CLIENT_TOKEN_KEY = 'clientToken' +_STEP_TIMEOUT_IN_MINUTES_KEY = 'stepTimeoutInMinutes' + +#The type of job topic. +class jobExecutionTopicType(object): + JOB_UNRECOGNIZED_TOPIC = (0, False, '') + JOB_GET_PENDING_TOPIC = (1, False, _GET_OPERATION) + JOB_START_NEXT_TOPIC = (2, False, _START_NEXT_OPERATION) + JOB_DESCRIBE_TOPIC = (3, True, _GET_OPERATION) + JOB_UPDATE_TOPIC = (4, True, _UPDATE_OPERATION) + JOB_NOTIFY_TOPIC = (5, False, _NOTIFY_OPERATION) + JOB_NOTIFY_NEXT_TOPIC = (6, False, _NOTIFY_NEXT_OPERATION) + JOB_WILDCARD_TOPIC = (7, False, _WILDCARD_OPERATION) + +#Members of this enum are tuples +_JOB_SUFFIX_INDEX = 1 +#The type of reply topic, or #JOB_REQUEST_TYPE for topics that are not replies. +class jobExecutionTopicReplyType(object): + JOB_UNRECOGNIZED_TOPIC_TYPE = (0, '') + JOB_REQUEST_TYPE = (1, '') + JOB_ACCEPTED_REPLY_TYPE = (2, '/' + _ACCEPTED_REPLY) + JOB_REJECTED_REPLY_TYPE = (3, '/' + _REJECTED_REPLY) + JOB_WILDCARD_REPLY_TYPE = (4, '/' + _WILDCARD_REPLY) + +_JOB_STATUS_INDEX = 1 +class jobExecutionStatus(object): + JOB_EXECUTION_STATUS_NOT_SET = (0, None) + JOB_EXECUTION_QUEUED = (1, 'QUEUED') + JOB_EXECUTION_IN_PROGRESS = (2, 'IN_PROGRESS') + JOB_EXECUTION_FAILED = (3, 'FAILED') + JOB_EXECUTION_SUCCEEDED = (4, 'SUCCEEDED') + JOB_EXECUTION_CANCELED = (5, 'CANCELED') + JOB_EXECUTION_REJECTED = (6, 'REJECTED') + JOB_EXECUTION_UNKNOWN_STATUS = (99, None) + +def _getExecutionStatus(jobStatus): + try: + return jobStatus[_JOB_STATUS_INDEX] + except KeyError: + return None + +def _isWithoutJobIdTopicType(srcJobExecTopicType): + return (srcJobExecTopicType == jobExecutionTopicType.JOB_GET_PENDING_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_START_NEXT_TOPIC + or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) + +class thingJobManager: + def __init__(self, thingName, clientToken = None): + self._thingName = thingName + self._clientToken = clientToken + + def getJobTopic(self, srcJobExecTopicType, srcJobExecTopicReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None): + if self._thingName is None: + return None + + #Verify topics that only support request type, actually have request type specified for reply + if (srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) and srcJobExecTopicReplyType != jobExecutionTopicReplyType.JOB_REQUEST_TYPE: + return None + + #Verify topics that explicitly do not want a job ID do not have one specified + if (jobId is not None and _isWithoutJobIdTopicType(srcJobExecTopicType)): + return None + + #Verify job ID is present if the topic requires one + if jobId is None and srcJobExecTopicType[_JOB_ID_REQUIRED_INDEX]: + return None + + #Ensure the job operation is a non-empty string + if srcJobExecTopicType[_JOB_OPERATION_INDEX] == '': + return None + + if srcJobExecTopicType[_JOB_ID_REQUIRED_INDEX]: + return '{0}{1}/jobs/{2}/{3}{4}'.format(_BASE_THINGS_TOPIC, self._thingName, str(jobId), srcJobExecTopicType[_JOB_OPERATION_INDEX], srcJobExecTopicReplyType[_JOB_SUFFIX_INDEX]) + elif srcJobExecTopicType == jobExecutionTopicType.JOB_WILDCARD_TOPIC: + return '{0}{1}/jobs/#'.format(_BASE_THINGS_TOPIC, self._thingName) + else: + return '{0}{1}/jobs/{2}{3}'.format(_BASE_THINGS_TOPIC, self._thingName, srcJobExecTopicType[_JOB_OPERATION_INDEX], srcJobExecTopicReplyType[_JOB_SUFFIX_INDEX]) + + def serializeJobExecutionUpdatePayload(self, status, statusDetails=None, expectedVersion=0, executionNumber=0, includeJobExecutionState=False, includeJobDocument=False, stepTimeoutInMinutes=None): + executionStatus = _getExecutionStatus(status) + if executionStatus is None: + return None + payload = {_STATUS_KEY: executionStatus} + if statusDetails: + payload[_STATUS_DETAILS_KEY] = statusDetails + if expectedVersion > 0: + payload[_EXPECTED_VERSION_KEY] = str(expectedVersion) + if executionNumber > 0: + payload[_EXEXCUTION_NUMBER_KEY] = str(executionNumber) + if includeJobExecutionState: + payload[_INCLUDE_JOB_EXECUTION_STATE_KEY] = True + if includeJobDocument: + payload[_INCLUDE_JOB_DOCUMENT_KEY] = True + if self._clientToken is not None: + payload[_CLIENT_TOKEN_KEY] = self._clientToken + if stepTimeoutInMinutes is not None: + payload[_STEP_TIMEOUT_IN_MINUTES_KEY] = stepTimeoutInMinutes + return json.dumps(payload) + + def serializeDescribeJobExecutionPayload(self, executionNumber=0, includeJobDocument=True): + payload = {_INCLUDE_JOB_DOCUMENT_KEY: includeJobDocument} + if executionNumber > 0: + payload[_EXEXCUTION_NUMBER_KEY] = executionNumber + if self._clientToken is not None: + payload[_CLIENT_TOKEN_KEY] = self._clientToken + return json.dumps(payload) + + def serializeStartNextPendingJobExecutionPayload(self, statusDetails=None, stepTimeoutInMinutes=None): + payload = {} + if self._clientToken is not None: + payload[_CLIENT_TOKEN_KEY] = self._clientToken + if statusDetails is not None: + payload[_STATUS_DETAILS_KEY] = statusDetails + if stepTimeoutInMinutes is not None: + payload[_STEP_TIMEOUT_IN_MINUTES_KEY] = stepTimeoutInMinutes + return json.dumps(payload) + + def serializeClientTokenPayload(self): + return json.dumps({_CLIENT_TOKEN_KEY: self._clientToken}) if self._clientToken is not None else '{}' diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/alpn.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/alpn.py new file mode 100644 index 0000000..8da98dd --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/alpn.py @@ -0,0 +1,63 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +try: + import ssl +except: + ssl = None + + +class SSLContextBuilder(object): + + def __init__(self): + self.check_supportability() + self._ssl_context = ssl.create_default_context() + + def check_supportability(self): + if ssl is None: + raise RuntimeError("This platform has no SSL/TLS.") + if not hasattr(ssl, "SSLContext"): + raise NotImplementedError("This platform does not support SSLContext. Python 2.7.10+/3.5+ is required.") + if not hasattr(ssl.SSLContext, "set_alpn_protocols"): + raise NotImplementedError("This platform does not support ALPN as TLS extensions. Python 2.7.10+/3.5+ is required.") + + def with_ca_certs(self, ca_certs): + self._ssl_context.load_verify_locations(ca_certs) + return self + + def with_cert_key_pair(self, cert_file, key_file): + self._ssl_context.load_cert_chain(cert_file, key_file) + return self + + def with_cert_reqs(self, cert_reqs): + self._ssl_context.verify_mode = cert_reqs + return self + + def with_check_hostname(self, check_hostname): + self._ssl_context.check_hostname = check_hostname + return self + + def with_ciphers(self, ciphers): + if ciphers is not None: + self._ssl_context.set_ciphers(ciphers) # set_ciphers() does not allow None input. Use default (do nothing) if None + return self + + def with_alpn_protocols(self, alpn_protocols): + self._ssl_context.set_alpn_protocols(alpn_protocols) + return self + + def build(self): + return self._ssl_context diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/cores.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/cores.py new file mode 100644 index 0000000..df12470 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/connection/cores.py @@ -0,0 +1,699 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +# This class implements the progressive backoff logic for auto-reconnect. +# It manages the reconnect wait time for the current reconnect, controling +# when to increase it and when to reset it. + + +import re +import sys +import ssl +import errno +import struct +import socket +import base64 +import time +import threading +import logging +import os +from datetime import datetime +import hashlib +import hmac +from AWSIoTPythonSDK.exception.AWSIoTExceptions import ClientError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssNoKeyInEnvironmentError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssHandShakeError +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC +try: + from urllib.parse import quote # Python 3+ +except ImportError: + from urllib import quote +# INI config file handling +try: + from configparser import ConfigParser # Python 3+ + from configparser import NoOptionError + from configparser import NoSectionError +except ImportError: + from ConfigParser import ConfigParser + from ConfigParser import NoOptionError + from ConfigParser import NoSectionError + + +class ProgressiveBackOffCore: + # Logger + _logger = logging.getLogger(__name__) + + def __init__(self, srcBaseReconnectTimeSecond=1, srcMaximumReconnectTimeSecond=32, srcMinimumConnectTimeSecond=20): + # The base reconnection time in seconds, default 1 + self._baseReconnectTimeSecond = srcBaseReconnectTimeSecond + # The maximum reconnection time in seconds, default 32 + self._maximumReconnectTimeSecond = srcMaximumReconnectTimeSecond + # The minimum time in milliseconds that a connection must be maintained in order to be considered stable + # Default 20 + self._minimumConnectTimeSecond = srcMinimumConnectTimeSecond + # Current backOff time in seconds, init to equal to 0 + self._currentBackoffTimeSecond = 1 + # Handler for timer + self._resetBackoffTimer = None + + # For custom progressiveBackoff timing configuration + def configTime(self, srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSecond, srcMinimumConnectTimeSecond): + if srcBaseReconnectTimeSecond < 0 or srcMaximumReconnectTimeSecond < 0 or srcMinimumConnectTimeSecond < 0: + self._logger.error("init: Negative time configuration detected.") + raise ValueError("Negative time configuration detected.") + if srcBaseReconnectTimeSecond >= srcMinimumConnectTimeSecond: + self._logger.error("init: Min connect time should be bigger than base reconnect time.") + raise ValueError("Min connect time should be bigger than base reconnect time.") + self._baseReconnectTimeSecond = srcBaseReconnectTimeSecond + self._maximumReconnectTimeSecond = srcMaximumReconnectTimeSecond + self._minimumConnectTimeSecond = srcMinimumConnectTimeSecond + self._currentBackoffTimeSecond = 1 + + # Block the reconnect logic for _currentBackoffTimeSecond + # Update the currentBackoffTimeSecond for the next reconnect + # Cancel the in-waiting timer for resetting backOff time + # This should get called only when a disconnect/reconnect happens + def backOff(self): + self._logger.debug("backOff: current backoff time is: " + str(self._currentBackoffTimeSecond) + " sec.") + if self._resetBackoffTimer is not None: + # Cancel the timer + self._resetBackoffTimer.cancel() + # Block the reconnect logic + time.sleep(self._currentBackoffTimeSecond) + # Update the backoff time + if self._currentBackoffTimeSecond == 0: + # This is the first attempt to connect, set it to base + self._currentBackoffTimeSecond = self._baseReconnectTimeSecond + else: + # r_cur = min(2^n*r_base, r_max) + self._currentBackoffTimeSecond = min(self._maximumReconnectTimeSecond, self._currentBackoffTimeSecond * 2) + + # Start the timer for resetting _currentBackoffTimeSecond + # Will be cancelled upon calling backOff + def startStableConnectionTimer(self): + self._resetBackoffTimer = threading.Timer(self._minimumConnectTimeSecond, + self._connectionStableThenResetBackoffTime) + self._resetBackoffTimer.start() + + def stopStableConnectionTimer(self): + if self._resetBackoffTimer is not None: + # Cancel the timer + self._resetBackoffTimer.cancel() + + # Timer callback to reset _currentBackoffTimeSecond + # If the connection is stable for longer than _minimumConnectTimeSecond, + # reset the currentBackoffTimeSecond to _baseReconnectTimeSecond + def _connectionStableThenResetBackoffTime(self): + self._logger.debug( + "stableConnection: Resetting the backoff time to: " + str(self._baseReconnectTimeSecond) + " sec.") + self._currentBackoffTimeSecond = self._baseReconnectTimeSecond + + +class SigV4Core: + + _logger = logging.getLogger(__name__) + + def __init__(self): + self._aws_access_key_id = "" + self._aws_secret_access_key = "" + self._aws_session_token = "" + self._credentialConfigFilePath = "~/.aws/credentials" + + def setIAMCredentials(self, srcAWSAccessKeyID, srcAWSSecretAccessKey, srcAWSSessionToken): + self._aws_access_key_id = srcAWSAccessKeyID + self._aws_secret_access_key = srcAWSSecretAccessKey + self._aws_session_token = srcAWSSessionToken + + def _createAmazonDate(self): + # Returned as a unicode string in Py3.x + amazonDate = [] + currentTime = datetime.utcnow() + YMDHMS = currentTime.strftime('%Y%m%dT%H%M%SZ') + YMD = YMDHMS[0:YMDHMS.index('T')] + amazonDate.append(YMD) + amazonDate.append(YMDHMS) + return amazonDate + + def _sign(self, key, message): + # Returned as a utf-8 byte string in Py3.x + return hmac.new(key, message.encode('utf-8'), hashlib.sha256).digest() + + def _getSignatureKey(self, key, dateStamp, regionName, serviceName): + # Returned as a utf-8 byte string in Py3.x + kDate = self._sign(('AWS4' + key).encode('utf-8'), dateStamp) + kRegion = self._sign(kDate, regionName) + kService = self._sign(kRegion, serviceName) + kSigning = self._sign(kService, 'aws4_request') + return kSigning + + def _checkIAMCredentials(self): + # Check custom config + ret = self._checkKeyInCustomConfig() + # Check environment variables + if not ret: + ret = self._checkKeyInEnv() + # Check files + if not ret: + ret = self._checkKeyInFiles() + # All credentials returned as unicode strings in Py3.x + return ret + + def _checkKeyInEnv(self): + ret = dict() + self._aws_access_key_id = os.environ.get('AWS_ACCESS_KEY_ID') + self._aws_secret_access_key = os.environ.get('AWS_SECRET_ACCESS_KEY') + self._aws_session_token = os.environ.get('AWS_SESSION_TOKEN') + if self._aws_access_key_id is not None and self._aws_secret_access_key is not None: + ret["aws_access_key_id"] = self._aws_access_key_id + ret["aws_secret_access_key"] = self._aws_secret_access_key + # We do not necessarily need session token... + if self._aws_session_token is not None: + ret["aws_session_token"] = self._aws_session_token + self._logger.debug("IAM credentials from env var.") + return ret + + def _checkKeyInINIDefault(self, srcConfigParser, sectionName): + ret = dict() + # Check aws_access_key_id and aws_secret_access_key + try: + ret["aws_access_key_id"] = srcConfigParser.get(sectionName, "aws_access_key_id") + ret["aws_secret_access_key"] = srcConfigParser.get(sectionName, "aws_secret_access_key") + except NoOptionError: + self._logger.warn("Cannot find IAM keyID/secretKey in credential file.") + # We do not continue searching if we cannot even get IAM id/secret right + if len(ret) == 2: + # Check aws_session_token, optional + try: + ret["aws_session_token"] = srcConfigParser.get(sectionName, "aws_session_token") + except NoOptionError: + self._logger.debug("No AWS Session Token found.") + return ret + + def _checkKeyInFiles(self): + credentialFile = None + credentialConfig = None + ret = dict() + # Should be compatible with aws cli default credential configuration + # *NIX/Windows + try: + # See if we get the file + credentialConfig = ConfigParser() + credentialFilePath = os.path.expanduser(self._credentialConfigFilePath) # Is it compatible with windows? \/ + credentialConfig.read(credentialFilePath) + # Now we have the file, start looking for credentials... + # 'default' section + ret = self._checkKeyInINIDefault(credentialConfig, "default") + if not ret: + # 'DEFAULT' section + ret = self._checkKeyInINIDefault(credentialConfig, "DEFAULT") + self._logger.debug("IAM credentials from file.") + except IOError: + self._logger.debug("No IAM credential configuration file in " + credentialFilePath) + except NoSectionError: + self._logger.error("Cannot find IAM 'default' section.") + return ret + + def _checkKeyInCustomConfig(self): + ret = dict() + if self._aws_access_key_id != "" and self._aws_secret_access_key != "": + ret["aws_access_key_id"] = self._aws_access_key_id + ret["aws_secret_access_key"] = self._aws_secret_access_key + # We do not necessarily need session token... + if self._aws_session_token != "": + ret["aws_session_token"] = self._aws_session_token + self._logger.debug("IAM credentials from custom config.") + return ret + + def createWebsocketEndpoint(self, host, port, region, method, awsServiceName, path): + # Return the endpoint as unicode string in 3.x + # Gather all the facts + amazonDate = self._createAmazonDate() + amazonDateSimple = amazonDate[0] # Unicode in 3.x + amazonDateComplex = amazonDate[1] # Unicode in 3.x + allKeys = self._checkIAMCredentials() # Unicode in 3.x + if not self._hasCredentialsNecessaryForWebsocket(allKeys): + raise wssNoKeyInEnvironmentError() + else: + # Because of self._hasCredentialsNecessaryForWebsocket(...), keyID and secretKey should not be None from here + keyID = allKeys["aws_access_key_id"] + secretKey = allKeys["aws_secret_access_key"] + # amazonDateSimple and amazonDateComplex are guaranteed not to be None + queryParameters = "X-Amz-Algorithm=AWS4-HMAC-SHA256" + \ + "&X-Amz-Credential=" + keyID + "%2F" + amazonDateSimple + "%2F" + region + "%2F" + awsServiceName + "%2Faws4_request" + \ + "&X-Amz-Date=" + amazonDateComplex + \ + "&X-Amz-Expires=86400" + \ + "&X-Amz-SignedHeaders=host" # Unicode in 3.x + hashedPayload = hashlib.sha256(str("").encode('utf-8')).hexdigest() # Unicode in 3.x + # Create the string to sign + signedHeaders = "host" + canonicalHeaders = "host:" + host + "\n" + canonicalRequest = method + "\n" + path + "\n" + queryParameters + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedPayload # Unicode in 3.x + hashedCanonicalRequest = hashlib.sha256(str(canonicalRequest).encode('utf-8')).hexdigest() # Unicoede in 3.x + stringToSign = "AWS4-HMAC-SHA256\n" + amazonDateComplex + "\n" + amazonDateSimple + "/" + region + "/" + awsServiceName + "/aws4_request\n" + hashedCanonicalRequest # Unicode in 3.x + # Sign it + signingKey = self._getSignatureKey(secretKey, amazonDateSimple, region, awsServiceName) + signature = hmac.new(signingKey, (stringToSign).encode("utf-8"), hashlib.sha256).hexdigest() + # generate url + url = "wss://" + host + ":" + str(port) + path + '?' + queryParameters + "&X-Amz-Signature=" + signature + # See if we have STS token, if we do, add it + awsSessionTokenCandidate = allKeys.get("aws_session_token") + if awsSessionTokenCandidate is not None and len(awsSessionTokenCandidate) != 0: + aws_session_token = allKeys["aws_session_token"] + url += "&X-Amz-Security-Token=" + quote(aws_session_token.encode("utf-8")) # Unicode in 3.x + self._logger.debug("createWebsocketEndpoint: Websocket URL: " + url) + return url + + def _hasCredentialsNecessaryForWebsocket(self, allKeys): + awsAccessKeyIdCandidate = allKeys.get("aws_access_key_id") + awsSecretAccessKeyCandidate = allKeys.get("aws_secret_access_key") + # None value is NOT considered as valid entries + validEntries = awsAccessKeyIdCandidate is not None and awsAccessKeyIdCandidate is not None + if validEntries: + # Empty value is NOT considered as valid entries + validEntries &= (len(awsAccessKeyIdCandidate) != 0 and len(awsSecretAccessKeyCandidate) != 0) + return validEntries + + +# This is an internal class that buffers the incoming bytes into an +# internal buffer until it gets the full desired length of bytes. +# At that time, this bufferedReader will be reset. +# *Error handling: +# For retry errors (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE, EAGAIN), +# leave them to the paho _packet_read for further handling (ignored and try +# again when data is available. +# For other errors, leave them to the paho _packet_read for error reporting. + + +class _BufferedReader: + _sslSocket = None + _internalBuffer = None + _remainedLength = -1 + _bufferingInProgress = False + + def __init__(self, sslSocket): + self._sslSocket = sslSocket + self._internalBuffer = bytearray() + self._bufferingInProgress = False + + def _reset(self): + self._internalBuffer = bytearray() + self._remainedLength = -1 + self._bufferingInProgress = False + + def read(self, numberOfBytesToBeBuffered): + if not self._bufferingInProgress: # If last read is completed... + self._remainedLength = numberOfBytesToBeBuffered + self._bufferingInProgress = True # Now we start buffering a new length of bytes + + while self._remainedLength > 0: # Read in a loop, always try to read in the remained length + # If the data is temporarily not available, socket.error will be raised and catched by paho + dataChunk = self._sslSocket.read(self._remainedLength) + # There is a chance where the server terminates the connection without closing the socket. + # If that happens, let's raise an exception and enter the reconnect flow. + if not dataChunk: + raise socket.error(errno.ECONNABORTED, 0) + self._internalBuffer.extend(dataChunk) # Buffer the data + self._remainedLength -= len(dataChunk) # Update the remained length + + # The requested length of bytes is buffered, recover the context and return it + # Otherwise error should be raised + ret = self._internalBuffer + self._reset() + return ret # This should always be bytearray + + +# This is the internal class that sends requested data out chunk by chunk according +# to the availablity of the socket write operation. If the requested bytes of data +# (after encoding) needs to be sent out in separate socket write operations (most +# probably be interrupted by the error socket.error (errno = ssl.SSL_ERROR_WANT_WRITE).) +# , the write pointer is stored to ensure that the continued bytes will be sent next +# time this function gets called. +# *Error handling: +# For retry errors (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE, EAGAIN), +# leave them to the paho _packet_read for further handling (ignored and try +# again when data is available. +# For other errors, leave them to the paho _packet_read for error reporting. + + +class _BufferedWriter: + _sslSocket = None + _internalBuffer = None + _writingInProgress = False + _requestedDataLength = -1 + + def __init__(self, sslSocket): + self._sslSocket = sslSocket + self._internalBuffer = bytearray() + self._writingInProgress = False + self._requestedDataLength = -1 + + def _reset(self): + self._internalBuffer = bytearray() + self._writingInProgress = False + self._requestedDataLength = -1 + + # Input data for this function needs to be an encoded wss frame + # Always request for packet[pos=0:] (raw MQTT data) + def write(self, encodedData, payloadLength): + # encodedData should always be bytearray + # Check if we have a frame that is partially sent + if not self._writingInProgress: + self._internalBuffer = encodedData + self._writingInProgress = True + self._requestedDataLength = payloadLength + # Now, write as much as we can + lengthWritten = self._sslSocket.write(self._internalBuffer) + self._internalBuffer = self._internalBuffer[lengthWritten:] + # This MQTT packet has been sent out in a wss frame, completely + if len(self._internalBuffer) == 0: + ret = self._requestedDataLength + self._reset() + return ret + # This socket write is half-baked... + else: + return 0 # Ensure that the 'pos' inside the MQTT packet never moves since we have not finished the transmission of this encoded frame + + +class SecuredWebSocketCore: + # Websocket Constants + _OP_CONTINUATION = 0x0 + _OP_TEXT = 0x1 + _OP_BINARY = 0x2 + _OP_CONNECTION_CLOSE = 0x8 + _OP_PING = 0x9 + _OP_PONG = 0xa + # Websocket Connect Status + _WebsocketConnectInit = -1 + _WebsocketDisconnected = 1 + + _logger = logging.getLogger(__name__) + + def __init__(self, socket, hostAddress, portNumber, AWSAccessKeyID="", AWSSecretAccessKey="", AWSSessionToken=""): + self._connectStatus = self._WebsocketConnectInit + # Handlers + self._sslSocket = socket + self._sigV4Handler = self._createSigV4Core() + self._sigV4Handler.setIAMCredentials(AWSAccessKeyID, AWSSecretAccessKey, AWSSessionToken) + # Endpoint Info + self._hostAddress = hostAddress + self._portNumber = portNumber + # Section Flags + self._hasOpByte = False + self._hasPayloadLengthFirst = False + self._hasPayloadLengthExtended = False + self._hasMaskKey = False + self._hasPayload = False + # Properties for current websocket frame + self._isFIN = False + self._RSVBits = None + self._opCode = None + self._needMaskKey = False + self._payloadLengthBytesLength = 1 + self._payloadLength = 0 + self._maskKey = None + self._payloadDataBuffer = bytearray() # Once the whole wss connection is lost, there is no need to keep the buffered payload + try: + self._handShake(hostAddress, portNumber) + except wssNoKeyInEnvironmentError: # Handle SigV4 signing and websocket handshaking errors + raise ValueError("No Access Key/KeyID Error") + except wssHandShakeError: + raise ValueError("Websocket Handshake Error") + except ClientError as e: + raise ValueError(e.message) + # Now we have a socket with secured websocket... + self._bufferedReader = _BufferedReader(self._sslSocket) + self._bufferedWriter = _BufferedWriter(self._sslSocket) + + def _createSigV4Core(self): + return SigV4Core() + + def _generateMaskKey(self): + return bytearray(os.urandom(4)) + # os.urandom returns ascii str in 2.x, converted to bytearray + # os.urandom returns bytes in 3.x, converted to bytearray + + def _reset(self): # Reset the context for wss frame reception + # Control info + self._hasOpByte = False + self._hasPayloadLengthFirst = False + self._hasPayloadLengthExtended = False + self._hasMaskKey = False + self._hasPayload = False + # Frame Info + self._isFIN = False + self._RSVBits = None + self._opCode = None + self._needMaskKey = False + self._payloadLengthBytesLength = 1 + self._payloadLength = 0 + self._maskKey = None + # Never reset the payloadData since we might have fragmented MQTT data from the pervious frame + + def _generateWSSKey(self): + return base64.b64encode(os.urandom(128)) # Bytes + + def _verifyWSSResponse(self, response, clientKey): + # Check if it is a 101 response + rawResponse = response.strip().lower() + if b"101 switching protocols" not in rawResponse or b"upgrade: websocket" not in rawResponse or b"connection: upgrade" not in rawResponse: + return False + # Parse out the sec-websocket-accept + WSSAcceptKeyIndex = response.strip().index(b"sec-websocket-accept: ") + len(b"sec-websocket-accept: ") + rawSecWebSocketAccept = response.strip()[WSSAcceptKeyIndex:].split(b"\r\n")[0].strip() + # Verify the WSSAcceptKey + return self._verifyWSSAcceptKey(rawSecWebSocketAccept, clientKey) + + def _verifyWSSAcceptKey(self, srcAcceptKey, clientKey): + GUID = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + verifyServerAcceptKey = base64.b64encode((hashlib.sha1(clientKey + GUID)).digest()) # Bytes + return srcAcceptKey == verifyServerAcceptKey + + def _handShake(self, hostAddress, portNumber): + CRLF = "\r\n" + IOT_ENDPOINT_PATTERN = r"^[0-9a-zA-Z]+(\.ats|-ats)?\.iot\.(.*)\.amazonaws\..*" + matched = re.compile(IOT_ENDPOINT_PATTERN, re.IGNORECASE).match(hostAddress) + if not matched: + raise ClientError("Invalid endpoint pattern for wss: %s" % hostAddress) + region = matched.group(2) + signedURL = self._sigV4Handler.createWebsocketEndpoint(hostAddress, portNumber, region, "GET", "iotdata", "/mqtt") + # Now we got a signedURL + path = signedURL[signedURL.index("/mqtt"):] + # Assemble HTTP request headers + Method = "GET " + path + " HTTP/1.1" + CRLF + Host = "Host: " + hostAddress + CRLF + Connection = "Connection: " + "Upgrade" + CRLF + Upgrade = "Upgrade: " + "websocket" + CRLF + secWebSocketVersion = "Sec-WebSocket-Version: " + "13" + CRLF + rawSecWebSocketKey = self._generateWSSKey() # Bytes + secWebSocketKey = "sec-websocket-key: " + rawSecWebSocketKey.decode('utf-8') + CRLF # Should be randomly generated... + secWebSocketProtocol = "Sec-WebSocket-Protocol: " + "mqttv3.1" + CRLF + secWebSocketExtensions = "Sec-WebSocket-Extensions: " + "permessage-deflate; client_max_window_bits" + CRLF + # Send the HTTP request + # Ensure that we are sending bytes, not by any chance unicode string + handshakeBytes = Method + Host + Connection + Upgrade + secWebSocketVersion + secWebSocketProtocol + secWebSocketExtensions + secWebSocketKey + CRLF + handshakeBytes = handshakeBytes.encode('utf-8') + self._sslSocket.write(handshakeBytes) + # Read it back (Non-blocking socket) + timeStart = time.time() + wssHandshakeResponse = bytearray() + while len(wssHandshakeResponse) == 0: + try: + wssHandshakeResponse += self._sslSocket.read(1024) # Response is always less than 1024 bytes + except socket.error as err: + if err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE: + if time.time() - timeStart > self._getTimeoutSec(): + raise err # We make sure that reconnect gets retried in Paho upon a wss reconnect response timeout + else: + raise err + # Verify response + # Now both wssHandshakeResponse and rawSecWebSocketKey are byte strings + if not self._verifyWSSResponse(wssHandshakeResponse, rawSecWebSocketKey): + raise wssHandShakeError() + else: + pass + + def _getTimeoutSec(self): + return DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC + + # Used to create a single wss frame + # Assume that the maximum length of a MQTT packet never exceeds the maximum length + # for a wss frame. Therefore, the FIN bit for the encoded frame will always be 1. + # Frames are encoded as BINARY frames. + def _encodeFrame(self, rawPayload, opCode, masked=1): + ret = bytearray() + # Op byte + opByte = 0x80 | opCode # Always a FIN, no RSV bits + ret.append(opByte) + # Payload Length bytes + maskBit = masked + payloadLength = len(rawPayload) + if payloadLength <= 125: + ret.append((maskBit << 7) | payloadLength) + elif payloadLength <= 0xffff: # 16-bit unsigned int + ret.append((maskBit << 7) | 126) + ret.extend(struct.pack("!H", payloadLength)) + elif payloadLength <= 0x7fffffffffffffff: # 64-bit unsigned int (most significant bit must be 0) + ret.append((maskBit << 7) | 127) + ret.extend(struct.pack("!Q", payloadLength)) + else: # Overflow + raise ValueError("Exceeds the maximum number of bytes for a single websocket frame.") + if maskBit == 1: + # Mask key bytes + maskKey = self._generateMaskKey() + ret.extend(maskKey) + # Mask the payload + payloadBytes = bytearray(rawPayload) + if maskBit == 1: + for i in range(0, payloadLength): + payloadBytes[i] ^= maskKey[i % 4] + ret.extend(payloadBytes) + # Return the assembled wss frame + return ret + + # Used for the wss client to close a wss connection + # Create and send a masked wss closing frame + def _closeWssConnection(self): + # Frames sent from client to server must be masked + self._sslSocket.write(self._encodeFrame(b"", self._OP_CONNECTION_CLOSE, masked=1)) + + # Used for the wss client to respond to a wss PING from server + # Create and send a masked PONG frame + def _sendPONG(self): + # Frames sent from client to server must be masked + self._sslSocket.write(self._encodeFrame(b"", self._OP_PONG, masked=1)) + + # Override sslSocket read. Always read from the wss internal payload buffer, which + # contains the masked MQTT packet. This read will decode ONE wss frame every time + # and load in the payload for MQTT _packet_read. At any time, MQTT _packet_read + # should be able to read a complete MQTT packet from the payload (buffered per wss + # frame payload). If the MQTT packet is break into separate wss frames, different + # chunks will be buffered in separate frames and MQTT _packet_read will not be able + # to collect a complete MQTT packet to operate on until the necessary payload is + # fully buffered. + # If the requested number of bytes are not available, SSL_ERROR_WANT_READ will be + # raised to trigger another call of _packet_read when the data is available again. + def read(self, numberOfBytes): + # Check if we have enough data for paho + # _payloadDataBuffer will not be empty ony when the payload of a new wss frame + # has been unmasked. + if len(self._payloadDataBuffer) >= numberOfBytes: + ret = self._payloadDataBuffer[0:numberOfBytes] + self._payloadDataBuffer = self._payloadDataBuffer[numberOfBytes:] + # struct.unpack(fmt, string) # Py2.x + # struct.unpack(fmt, buffer) # Py3.x + # Here ret is always in bytes (buffer interface) + if sys.version_info[0] < 3: # Py2.x + ret = str(ret) + return ret + # Emmm, We don't. Try to buffer from the socket (It's a new wss frame). + if not self._hasOpByte: # Check if we need to buffer OpByte + opByte = self._bufferedReader.read(1) + self._isFIN = (opByte[0] & 0x80) == 0x80 + self._RSVBits = (opByte[0] & 0x70) + self._opCode = (opByte[0] & 0x0f) + self._hasOpByte = True # Finished buffering opByte + # Check if any of the RSV bits are set, if so, close the connection + # since client never sends negotiated extensions + if self._RSVBits != 0x0: + self._closeWssConnection() + self._connectStatus = self._WebsocketDisconnected + self._payloadDataBuffer = bytearray() + raise socket.error(ssl.SSL_ERROR_WANT_READ, "RSV bits set with NO negotiated extensions.") + if not self._hasPayloadLengthFirst: # Check if we need to buffer First Payload Length byte + payloadLengthFirst = self._bufferedReader.read(1) + self._hasPayloadLengthFirst = True # Finished buffering first byte of payload length + self._needMaskKey = (payloadLengthFirst[0] & 0x80) == 0x80 + payloadLengthFirstByteArray = bytearray() + payloadLengthFirstByteArray.extend(payloadLengthFirst) + self._payloadLength = (payloadLengthFirstByteArray[0] & 0x7f) + + if self._payloadLength == 126: + self._payloadLengthBytesLength = 2 + self._hasPayloadLengthExtended = False # Force to buffer the extended + elif self._payloadLength == 127: + self._payloadLengthBytesLength = 8 + self._hasPayloadLengthExtended = False # Force to buffer the extended + else: # _payloadLength <= 125: + self._hasPayloadLengthExtended = True # No need to buffer extended payload length + if not self._hasPayloadLengthExtended: # Check if we need to buffer Extended Payload Length bytes + payloadLengthExtended = self._bufferedReader.read(self._payloadLengthBytesLength) + self._hasPayloadLengthExtended = True + if sys.version_info[0] < 3: + payloadLengthExtended = str(payloadLengthExtended) + if self._payloadLengthBytesLength == 2: + self._payloadLength = struct.unpack("!H", payloadLengthExtended)[0] + else: # _payloadLengthBytesLength == 8 + self._payloadLength = struct.unpack("!Q", payloadLengthExtended)[0] + + if self._needMaskKey: # Response from server is masked, close the connection + self._closeWssConnection() + self._connectStatus = self._WebsocketDisconnected + self._payloadDataBuffer = bytearray() + raise socket.error(ssl.SSL_ERROR_WANT_READ, "Server response masked, closing connection and try again.") + + if not self._hasPayload: # Check if we need to buffer the payload + payloadForThisFrame = self._bufferedReader.read(self._payloadLength) + self._hasPayload = True + # Client side should never received a masked packet from the server side + # Unmask it as needed + #if self._needMaskKey: + # for i in range(0, self._payloadLength): + # payloadForThisFrame[i] ^= self._maskKey[i % 4] + # Append it to the internal payload buffer + self._payloadDataBuffer.extend(payloadForThisFrame) + # Now we have the complete wss frame, reset the context + # Check to see if it is a wss closing frame + if self._opCode == self._OP_CONNECTION_CLOSE: + self._connectStatus = self._WebsocketDisconnected + self._payloadDataBuffer = bytearray() # Ensure that once the wss closing frame comes, we have nothing to read and start all over again + # Check to see if it is a wss PING frame + if self._opCode == self._OP_PING: + self._sendPONG() # Nothing more to do here, if the transmission of the last wssMQTT packet is not finished, it will continue + self._reset() + # Check again if we have enough data for paho + if len(self._payloadDataBuffer) >= numberOfBytes: + ret = self._payloadDataBuffer[0:numberOfBytes] + self._payloadDataBuffer = self._payloadDataBuffer[numberOfBytes:] + # struct.unpack(fmt, string) # Py2.x + # struct.unpack(fmt, buffer) # Py3.x + # Here ret is always in bytes (buffer interface) + if sys.version_info[0] < 3: # Py2.x + ret = str(ret) + return ret + else: # Fragmented MQTT packets in separate wss frames + raise socket.error(ssl.SSL_ERROR_WANT_READ, "Not a complete MQTT packet payload within this wss frame.") + + def write(self, bytesToBeSent): + # When there is a disconnection, select will report a TypeError which triggers the reconnect. + # In reconnect, Paho will set the socket object (mocked by wss) to None, blocking other ops + # before a connection is re-established. + # This 'low-level' socket write op should always be able to write to plain socket. + # Error reporting is performed by Python socket itself. + # Wss closing frame handling is performed in the wss read. + return self._bufferedWriter.write(self._encodeFrame(bytesToBeSent, self._OP_BINARY, 1), len(bytesToBeSent)) + + def close(self): + if self._sslSocket is not None: + self._sslSocket.close() + self._sslSocket = None + + def getpeercert(self): + return self._sslSocket.getpeercert() + + def getSSLSocket(self): + if self._connectStatus != self._WebsocketDisconnected: + return self._sslSocket + else: + return None # Leave the sslSocket to Paho to close it. (_ssl.close() -> wssCore.close()) diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/clients.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/clients.py new file mode 100644 index 0000000..bb670f7 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/clients.py @@ -0,0 +1,244 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import ssl +import logging +from threading import Lock +from numbers import Number +import AWSIoTPythonSDK.core.protocol.paho.client as mqtt +from AWSIoTPythonSDK.core.protocol.paho.client import MQTT_ERR_SUCCESS +from AWSIoTPythonSDK.core.protocol.internal.events import FixedEventMids + + +class ClientStatus(object): + + IDLE = 0 + CONNECT = 1 + RESUBSCRIBE = 2 + DRAINING = 3 + STABLE = 4 + USER_DISCONNECT = 5 + ABNORMAL_DISCONNECT = 6 + + +class ClientStatusContainer(object): + + def __init__(self): + self._status = ClientStatus.IDLE + + def get_status(self): + return self._status + + def set_status(self, status): + if ClientStatus.USER_DISCONNECT == self._status: # If user requests to disconnect, no status updates other than user connect + if ClientStatus.CONNECT == status: + self._status = status + else: + self._status = status + + +class InternalAsyncMqttClient(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, client_id, clean_session, protocol, use_wss): + self._paho_client = self._create_paho_client(client_id, clean_session, None, protocol, use_wss) + self._use_wss = use_wss + self._event_callback_map_lock = Lock() + self._event_callback_map = dict() + + def _create_paho_client(self, client_id, clean_session, user_data, protocol, use_wss): + self._logger.debug("Initializing MQTT layer...") + return mqtt.Client(client_id, clean_session, user_data, protocol, use_wss) + + # TODO: Merge credentials providers configuration into one + def set_cert_credentials_provider(self, cert_credentials_provider): + # History issue from Yun SDK where AR9331 embedded Linux only have Python 2.7.3 + # pre-installed. In this version, TLSv1_2 is not even an option. + # SSLv23 is a work-around which selects the highest TLS version between the client + # and service. If user installs opensslv1.0.1+, this option will work fine for Mutual + # Auth. + # Note that we cannot force TLSv1.2 for Mutual Auth. in Python 2.7.3 and TLS support + # in Python only starts from Python2.7. + # See also: https://docs.python.org/2/library/ssl.html#ssl.PROTOCOL_SSLv23 + if self._use_wss: + ca_path = cert_credentials_provider.get_ca_path() + self._paho_client.tls_set(ca_certs=ca_path, cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_SSLv23) + else: + ca_path = cert_credentials_provider.get_ca_path() + cert_path = cert_credentials_provider.get_cert_path() + key_path = cert_credentials_provider.get_key_path() + self._paho_client.tls_set(ca_certs=ca_path,certfile=cert_path, keyfile=key_path, + cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_SSLv23) + + def set_iam_credentials_provider(self, iam_credentials_provider): + self._paho_client.configIAMCredentials(iam_credentials_provider.get_access_key_id(), + iam_credentials_provider.get_secret_access_key(), + iam_credentials_provider.get_session_token()) + + def set_endpoint_provider(self, endpoint_provider): + self._endpoint_provider = endpoint_provider + + def configure_last_will(self, topic, payload, qos, retain=False): + self._paho_client.will_set(topic, payload, qos, retain) + + def configure_alpn_protocols(self, alpn_protocols): + self._paho_client.config_alpn_protocols(alpn_protocols) + + def clear_last_will(self): + self._paho_client.will_clear() + + def set_username_password(self, username, password=None): + self._paho_client.username_pw_set(username, password) + + def set_socket_factory(self, socket_factory): + self._paho_client.socket_factory_set(socket_factory) + + def configure_reconnect_back_off(self, base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec): + self._paho_client.setBackoffTiming(base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec) + + def connect(self, keep_alive_sec, ack_callback=None): + host = self._endpoint_provider.get_host() + port = self._endpoint_provider.get_port() + + with self._event_callback_map_lock: + self._logger.debug("Filling in fixed event callbacks: CONNACK, DISCONNECT, MESSAGE") + self._event_callback_map[FixedEventMids.CONNACK_MID] = self._create_combined_on_connect_callback(ack_callback) + self._event_callback_map[FixedEventMids.DISCONNECT_MID] = self._create_combined_on_disconnect_callback(None) + self._event_callback_map[FixedEventMids.MESSAGE_MID] = self._create_converted_on_message_callback() + + rc = self._paho_client.connect(host, port, keep_alive_sec) + if MQTT_ERR_SUCCESS == rc: + self.start_background_network_io() + + return rc + + def start_background_network_io(self): + self._logger.debug("Starting network I/O thread...") + self._paho_client.loop_start() + + def stop_background_network_io(self): + self._logger.debug("Stopping network I/O thread...") + self._paho_client.loop_stop() + + def disconnect(self, ack_callback=None): + with self._event_callback_map_lock: + rc = self._paho_client.disconnect() + if MQTT_ERR_SUCCESS == rc: + self._logger.debug("Filling in custom disconnect event callback...") + combined_on_disconnect_callback = self._create_combined_on_disconnect_callback(ack_callback) + self._event_callback_map[FixedEventMids.DISCONNECT_MID] = combined_on_disconnect_callback + return rc + + def _create_combined_on_connect_callback(self, ack_callback): + def combined_on_connect_callback(mid, data): + self.on_online() + if ack_callback: + ack_callback(mid, data) + return combined_on_connect_callback + + def _create_combined_on_disconnect_callback(self, ack_callback): + def combined_on_disconnect_callback(mid, data): + self.on_offline() + if ack_callback: + ack_callback(mid, data) + return combined_on_disconnect_callback + + def _create_converted_on_message_callback(self): + def converted_on_message_callback(mid, data): + self.on_message(data) + return converted_on_message_callback + + # For client online notification + def on_online(self): + pass + + # For client offline notification + def on_offline(self): + pass + + # For client message reception notification + def on_message(self, message): + pass + + def publish(self, topic, payload, qos, retain=False, ack_callback=None): + with self._event_callback_map_lock: + rc, mid = self._paho_client.publish(topic, payload, qos, retain) + if MQTT_ERR_SUCCESS == rc and qos > 0 and ack_callback: + self._logger.debug("Filling in custom puback (QoS>0) event callback...") + self._event_callback_map[mid] = ack_callback + return rc, mid + + def subscribe(self, topic, qos, ack_callback=None): + with self._event_callback_map_lock: + rc, mid = self._paho_client.subscribe(topic, qos) + if MQTT_ERR_SUCCESS == rc and ack_callback: + self._logger.debug("Filling in custom suback event callback...") + self._event_callback_map[mid] = ack_callback + return rc, mid + + def unsubscribe(self, topic, ack_callback=None): + with self._event_callback_map_lock: + rc, mid = self._paho_client.unsubscribe(topic) + if MQTT_ERR_SUCCESS == rc and ack_callback: + self._logger.debug("Filling in custom unsuback event callback...") + self._event_callback_map[mid] = ack_callback + return rc, mid + + def register_internal_event_callbacks(self, on_connect, on_disconnect, on_publish, on_subscribe, on_unsubscribe, on_message): + self._logger.debug("Registering internal event callbacks to MQTT layer...") + self._paho_client.on_connect = on_connect + self._paho_client.on_disconnect = on_disconnect + self._paho_client.on_publish = on_publish + self._paho_client.on_subscribe = on_subscribe + self._paho_client.on_unsubscribe = on_unsubscribe + self._paho_client.on_message = on_message + + def unregister_internal_event_callbacks(self): + self._logger.debug("Unregistering internal event callbacks from MQTT layer...") + self._paho_client.on_connect = None + self._paho_client.on_disconnect = None + self._paho_client.on_publish = None + self._paho_client.on_subscribe = None + self._paho_client.on_unsubscribe = None + self._paho_client.on_message = None + + def invoke_event_callback(self, mid, data=None): + with self._event_callback_map_lock: + event_callback = self._event_callback_map.get(mid) + # For invoking the event callback, we do not need to acquire the lock + if event_callback: + self._logger.debug("Invoking custom event callback...") + if data is not None: + event_callback(mid=mid, data=data) + else: + event_callback(mid=mid) + if isinstance(mid, Number): # Do NOT remove callbacks for CONNACK/DISCONNECT/MESSAGE + self._logger.debug("This custom event callback is for pub/sub/unsub, removing it after invocation...") + with self._event_callback_map_lock: + del self._event_callback_map[mid] + + def remove_event_callback(self, mid): + with self._event_callback_map_lock: + if mid in self._event_callback_map: + self._logger.debug("Removing custom event callback...") + del self._event_callback_map[mid] + + def clean_up_event_callbacks(self): + with self._event_callback_map_lock: + self._event_callback_map.clear() + + def get_event_callback_map(self): + return self._event_callback_map diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/defaults.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/defaults.py new file mode 100644 index 0000000..66817d3 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/defaults.py @@ -0,0 +1,20 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC = 30 +DEFAULT_OPERATION_TIMEOUT_SEC = 5 +DEFAULT_DRAINING_INTERNAL_SEC = 0.5 +METRICS_PREFIX = "?SDK=Python&Version=" +ALPN_PROTCOLS = "x-amzn-mqtt-ca" \ No newline at end of file diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/events.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/events.py new file mode 100644 index 0000000..90f0b70 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/events.py @@ -0,0 +1,29 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +class EventTypes(object): + CONNACK = 0 + DISCONNECT = 1 + PUBACK = 2 + SUBACK = 3 + UNSUBACK = 4 + MESSAGE = 5 + + +class FixedEventMids(object): + CONNACK_MID = "CONNECTED" + DISCONNECT_MID = "DISCONNECTED" + MESSAGE_MID = "MESSAGE" + QUEUED_MID = "QUEUED" diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/queues.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/queues.py new file mode 100644 index 0000000..77046a8 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/queues.py @@ -0,0 +1,87 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import logging +from AWSIoTPythonSDK.core.util.enums import DropBehaviorTypes + + +class AppendResults(object): + APPEND_FAILURE_QUEUE_FULL = -1 + APPEND_FAILURE_QUEUE_DISABLED = -2 + APPEND_SUCCESS = 0 + + +class OfflineRequestQueue(list): + _logger = logging.getLogger(__name__) + + def __init__(self, max_size, drop_behavior=DropBehaviorTypes.DROP_NEWEST): + if not isinstance(max_size, int) or not isinstance(drop_behavior, int): + self._logger.error("init: MaximumSize/DropBehavior must be integer.") + raise TypeError("MaximumSize/DropBehavior must be integer.") + if drop_behavior != DropBehaviorTypes.DROP_OLDEST and drop_behavior != DropBehaviorTypes.DROP_NEWEST: + self._logger.error("init: Drop behavior not supported.") + raise ValueError("Drop behavior not supported.") + + list.__init__([]) + self._drop_behavior = drop_behavior + # When self._maximumSize > 0, queue is limited + # When self._maximumSize == 0, queue is disabled + # When self._maximumSize < 0. queue is infinite + self._max_size = max_size + + def _is_enabled(self): + return self._max_size != 0 + + def _need_drop_messages(self): + # Need to drop messages when: + # 1. Queue is limited and full + # 2. Queue is disabled + is_queue_full = len(self) >= self._max_size + is_queue_limited = self._max_size > 0 + is_queue_disabled = not self._is_enabled() + return (is_queue_full and is_queue_limited) or is_queue_disabled + + def set_behavior_drop_newest(self): + self._drop_behavior = DropBehaviorTypes.DROP_NEWEST + + def set_behavior_drop_oldest(self): + self._drop_behavior = DropBehaviorTypes.DROP_OLDEST + + # Override + # Append to a queue with a limited size. + # Return APPEND_SUCCESS if the append is successful + # Return APPEND_FAILURE_QUEUE_FULL if the append failed because the queue is full + # Return APPEND_FAILURE_QUEUE_DISABLED if the append failed because the queue is disabled + def append(self, data): + ret = AppendResults.APPEND_SUCCESS + if self._is_enabled(): + if self._need_drop_messages(): + # We should drop the newest + if DropBehaviorTypes.DROP_NEWEST == self._drop_behavior: + self._logger.warn("append: Full queue. Drop the newest: " + str(data)) + ret = AppendResults.APPEND_FAILURE_QUEUE_FULL + # We should drop the oldest + else: + current_oldest = super(OfflineRequestQueue, self).pop(0) + self._logger.warn("append: Full queue. Drop the oldest: " + str(current_oldest)) + super(OfflineRequestQueue, self).append(data) + ret = AppendResults.APPEND_FAILURE_QUEUE_FULL + else: + self._logger.debug("append: Add new element: " + str(data)) + super(OfflineRequestQueue, self).append(data) + else: + self._logger.debug("append: Queue is disabled. Drop the message: " + str(data)) + ret = AppendResults.APPEND_FAILURE_QUEUE_DISABLED + return ret diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/requests.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/requests.py new file mode 100644 index 0000000..bd2585d --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/requests.py @@ -0,0 +1,27 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +class RequestTypes(object): + CONNECT = 0 + DISCONNECT = 1 + PUBLISH = 2 + SUBSCRIBE = 3 + UNSUBSCRIBE = 4 + +class QueueableRequest(object): + + def __init__(self, type, data): + self.type = type + self.data = data # Can be a tuple diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/workers.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/workers.py new file mode 100644 index 0000000..e52db3f --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/internal/workers.py @@ -0,0 +1,296 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import time +import logging +from threading import Thread +from threading import Event +from AWSIoTPythonSDK.core.protocol.internal.events import EventTypes +from AWSIoTPythonSDK.core.protocol.internal.events import FixedEventMids +from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatus +from AWSIoTPythonSDK.core.protocol.internal.queues import OfflineRequestQueue +from AWSIoTPythonSDK.core.protocol.internal.requests import RequestTypes +from AWSIoTPythonSDK.core.protocol.paho.client import topic_matches_sub +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_DRAINING_INTERNAL_SEC + + +class EventProducer(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, cv, event_queue): + self._cv = cv + self._event_queue = event_queue + + def on_connect(self, client, user_data, flags, rc): + self._add_to_queue(FixedEventMids.CONNACK_MID, EventTypes.CONNACK, rc) + self._logger.debug("Produced [connack] event") + + def on_disconnect(self, client, user_data, rc): + self._add_to_queue(FixedEventMids.DISCONNECT_MID, EventTypes.DISCONNECT, rc) + self._logger.debug("Produced [disconnect] event") + + def on_publish(self, client, user_data, mid): + self._add_to_queue(mid, EventTypes.PUBACK, None) + self._logger.debug("Produced [puback] event") + + def on_subscribe(self, client, user_data, mid, granted_qos): + self._add_to_queue(mid, EventTypes.SUBACK, granted_qos) + self._logger.debug("Produced [suback] event") + + def on_unsubscribe(self, client, user_data, mid): + self._add_to_queue(mid, EventTypes.UNSUBACK, None) + self._logger.debug("Produced [unsuback] event") + + def on_message(self, client, user_data, message): + self._add_to_queue(FixedEventMids.MESSAGE_MID, EventTypes.MESSAGE, message) + self._logger.debug("Produced [message] event") + + def _add_to_queue(self, mid, event_type, data): + with self._cv: + self._event_queue.put((mid, event_type, data)) + self._cv.notify() + + +class EventConsumer(object): + + MAX_DISPATCH_INTERNAL_SEC = 0.01 + _logger = logging.getLogger(__name__) + + def __init__(self, cv, event_queue, internal_async_client, + subscription_manager, offline_requests_manager, client_status): + self._cv = cv + self._event_queue = event_queue + self._internal_async_client = internal_async_client + self._subscription_manager = subscription_manager + self._offline_requests_manager = offline_requests_manager + self._client_status = client_status + self._is_running = False + self._draining_interval_sec = DEFAULT_DRAINING_INTERNAL_SEC + self._dispatch_methods = { + EventTypes.CONNACK : self._dispatch_connack, + EventTypes.DISCONNECT : self._dispatch_disconnect, + EventTypes.PUBACK : self._dispatch_puback, + EventTypes.SUBACK : self._dispatch_suback, + EventTypes.UNSUBACK : self._dispatch_unsuback, + EventTypes.MESSAGE : self._dispatch_message + } + self._offline_request_handlers = { + RequestTypes.PUBLISH : self._handle_offline_publish, + RequestTypes.SUBSCRIBE : self._handle_offline_subscribe, + RequestTypes.UNSUBSCRIBE : self._handle_offline_unsubscribe + } + self._stopper = Event() + + def update_offline_requests_manager(self, offline_requests_manager): + self._offline_requests_manager = offline_requests_manager + + def update_draining_interval_sec(self, draining_interval_sec): + self._draining_interval_sec = draining_interval_sec + + def get_draining_interval_sec(self): + return self._draining_interval_sec + + def is_running(self): + return self._is_running + + def start(self): + self._stopper.clear() + self._is_running = True + dispatch_events = Thread(target=self._dispatch) + dispatch_events.daemon = True + dispatch_events.start() + self._logger.debug("Event consuming thread started") + + def stop(self): + if self._is_running: + self._is_running = False + self._clean_up() + self._logger.debug("Event consuming thread stopped") + + def _clean_up(self): + self._logger.debug("Cleaning up before stopping event consuming") + with self._event_queue.mutex: + self._event_queue.queue.clear() + self._logger.debug("Event queue cleared") + self._internal_async_client.stop_background_network_io() + self._logger.debug("Network thread stopped") + self._internal_async_client.clean_up_event_callbacks() + self._logger.debug("Event callbacks cleared") + + def wait_until_it_stops(self, timeout_sec): + self._logger.debug("Waiting for event consumer to completely stop") + return self._stopper.wait(timeout=timeout_sec) + + def is_fully_stopped(self): + return self._stopper.is_set() + + def _dispatch(self): + while self._is_running: + with self._cv: + if self._event_queue.empty(): + self._cv.wait(self.MAX_DISPATCH_INTERNAL_SEC) + else: + while not self._event_queue.empty(): + self._dispatch_one() + self._stopper.set() + self._logger.debug("Exiting dispatching loop...") + + def _dispatch_one(self): + mid, event_type, data = self._event_queue.get() + if mid: + self._dispatch_methods[event_type](mid, data) + self._internal_async_client.invoke_event_callback(mid, data=data) + # We need to make sure disconnect event gets dispatched and then we stop the consumer + if self._need_to_stop_dispatching(mid): + self.stop() + + def _need_to_stop_dispatching(self, mid): + status = self._client_status.get_status() + return (ClientStatus.USER_DISCONNECT == status or ClientStatus.CONNECT == status) \ + and mid == FixedEventMids.DISCONNECT_MID + + def _dispatch_connack(self, mid, rc): + status = self._client_status.get_status() + self._logger.debug("Dispatching [connack] event") + if self._need_recover(): + if ClientStatus.STABLE != status: # To avoid multiple connack dispatching + self._logger.debug("Has recovery job") + clean_up_debt = Thread(target=self._clean_up_debt) + clean_up_debt.start() + else: + self._logger.debug("No need for recovery") + self._client_status.set_status(ClientStatus.STABLE) + + def _need_recover(self): + return self._subscription_manager.list_records() or self._offline_requests_manager.has_more() + + def _clean_up_debt(self): + self._handle_resubscribe() + self._handle_draining() + self._client_status.set_status(ClientStatus.STABLE) + + def _handle_resubscribe(self): + subscriptions = self._subscription_manager.list_records() + if subscriptions and not self._has_user_disconnect_request(): + self._logger.debug("Start resubscribing") + self._client_status.set_status(ClientStatus.RESUBSCRIBE) + for topic, (qos, message_callback, ack_callback) in subscriptions: + if self._has_user_disconnect_request(): + self._logger.debug("User disconnect detected") + break + self._internal_async_client.subscribe(topic, qos, ack_callback) + + def _handle_draining(self): + if self._offline_requests_manager.has_more() and not self._has_user_disconnect_request(): + self._logger.debug("Start draining") + self._client_status.set_status(ClientStatus.DRAINING) + while self._offline_requests_manager.has_more(): + if self._has_user_disconnect_request(): + self._logger.debug("User disconnect detected") + break + offline_request = self._offline_requests_manager.get_next() + if offline_request: + self._offline_request_handlers[offline_request.type](offline_request) + time.sleep(self._draining_interval_sec) + + def _has_user_disconnect_request(self): + return ClientStatus.USER_DISCONNECT == self._client_status.get_status() + + def _dispatch_disconnect(self, mid, rc): + self._logger.debug("Dispatching [disconnect] event") + status = self._client_status.get_status() + if ClientStatus.USER_DISCONNECT == status or ClientStatus.CONNECT == status: + pass + else: + self._client_status.set_status(ClientStatus.ABNORMAL_DISCONNECT) + + # For puback, suback and unsuback, ack callback invocation is handled in dispatch_one + # Do nothing in the event dispatching itself + def _dispatch_puback(self, mid, rc): + self._logger.debug("Dispatching [puback] event") + + def _dispatch_suback(self, mid, rc): + self._logger.debug("Dispatching [suback] event") + + def _dispatch_unsuback(self, mid, rc): + self._logger.debug("Dispatching [unsuback] event") + + def _dispatch_message(self, mid, message): + self._logger.debug("Dispatching [message] event") + subscriptions = self._subscription_manager.list_records() + if subscriptions: + for topic, (qos, message_callback, _) in subscriptions: + if topic_matches_sub(topic, message.topic) and message_callback: + message_callback(None, None, message) # message_callback(client, userdata, message) + + def _handle_offline_publish(self, request): + topic, payload, qos, retain = request.data + self._internal_async_client.publish(topic, payload, qos, retain) + self._logger.debug("Processed offline publish request") + + def _handle_offline_subscribe(self, request): + topic, qos, message_callback, ack_callback = request.data + self._subscription_manager.add_record(topic, qos, message_callback, ack_callback) + self._internal_async_client.subscribe(topic, qos, ack_callback) + self._logger.debug("Processed offline subscribe request") + + def _handle_offline_unsubscribe(self, request): + topic, ack_callback = request.data + self._subscription_manager.remove_record(topic) + self._internal_async_client.unsubscribe(topic, ack_callback) + self._logger.debug("Processed offline unsubscribe request") + + +class SubscriptionManager(object): + + _logger = logging.getLogger(__name__) + + def __init__(self): + self._subscription_map = dict() + + def add_record(self, topic, qos, message_callback, ack_callback): + self._logger.debug("Adding a new subscription record: %s qos: %d", topic, qos) + self._subscription_map[topic] = qos, message_callback, ack_callback # message_callback and/or ack_callback could be None + + def remove_record(self, topic): + self._logger.debug("Removing subscription record: %s", topic) + if self._subscription_map.get(topic): # Ignore topics that are never subscribed to + del self._subscription_map[topic] + else: + self._logger.warn("Removing attempt for non-exist subscription record: %s", topic) + + def list_records(self): + return list(self._subscription_map.items()) + + +class OfflineRequestsManager(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, max_size, drop_behavior): + self._queue = OfflineRequestQueue(max_size, drop_behavior) + + def has_more(self): + return len(self._queue) > 0 + + def add_one(self, request): + return self._queue.append(request) + + def get_next(self): + if self.has_more(): + return self._queue.pop(0) + else: + return None diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/mqtt_core.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/mqtt_core.py new file mode 100644 index 0000000..e2f98fc --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/mqtt_core.py @@ -0,0 +1,373 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import AWSIoTPythonSDK +from AWSIoTPythonSDK.core.protocol.internal.clients import InternalAsyncMqttClient +from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatusContainer +from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatus +from AWSIoTPythonSDK.core.protocol.internal.workers import EventProducer +from AWSIoTPythonSDK.core.protocol.internal.workers import EventConsumer +from AWSIoTPythonSDK.core.protocol.internal.workers import SubscriptionManager +from AWSIoTPythonSDK.core.protocol.internal.workers import OfflineRequestsManager +from AWSIoTPythonSDK.core.protocol.internal.requests import RequestTypes +from AWSIoTPythonSDK.core.protocol.internal.requests import QueueableRequest +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_OPERATION_TIMEOUT_SEC +from AWSIoTPythonSDK.core.protocol.internal.defaults import METRICS_PREFIX +from AWSIoTPythonSDK.core.protocol.internal.defaults import ALPN_PROTCOLS +from AWSIoTPythonSDK.core.protocol.internal.events import FixedEventMids +from AWSIoTPythonSDK.core.protocol.paho.client import MQTT_ERR_SUCCESS +from AWSIoTPythonSDK.exception.AWSIoTExceptions import connectError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import connectTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import disconnectError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import disconnectTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishQueueFullException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishQueueDisabledException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeQueueFullException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeQueueDisabledException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeQueueFullException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeQueueDisabledException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeTimeoutException +from AWSIoTPythonSDK.core.protocol.internal.queues import AppendResults +from AWSIoTPythonSDK.core.util.enums import DropBehaviorTypes +from AWSIoTPythonSDK.core.protocol.paho.client import MQTTv31 +from threading import Condition +from threading import Event +import logging +import sys +if sys.version_info[0] < 3: + from Queue import Queue +else: + from queue import Queue + + +class MqttCore(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, client_id, clean_session, protocol, use_wss): + self._use_wss = use_wss + self._username = "" + self._password = None + self._enable_metrics_collection = True + self._event_queue = Queue() + self._event_cv = Condition() + self._event_producer = EventProducer(self._event_cv, self._event_queue) + self._client_status = ClientStatusContainer() + self._internal_async_client = InternalAsyncMqttClient(client_id, clean_session, protocol, use_wss) + self._subscription_manager = SubscriptionManager() + self._offline_requests_manager = OfflineRequestsManager(-1, DropBehaviorTypes.DROP_NEWEST) # Infinite queue + self._event_consumer = EventConsumer(self._event_cv, + self._event_queue, + self._internal_async_client, + self._subscription_manager, + self._offline_requests_manager, + self._client_status) + self._connect_disconnect_timeout_sec = DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC + self._operation_timeout_sec = DEFAULT_OPERATION_TIMEOUT_SEC + self._init_offline_request_exceptions() + self._init_workers() + self._logger.info("MqttCore initialized") + self._logger.info("Client id: %s" % client_id) + self._logger.info("Protocol version: %s" % ("MQTTv3.1" if protocol == MQTTv31 else "MQTTv3.1.1")) + self._logger.info("Authentication type: %s" % ("SigV4 WebSocket" if use_wss else "TLSv1.2 certificate based Mutual Auth.")) + + def _init_offline_request_exceptions(self): + self._offline_request_queue_disabled_exceptions = { + RequestTypes.PUBLISH : publishQueueDisabledException(), + RequestTypes.SUBSCRIBE : subscribeQueueDisabledException(), + RequestTypes.UNSUBSCRIBE : unsubscribeQueueDisabledException() + } + self._offline_request_queue_full_exceptions = { + RequestTypes.PUBLISH : publishQueueFullException(), + RequestTypes.SUBSCRIBE : subscribeQueueFullException(), + RequestTypes.UNSUBSCRIBE : unsubscribeQueueFullException() + } + + def _init_workers(self): + self._internal_async_client.register_internal_event_callbacks(self._event_producer.on_connect, + self._event_producer.on_disconnect, + self._event_producer.on_publish, + self._event_producer.on_subscribe, + self._event_producer.on_unsubscribe, + self._event_producer.on_message) + + def _start_workers(self): + self._event_consumer.start() + + def use_wss(self): + return self._use_wss + + # Used for general message event reception + def on_message(self, message): + pass + + # Used for general online event notification + def on_online(self): + pass + + # Used for general offline event notification + def on_offline(self): + pass + + def configure_cert_credentials(self, cert_credentials_provider): + self._logger.info("Configuring certificates...") + self._internal_async_client.set_cert_credentials_provider(cert_credentials_provider) + + def configure_iam_credentials(self, iam_credentials_provider): + self._logger.info("Configuring custom IAM credentials...") + self._internal_async_client.set_iam_credentials_provider(iam_credentials_provider) + + def configure_endpoint(self, endpoint_provider): + self._logger.info("Configuring endpoint...") + self._internal_async_client.set_endpoint_provider(endpoint_provider) + + def configure_connect_disconnect_timeout_sec(self, connect_disconnect_timeout_sec): + self._logger.info("Configuring connect/disconnect time out: %f sec" % connect_disconnect_timeout_sec) + self._connect_disconnect_timeout_sec = connect_disconnect_timeout_sec + + def configure_operation_timeout_sec(self, operation_timeout_sec): + self._logger.info("Configuring MQTT operation time out: %f sec" % operation_timeout_sec) + self._operation_timeout_sec = operation_timeout_sec + + def configure_reconnect_back_off(self, base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec): + self._logger.info("Configuring reconnect back off timing...") + self._logger.info("Base quiet time: %f sec" % base_reconnect_quiet_sec) + self._logger.info("Max quiet time: %f sec" % max_reconnect_quiet_sec) + self._logger.info("Stable connection time: %f sec" % stable_connection_sec) + self._internal_async_client.configure_reconnect_back_off(base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec) + + def configure_alpn_protocols(self): + self._logger.info("Configuring alpn protocols...") + self._internal_async_client.configure_alpn_protocols([ALPN_PROTCOLS]) + + def configure_last_will(self, topic, payload, qos, retain=False): + self._logger.info("Configuring last will...") + self._internal_async_client.configure_last_will(topic, payload, qos, retain) + + def clear_last_will(self): + self._logger.info("Clearing last will...") + self._internal_async_client.clear_last_will() + + def configure_username_password(self, username, password=None): + self._logger.info("Configuring username and password...") + self._username = username + self._password = password + + def configure_socket_factory(self, socket_factory): + self._logger.info("Configuring socket factory...") + self._internal_async_client.set_socket_factory(socket_factory) + + def enable_metrics_collection(self): + self._enable_metrics_collection = True + + def disable_metrics_collection(self): + self._enable_metrics_collection = False + + def configure_offline_requests_queue(self, max_size, drop_behavior): + self._logger.info("Configuring offline requests queueing: max queue size: %d", max_size) + self._offline_requests_manager = OfflineRequestsManager(max_size, drop_behavior) + self._event_consumer.update_offline_requests_manager(self._offline_requests_manager) + + def configure_draining_interval_sec(self, draining_interval_sec): + self._logger.info("Configuring offline requests queue draining interval: %f sec", draining_interval_sec) + self._event_consumer.update_draining_interval_sec(draining_interval_sec) + + def connect(self, keep_alive_sec): + self._logger.info("Performing sync connect...") + event = Event() + self.connect_async(keep_alive_sec, self._create_blocking_ack_callback(event)) + if not event.wait(self._connect_disconnect_timeout_sec): + self._logger.error("Connect timed out") + raise connectTimeoutException() + return True + + def connect_async(self, keep_alive_sec, ack_callback=None): + self._logger.info("Performing async connect...") + self._logger.info("Keep-alive: %f sec" % keep_alive_sec) + self._start_workers() + self._load_callbacks() + self._load_username_password() + + try: + self._client_status.set_status(ClientStatus.CONNECT) + rc = self._internal_async_client.connect(keep_alive_sec, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Connect error: %d", rc) + raise connectError(rc) + except Exception as e: + # Provided any error in connect, we should clean up the threads that have been created + self._event_consumer.stop() + if not self._event_consumer.wait_until_it_stops(self._connect_disconnect_timeout_sec): + self._logger.error("Time out in waiting for event consumer to stop") + else: + self._logger.debug("Event consumer stopped") + self._client_status.set_status(ClientStatus.IDLE) + raise e + + return FixedEventMids.CONNACK_MID + + def _load_callbacks(self): + self._logger.debug("Passing in general notification callbacks to internal client...") + self._internal_async_client.on_online = self.on_online + self._internal_async_client.on_offline = self.on_offline + self._internal_async_client.on_message = self.on_message + + def _load_username_password(self): + username_candidate = self._username + if self._enable_metrics_collection: + username_candidate += METRICS_PREFIX + username_candidate += AWSIoTPythonSDK.__version__ + self._internal_async_client.set_username_password(username_candidate, self._password) + + def disconnect(self): + self._logger.info("Performing sync disconnect...") + event = Event() + self.disconnect_async(self._create_blocking_ack_callback(event)) + if not event.wait(self._connect_disconnect_timeout_sec): + self._logger.error("Disconnect timed out") + raise disconnectTimeoutException() + if not self._event_consumer.wait_until_it_stops(self._connect_disconnect_timeout_sec): + self._logger.error("Disconnect timed out in waiting for event consumer") + raise disconnectTimeoutException() + return True + + def disconnect_async(self, ack_callback=None): + self._logger.info("Performing async disconnect...") + self._client_status.set_status(ClientStatus.USER_DISCONNECT) + rc = self._internal_async_client.disconnect(ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Disconnect error: %d", rc) + raise disconnectError(rc) + return FixedEventMids.DISCONNECT_MID + + def publish(self, topic, payload, qos, retain=False): + self._logger.info("Performing sync publish...") + ret = False + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.PUBLISH, (topic, payload, qos, retain)) + else: + if qos > 0: + event = Event() + rc, mid = self._publish_async(topic, payload, qos, retain, self._create_blocking_ack_callback(event)) + if not event.wait(self._operation_timeout_sec): + self._internal_async_client.remove_event_callback(mid) + self._logger.error("Publish timed out") + raise publishTimeoutException() + else: + self._publish_async(topic, payload, qos, retain) + ret = True + return ret + + def publish_async(self, topic, payload, qos, retain=False, ack_callback=None): + self._logger.info("Performing async publish...") + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.PUBLISH, (topic, payload, qos, retain)) + return FixedEventMids.QUEUED_MID + else: + rc, mid = self._publish_async(topic, payload, qos, retain, ack_callback) + return mid + + def _publish_async(self, topic, payload, qos, retain=False, ack_callback=None): + rc, mid = self._internal_async_client.publish(topic, payload, qos, retain, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Publish error: %d", rc) + raise publishError(rc) + return rc, mid + + def subscribe(self, topic, qos, message_callback=None): + self._logger.info("Performing sync subscribe...") + ret = False + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.SUBSCRIBE, (topic, qos, message_callback, None)) + else: + event = Event() + rc, mid = self._subscribe_async(topic, qos, self._create_blocking_ack_callback(event), message_callback) + if not event.wait(self._operation_timeout_sec): + self._internal_async_client.remove_event_callback(mid) + self._logger.error("Subscribe timed out") + raise subscribeTimeoutException() + ret = True + return ret + + def subscribe_async(self, topic, qos, ack_callback=None, message_callback=None): + self._logger.info("Performing async subscribe...") + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.SUBSCRIBE, (topic, qos, message_callback, ack_callback)) + return FixedEventMids.QUEUED_MID + else: + rc, mid = self._subscribe_async(topic, qos, ack_callback, message_callback) + return mid + + def _subscribe_async(self, topic, qos, ack_callback=None, message_callback=None): + self._subscription_manager.add_record(topic, qos, message_callback, ack_callback) + rc, mid = self._internal_async_client.subscribe(topic, qos, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Subscribe error: %d", rc) + raise subscribeError(rc) + return rc, mid + + def unsubscribe(self, topic): + self._logger.info("Performing sync unsubscribe...") + ret = False + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.UNSUBSCRIBE, (topic, None)) + else: + event = Event() + rc, mid = self._unsubscribe_async(topic, self._create_blocking_ack_callback(event)) + if not event.wait(self._operation_timeout_sec): + self._internal_async_client.remove_event_callback(mid) + self._logger.error("Unsubscribe timed out") + raise unsubscribeTimeoutException() + ret = True + return ret + + def unsubscribe_async(self, topic, ack_callback=None): + self._logger.info("Performing async unsubscribe...") + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.UNSUBSCRIBE, (topic, ack_callback)) + return FixedEventMids.QUEUED_MID + else: + rc, mid = self._unsubscribe_async(topic, ack_callback) + return mid + + def _unsubscribe_async(self, topic, ack_callback=None): + self._subscription_manager.remove_record(topic) + rc, mid = self._internal_async_client.unsubscribe(topic, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Unsubscribe error: %d", rc) + raise unsubscribeError(rc) + return rc, mid + + def _create_blocking_ack_callback(self, event): + def ack_callback(mid, data=None): + event.set() + return ack_callback + + def _handle_offline_request(self, type, data): + self._logger.info("Offline request detected!") + offline_request = QueueableRequest(type, data) + append_result = self._offline_requests_manager.add_one(offline_request) + if AppendResults.APPEND_FAILURE_QUEUE_DISABLED == append_result: + self._logger.error("Offline request queue has been disabled") + raise self._offline_request_queue_disabled_exceptions[type] + if AppendResults.APPEND_FAILURE_QUEUE_FULL == append_result: + self._logger.error("Offline request queue is full") + raise self._offline_request_queue_full_exceptions[type] diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/paho/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/paho/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/paho/client.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/paho/client.py new file mode 100644 index 0000000..503d1c6 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/protocol/paho/client.py @@ -0,0 +1,2445 @@ +# Copyright (c) 2012-2014 Roger Light +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# and Eclipse Distribution License v1.0 which accompany this distribution. +# +# The Eclipse Public License is available at +# http://www.eclipse.org/legal/epl-v10.html +# and the Eclipse Distribution License is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# Contributors: +# Roger Light - initial API and implementation + +""" +This is an MQTT v3.1 client module. MQTT is a lightweight pub/sub messaging +protocol that is easy to implement and suitable for low powered devices. +""" +import errno +import platform +import random +import select +import socket +HAVE_SSL = True +try: + import ssl + cert_reqs = ssl.CERT_REQUIRED + tls_version = ssl.PROTOCOL_TLSv1 +except: + HAVE_SSL = False + cert_reqs = None + tls_version = None +import struct +import sys +import threading +import time +HAVE_DNS = True +try: + import dns.resolver +except ImportError: + HAVE_DNS = False + +if platform.system() == 'Windows': + EAGAIN = errno.WSAEWOULDBLOCK +else: + EAGAIN = errno.EAGAIN + +from AWSIoTPythonSDK.core.protocol.connection.cores import ProgressiveBackOffCore +from AWSIoTPythonSDK.core.protocol.connection.cores import SecuredWebSocketCore +from AWSIoTPythonSDK.core.protocol.connection.alpn import SSLContextBuilder + +VERSION_MAJOR=1 +VERSION_MINOR=0 +VERSION_REVISION=0 +VERSION_NUMBER=(VERSION_MAJOR*1000000+VERSION_MINOR*1000+VERSION_REVISION) + +MQTTv31 = 3 +MQTTv311 = 4 + +if sys.version_info[0] < 3: + PROTOCOL_NAMEv31 = "MQIsdp" + PROTOCOL_NAMEv311 = "MQTT" +else: + PROTOCOL_NAMEv31 = b"MQIsdp" + PROTOCOL_NAMEv311 = b"MQTT" + +PROTOCOL_VERSION = 3 + +# Message types +CONNECT = 0x10 +CONNACK = 0x20 +PUBLISH = 0x30 +PUBACK = 0x40 +PUBREC = 0x50 +PUBREL = 0x60 +PUBCOMP = 0x70 +SUBSCRIBE = 0x80 +SUBACK = 0x90 +UNSUBSCRIBE = 0xA0 +UNSUBACK = 0xB0 +PINGREQ = 0xC0 +PINGRESP = 0xD0 +DISCONNECT = 0xE0 + +# Log levels +MQTT_LOG_INFO = 0x01 +MQTT_LOG_NOTICE = 0x02 +MQTT_LOG_WARNING = 0x04 +MQTT_LOG_ERR = 0x08 +MQTT_LOG_DEBUG = 0x10 + +# CONNACK codes +CONNACK_ACCEPTED = 0 +CONNACK_REFUSED_PROTOCOL_VERSION = 1 +CONNACK_REFUSED_IDENTIFIER_REJECTED = 2 +CONNACK_REFUSED_SERVER_UNAVAILABLE = 3 +CONNACK_REFUSED_BAD_USERNAME_PASSWORD = 4 +CONNACK_REFUSED_NOT_AUTHORIZED = 5 + +# Connection state +mqtt_cs_new = 0 +mqtt_cs_connected = 1 +mqtt_cs_disconnecting = 2 +mqtt_cs_connect_async = 3 + +# Message state +mqtt_ms_invalid = 0 +mqtt_ms_publish= 1 +mqtt_ms_wait_for_puback = 2 +mqtt_ms_wait_for_pubrec = 3 +mqtt_ms_resend_pubrel = 4 +mqtt_ms_wait_for_pubrel = 5 +mqtt_ms_resend_pubcomp = 6 +mqtt_ms_wait_for_pubcomp = 7 +mqtt_ms_send_pubrec = 8 +mqtt_ms_queued = 9 + +# Error values +MQTT_ERR_AGAIN = -1 +MQTT_ERR_SUCCESS = 0 +MQTT_ERR_NOMEM = 1 +MQTT_ERR_PROTOCOL = 2 +MQTT_ERR_INVAL = 3 +MQTT_ERR_NO_CONN = 4 +MQTT_ERR_CONN_REFUSED = 5 +MQTT_ERR_NOT_FOUND = 6 +MQTT_ERR_CONN_LOST = 7 +MQTT_ERR_TLS = 8 +MQTT_ERR_PAYLOAD_SIZE = 9 +MQTT_ERR_NOT_SUPPORTED = 10 +MQTT_ERR_AUTH = 11 +MQTT_ERR_ACL_DENIED = 12 +MQTT_ERR_UNKNOWN = 13 +MQTT_ERR_ERRNO = 14 + +# MessageQueueing DropBehavior +MSG_QUEUEING_DROP_OLDEST = 0 +MSG_QUEUEING_DROP_NEWEST = 1 + +if sys.version_info[0] < 3: + sockpair_data = "0" +else: + sockpair_data = b"0" + +def error_string(mqtt_errno): + """Return the error string associated with an mqtt error number.""" + if mqtt_errno == MQTT_ERR_SUCCESS: + return "No error." + elif mqtt_errno == MQTT_ERR_NOMEM: + return "Out of memory." + elif mqtt_errno == MQTT_ERR_PROTOCOL: + return "A network protocol error occurred when communicating with the broker." + elif mqtt_errno == MQTT_ERR_INVAL: + return "Invalid function arguments provided." + elif mqtt_errno == MQTT_ERR_NO_CONN: + return "The client is not currently connected." + elif mqtt_errno == MQTT_ERR_CONN_REFUSED: + return "The connection was refused." + elif mqtt_errno == MQTT_ERR_NOT_FOUND: + return "Message not found (internal error)." + elif mqtt_errno == MQTT_ERR_CONN_LOST: + return "The connection was lost." + elif mqtt_errno == MQTT_ERR_TLS: + return "A TLS error occurred." + elif mqtt_errno == MQTT_ERR_PAYLOAD_SIZE: + return "Payload too large." + elif mqtt_errno == MQTT_ERR_NOT_SUPPORTED: + return "This feature is not supported." + elif mqtt_errno == MQTT_ERR_AUTH: + return "Authorisation failed." + elif mqtt_errno == MQTT_ERR_ACL_DENIED: + return "Access denied by ACL." + elif mqtt_errno == MQTT_ERR_UNKNOWN: + return "Unknown error." + elif mqtt_errno == MQTT_ERR_ERRNO: + return "Error defined by errno." + else: + return "Unknown error." + + +def connack_string(connack_code): + """Return the string associated with a CONNACK result.""" + if connack_code == 0: + return "Connection Accepted." + elif connack_code == 1: + return "Connection Refused: unacceptable protocol version." + elif connack_code == 2: + return "Connection Refused: identifier rejected." + elif connack_code == 3: + return "Connection Refused: broker unavailable." + elif connack_code == 4: + return "Connection Refused: bad user name or password." + elif connack_code == 5: + return "Connection Refused: not authorised." + else: + return "Connection Refused: unknown reason." + + +def topic_matches_sub(sub, topic): + """Check whether a topic matches a subscription. + + For example: + + foo/bar would match the subscription foo/# or +/bar + non/matching would not match the subscription non/+/+ + """ + result = True + multilevel_wildcard = False + + slen = len(sub) + tlen = len(topic) + + if slen > 0 and tlen > 0: + if (sub[0] == '$' and topic[0] != '$') or (topic[0] == '$' and sub[0] != '$'): + return False + + spos = 0 + tpos = 0 + + while spos < slen and tpos < tlen: + if sub[spos] == topic[tpos]: + if tpos == tlen-1: + # Check for e.g. foo matching foo/# + if spos == slen-3 and sub[spos+1] == '/' and sub[spos+2] == '#': + result = True + multilevel_wildcard = True + break + + spos += 1 + tpos += 1 + + if tpos == tlen and spos == slen-1 and sub[spos] == '+': + spos += 1 + result = True + break + else: + if sub[spos] == '+': + spos += 1 + while tpos < tlen and topic[tpos] != '/': + tpos += 1 + if tpos == tlen and spos == slen: + result = True + break + + elif sub[spos] == '#': + multilevel_wildcard = True + if spos+1 != slen: + result = False + break + else: + result = True + break + + else: + result = False + break + + if not multilevel_wildcard and (tpos < tlen or spos < slen): + result = False + + return result + + +def _socketpair_compat(): + """TCP/IP socketpair including Windows support""" + listensock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_IP) + listensock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + listensock.bind(("127.0.0.1", 0)) + listensock.listen(1) + + iface, port = listensock.getsockname() + sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_IP) + sock1.setblocking(0) + try: + sock1.connect(("127.0.0.1", port)) + except socket.error as err: + if err.errno != errno.EINPROGRESS and err.errno != errno.EWOULDBLOCK and err.errno != EAGAIN: + raise + sock2, address = listensock.accept() + sock2.setblocking(0) + listensock.close() + return (sock1, sock2) + + +class MQTTMessage: + """ This is a class that describes an incoming message. It is passed to the + on_message callback as the message parameter. + + Members: + + topic : String. topic that the message was published on. + payload : String/bytes the message payload. + qos : Integer. The message Quality of Service 0, 1 or 2. + retain : Boolean. If true, the message is a retained message and not fresh. + mid : Integer. The message id. + """ + def __init__(self): + self.timestamp = 0 + self.state = mqtt_ms_invalid + self.dup = False + self.mid = 0 + self.topic = "" + self.payload = None + self.qos = 0 + self.retain = False + + +class Client(object): + """MQTT version 3.1/3.1.1 client class. + + This is the main class for use communicating with an MQTT broker. + + General usage flow: + + * Use connect()/connect_async() to connect to a broker + * Call loop() frequently to maintain network traffic flow with the broker + * Or use loop_start() to set a thread running to call loop() for you. + * Or use loop_forever() to handle calling loop() for you in a blocking + * function. + * Use subscribe() to subscribe to a topic and receive messages + * Use publish() to send messages + * Use disconnect() to disconnect from the broker + + Data returned from the broker is made available with the use of callback + functions as described below. + + Callbacks + ========= + + A number of callback functions are available to receive data back from the + broker. To use a callback, define a function and then assign it to the + client: + + def on_connect(client, userdata, flags, rc): + print("Connection returned " + str(rc)) + + client.on_connect = on_connect + + All of the callbacks as described below have a "client" and an "userdata" + argument. "client" is the Client instance that is calling the callback. + "userdata" is user data of any type and can be set when creating a new client + instance or with user_data_set(userdata). + + The callbacks: + + on_connect(client, userdata, flags, rc): called when the broker responds to our connection + request. + flags is a dict that contains response flags from the broker: + flags['session present'] - this flag is useful for clients that are + using clean session set to 0 only. If a client with clean + session=0, that reconnects to a broker that it has previously + connected to, this flag indicates whether the broker still has the + session information for the client. If 1, the session still exists. + The value of rc determines success or not: + 0: Connection successful + 1: Connection refused - incorrect protocol version + 2: Connection refused - invalid client identifier + 3: Connection refused - server unavailable + 4: Connection refused - bad username or password + 5: Connection refused - not authorised + 6-255: Currently unused. + + on_disconnect(client, userdata, rc): called when the client disconnects from the broker. + The rc parameter indicates the disconnection state. If MQTT_ERR_SUCCESS + (0), the callback was called in response to a disconnect() call. If any + other value the disconnection was unexpected, such as might be caused by + a network error. + + on_message(client, userdata, message): called when a message has been received on a + topic that the client subscribes to. The message variable is a + MQTTMessage that describes all of the message parameters. + + on_publish(client, userdata, mid): called when a message that was to be sent using the + publish() call has completed transmission to the broker. For messages + with QoS levels 1 and 2, this means that the appropriate handshakes have + completed. For QoS 0, this simply means that the message has left the + client. The mid variable matches the mid variable returned from the + corresponding publish() call, to allow outgoing messages to be tracked. + This callback is important because even if the publish() call returns + success, it does not always mean that the message has been sent. + + on_subscribe(client, userdata, mid, granted_qos): called when the broker responds to a + subscribe request. The mid variable matches the mid variable returned + from the corresponding subscribe() call. The granted_qos variable is a + list of integers that give the QoS level the broker has granted for each + of the different subscription requests. + + on_unsubscribe(client, userdata, mid): called when the broker responds to an unsubscribe + request. The mid variable matches the mid variable returned from the + corresponding unsubscribe() call. + + on_log(client, userdata, level, buf): called when the client has log information. Define + to allow debugging. The level variable gives the severity of the message + and will be one of MQTT_LOG_INFO, MQTT_LOG_NOTICE, MQTT_LOG_WARNING, + MQTT_LOG_ERR, and MQTT_LOG_DEBUG. The message itself is in buf. + + """ + def __init__(self, client_id="", clean_session=True, userdata=None, protocol=MQTTv31, useSecuredWebsocket=False): + """client_id is the unique client id string used when connecting to the + broker. If client_id is zero length or None, then one will be randomly + generated. In this case, clean_session must be True. If this is not the + case a ValueError will be raised. + + clean_session is a boolean that determines the client type. If True, + the broker will remove all information about this client when it + disconnects. If False, the client is a persistent client and + subscription information and queued messages will be retained when the + client disconnects. + Note that a client will never discard its own outgoing messages on + disconnect. Calling connect() or reconnect() will cause the messages to + be resent. Use reinitialise() to reset a client to its original state. + + userdata is user defined data of any type that is passed as the "userdata" + parameter to callbacks. It may be updated at a later point with the + user_data_set() function. + + The protocol argument allows explicit setting of the MQTT version to + use for this client. Can be paho.mqtt.client.MQTTv311 (v3.1.1) or + paho.mqtt.client.MQTTv31 (v3.1), with the default being v3.1. If the + broker reports that the client connected with an invalid protocol + version, the client will automatically attempt to reconnect using v3.1 + instead. + + useSecuredWebsocket is a boolean that determines whether the client uses + MQTT over Websocket with sigV4 signing (True) or MQTT with plain TCP + socket. If True, the client will try to find AWS_ACCESS_KEY_ID and + AWS_SECRET_ACCESS_KEY in the system environment variables and start the + sigV4 signing and Websocket handshake. Under this configuration, all + outbound MQTT packets will be wrapped around with Websocket framework. All + inbound MQTT packets will be automatically wss-decoded. + """ + if not clean_session and (client_id == "" or client_id is None): + raise ValueError('A client id must be provided if clean session is False.') + + self._protocol = protocol + self._userdata = userdata + self._sock = None + self._sockpairR, self._sockpairW = _socketpair_compat() + self._keepalive = 60 + self._message_retry = 20 + self._last_retry_check = 0 + self._clean_session = clean_session + if client_id == "" or client_id is None: + self._client_id = "paho/" + "".join(random.choice("0123456789ADCDEF") for x in range(23-5)) + else: + self._client_id = client_id + + self._username = "" + self._password = "" + self._in_packet = { + "command": 0, + "have_remaining": 0, + "remaining_count": [], + "remaining_mult": 1, + "remaining_length": 0, + "packet": b"", + "to_process": 0, + "pos": 0} + self._out_packet = [] + self._current_out_packet = None + self._last_msg_in = time.time() + self._last_msg_out = time.time() + self._ping_t = 0 + self._last_mid = 0 + self._state = mqtt_cs_new + self._max_inflight_messages = 20 + self._out_messages = [] + self._in_messages = [] + self._inflight_messages = 0 + self._will = False + self._will_topic = "" + self._will_payload = None + self._will_qos = 0 + self._will_retain = False + self.on_disconnect = None + self.on_connect = None + self.on_publish = None + self.on_message = None + self.on_message_filtered = [] + self.on_subscribe = None + self.on_unsubscribe = None + self.on_log = None + self._host = "" + self._port = 1883 + self._bind_address = "" + self._socket_factory = None + self._in_callback = False + self._strict_protocol = False + self._callback_mutex = threading.Lock() + self._state_mutex = threading.Lock() + self._out_packet_mutex = threading.Lock() + self._current_out_packet_mutex = threading.Lock() + self._msgtime_mutex = threading.Lock() + self._out_message_mutex = threading.Lock() + self._in_message_mutex = threading.Lock() + self._thread = None + self._thread_terminate = False + self._ssl = None + self._tls_certfile = None + self._tls_keyfile = None + self._tls_ca_certs = None + self._tls_cert_reqs = None + self._tls_ciphers = None + self._tls_version = tls_version + self._tls_insecure = False + self._useSecuredWebsocket = useSecuredWebsocket # Do we enable secured websocket + self._backoffCore = ProgressiveBackOffCore() # Init the backoffCore using default configuration + self._AWSAccessKeyIDCustomConfig = "" + self._AWSSecretAccessKeyCustomConfig = "" + self._AWSSessionTokenCustomConfig = "" + self._alpn_protocols = None + + def __del__(self): + pass + + + def setBackoffTiming(self, srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSecond, srcMinimumConnectTimeSecond): + """ + Make custom settings for backoff timing for reconnect logic + srcBaseReconnectTimeSecond - The base reconnection time in seconds + srcMaximumReconnectTimeSecond - The maximum reconnection time in seconds + srcMinimumConnectTimeSecond - The minimum time in seconds that a connection must be maintained in order to be considered stable + * Raise ValueError if input params are malformed + """ + self._backoffCore.configTime(srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSecond, srcMinimumConnectTimeSecond) + + def configIAMCredentials(self, srcAWSAccessKeyID, srcAWSSecretAccessKey, srcAWSSessionToken): + """ + Make custom settings for IAM credentials for websocket connection + srcAWSAccessKeyID - AWS IAM access key + srcAWSSecretAccessKey - AWS IAM secret key + srcAWSSessionToken - AWS Session Token + """ + self._AWSAccessKeyIDCustomConfig = srcAWSAccessKeyID + self._AWSSecretAccessKeyCustomConfig = srcAWSSecretAccessKey + self._AWSSessionTokenCustomConfig = srcAWSSessionToken + + def config_alpn_protocols(self, alpn_protocols): + """ + Make custom settings for ALPN protocols + :param alpn_protocols: Array of strings that specifies the alpn protocols to be used + :return: None + """ + self._alpn_protocols = alpn_protocols + + def reinitialise(self, client_id="", clean_session=True, userdata=None): + if self._ssl: + self._ssl.close() + self._ssl = None + self._sock = None + elif self._sock: + self._sock.close() + self._sock = None + if self._sockpairR: + self._sockpairR.close() + self._sockpairR = None + if self._sockpairW: + self._sockpairW.close() + self._sockpairW = None + + self.__init__(client_id, clean_session, userdata) + + def tls_set(self, ca_certs, certfile=None, keyfile=None, cert_reqs=cert_reqs, tls_version=tls_version, ciphers=None): + """Configure network encryption and authentication options. Enables SSL/TLS support. + + ca_certs : a string path to the Certificate Authority certificate files + that are to be treated as trusted by this client. If this is the only + option given then the client will operate in a similar manner to a web + browser. That is to say it will require the broker to have a + certificate signed by the Certificate Authorities in ca_certs and will + communicate using TLS v1, but will not attempt any form of + authentication. This provides basic network encryption but may not be + sufficient depending on how the broker is configured. + + certfile and keyfile are strings pointing to the PEM encoded client + certificate and private keys respectively. If these arguments are not + None then they will be used as client information for TLS based + authentication. Support for this feature is broker dependent. Note + that if either of these files in encrypted and needs a password to + decrypt it, Python will ask for the password at the command line. It is + not currently possible to define a callback to provide the password. + + cert_reqs allows the certificate requirements that the client imposes + on the broker to be changed. By default this is ssl.CERT_REQUIRED, + which means that the broker must provide a certificate. See the ssl + pydoc for more information on this parameter. + + tls_version allows the version of the SSL/TLS protocol used to be + specified. By default TLS v1 is used. Previous versions (all versions + beginning with SSL) are possible but not recommended due to possible + security problems. + + ciphers is a string specifying which encryption ciphers are allowable + for this connection, or None to use the defaults. See the ssl pydoc for + more information. + + Must be called before connect() or connect_async().""" + if HAVE_SSL is False: + raise ValueError('This platform has no SSL/TLS.') + + if sys.version < '2.7': + raise ValueError('Python 2.7 is the minimum supported version for TLS.') + + if ca_certs is None: + raise ValueError('ca_certs must not be None.') + + try: + f = open(ca_certs, "r") + except IOError as err: + raise IOError(ca_certs+": "+err.strerror) + else: + f.close() + if certfile is not None: + try: + f = open(certfile, "r") + except IOError as err: + raise IOError(certfile+": "+err.strerror) + else: + f.close() + if keyfile is not None: + try: + f = open(keyfile, "r") + except IOError as err: + raise IOError(keyfile+": "+err.strerror) + else: + f.close() + + self._tls_ca_certs = ca_certs + self._tls_certfile = certfile + self._tls_keyfile = keyfile + self._tls_cert_reqs = cert_reqs + self._tls_version = tls_version + self._tls_ciphers = ciphers + + def tls_insecure_set(self, value): + """Configure verification of the server hostname in the server certificate. + + If value is set to true, it is impossible to guarantee that the host + you are connecting to is not impersonating your server. This can be + useful in initial server testing, but makes it possible for a malicious + third party to impersonate your server through DNS spoofing, for + example. + + Do not use this function in a real system. Setting value to true means + there is no point using encryption. + + Must be called before connect().""" + if HAVE_SSL is False: + raise ValueError('This platform has no SSL/TLS.') + + self._tls_insecure = value + + def connect(self, host, port=1883, keepalive=60, bind_address=""): + """Connect to a remote broker. + + host is the hostname or IP address of the remote broker. + port is the network port of the server host to connect to. Defaults to + 1883. Note that the default port for MQTT over SSL/TLS is 8883 so if you + are using tls_set() the port may need providing. + keepalive: Maximum period in seconds between communications with the + broker. If no other messages are being exchanged, this controls the + rate at which the client will send ping messages to the broker. + """ + self.connect_async(host, port, keepalive, bind_address) + return self.reconnect() + + def connect_srv(self, domain=None, keepalive=60, bind_address=""): + """Connect to a remote broker. + + domain is the DNS domain to search for SRV records; if None, + try to determine local domain name. + keepalive and bind_address are as for connect() + """ + + if HAVE_DNS is False: + raise ValueError('No DNS resolver library found.') + + if domain is None: + domain = socket.getfqdn() + domain = domain[domain.find('.') + 1:] + + try: + rr = '_mqtt._tcp.%s' % domain + if self._ssl is not None: + # IANA specifies secure-mqtt (not mqtts) for port 8883 + rr = '_secure-mqtt._tcp.%s' % domain + answers = [] + for answer in dns.resolver.query(rr, dns.rdatatype.SRV): + addr = answer.target.to_text()[:-1] + answers.append((addr, answer.port, answer.priority, answer.weight)) + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.resolver.NoNameservers): + raise ValueError("No answer/NXDOMAIN for SRV in %s" % (domain)) + + # FIXME: doesn't account for weight + for answer in answers: + host, port, prio, weight = answer + + try: + return self.connect(host, port, keepalive, bind_address) + except: + pass + + raise ValueError("No SRV hosts responded") + + def connect_async(self, host, port=1883, keepalive=60, bind_address=""): + """Connect to a remote broker asynchronously. This is a non-blocking + connect call that can be used with loop_start() to provide very quick + start. + + host is the hostname or IP address of the remote broker. + port is the network port of the server host to connect to. Defaults to + 1883. Note that the default port for MQTT over SSL/TLS is 8883 so if you + are using tls_set() the port may need providing. + keepalive: Maximum period in seconds between communications with the + broker. If no other messages are being exchanged, this controls the + rate at which the client will send ping messages to the broker. + """ + if host is None or len(host) == 0: + raise ValueError('Invalid host.') + if port <= 0: + raise ValueError('Invalid port number.') + if keepalive < 0: + raise ValueError('Keepalive must be >=0.') + if bind_address != "" and bind_address is not None: + if (sys.version_info[0] == 2 and sys.version_info[1] < 7) or (sys.version_info[0] == 3 and sys.version_info[1] < 2): + raise ValueError('bind_address requires Python 2.7 or 3.2.') + + self._host = host + self._port = port + self._keepalive = keepalive + self._bind_address = bind_address + + self._state_mutex.acquire() + self._state = mqtt_cs_connect_async + self._state_mutex.release() + + def reconnect(self): + """Reconnect the client after a disconnect. Can only be called after + connect()/connect_async().""" + if len(self._host) == 0: + raise ValueError('Invalid host.') + if self._port <= 0: + raise ValueError('Invalid port number.') + + self._in_packet = { + "command": 0, + "have_remaining": 0, + "remaining_count": [], + "remaining_mult": 1, + "remaining_length": 0, + "packet": b"", + "to_process": 0, + "pos": 0} + + self._out_packet_mutex.acquire() + self._out_packet = [] + self._out_packet_mutex.release() + + self._current_out_packet_mutex.acquire() + self._current_out_packet = None + self._current_out_packet_mutex.release() + + self._msgtime_mutex.acquire() + self._last_msg_in = time.time() + self._last_msg_out = time.time() + self._msgtime_mutex.release() + + self._ping_t = 0 + self._state_mutex.acquire() + self._state = mqtt_cs_new + self._state_mutex.release() + if self._ssl: + self._ssl.close() + self._ssl = None + self._sock = None + elif self._sock: + self._sock.close() + self._sock = None + + # Put messages in progress in a valid state. + self._messages_reconnect_reset() + + try: + if self._socket_factory: + sock = self._socket_factory() + elif (sys.version_info[0] == 2 and sys.version_info[1] < 7) or (sys.version_info[0] == 3 and sys.version_info[1] < 2): + sock = socket.create_connection((self._host, self._port)) + else: + sock = socket.create_connection((self._host, self._port), source_address=(self._bind_address, 0)) + except socket.error as err: + if err.errno != errno.EINPROGRESS and err.errno != errno.EWOULDBLOCK and err.errno != EAGAIN: + raise + + verify_hostname = self._tls_insecure is False # Decide whether we need to verify hostname + + if self._tls_ca_certs is not None: + if self._useSecuredWebsocket: + # Never assign to ._ssl before wss handshake is finished + # Non-None value for ._ssl will allow ops before wss-MQTT connection is established + rawSSL = ssl.wrap_socket(sock, ca_certs=self._tls_ca_certs, cert_reqs=ssl.CERT_REQUIRED) # Add server certificate verification + rawSSL.setblocking(0) # Non-blocking socket + self._ssl = SecuredWebSocketCore(rawSSL, self._host, self._port, self._AWSAccessKeyIDCustomConfig, self._AWSSecretAccessKeyCustomConfig, self._AWSSessionTokenCustomConfig) # Override the _ssl socket + # self._ssl.enableDebug() + elif self._alpn_protocols is not None: + # SSLContext is required to enable ALPN support + # Assuming Python 2.7.10+/3.5+ till the end of this elif branch + ssl_context = SSLContextBuilder()\ + .with_ca_certs(self._tls_ca_certs)\ + .with_cert_key_pair(self._tls_certfile, self._tls_keyfile)\ + .with_cert_reqs(self._tls_cert_reqs)\ + .with_check_hostname(True)\ + .with_ciphers(self._tls_ciphers)\ + .with_alpn_protocols(self._alpn_protocols)\ + .build() + self._ssl = ssl_context.wrap_socket(sock, server_hostname=self._host, do_handshake_on_connect=False) + verify_hostname = False # Since check_hostname in SSLContext is already set to True, no need to verify it again + self._ssl.do_handshake() + else: + self._ssl = ssl.wrap_socket( + sock, + certfile=self._tls_certfile, + keyfile=self._tls_keyfile, + ca_certs=self._tls_ca_certs, + cert_reqs=self._tls_cert_reqs, + ssl_version=self._tls_version, + ciphers=self._tls_ciphers) + + if verify_hostname: + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 5): # No IP host match before 3.5.x + self._tls_match_hostname() + else: + ssl.match_hostname(self._ssl.getpeercert(), self._host) + + self._sock = sock + + if self._ssl and not self._useSecuredWebsocket: + self._ssl.setblocking(0) # For X.509 cert mutual auth. + elif not self._ssl: + self._sock.setblocking(0) # For plain socket + else: + pass # For MQTT over WebSocket + + return self._send_connect(self._keepalive, self._clean_session) + + def loop(self, timeout=1.0, max_packets=1): + """Process network events. + + This function must be called regularly to ensure communication with the + broker is carried out. It calls select() on the network socket to wait + for network events. If incoming data is present it will then be + processed. Outgoing commands, from e.g. publish(), are normally sent + immediately that their function is called, but this is not always + possible. loop() will also attempt to send any remaining outgoing + messages, which also includes commands that are part of the flow for + messages with QoS>0. + + timeout: The time in seconds to wait for incoming/outgoing network + traffic before timing out and returning. + max_packets: Not currently used. + + Returns MQTT_ERR_SUCCESS on success. + Returns >0 on error. + + A ValueError will be raised if timeout < 0""" + if timeout < 0.0: + raise ValueError('Invalid timeout.') + + self._current_out_packet_mutex.acquire() + self._out_packet_mutex.acquire() + if self._current_out_packet is None and len(self._out_packet) > 0: + self._current_out_packet = self._out_packet.pop(0) + + if self._current_out_packet: + wlist = [self.socket()] + else: + wlist = [] + self._out_packet_mutex.release() + self._current_out_packet_mutex.release() + + # sockpairR is used to break out of select() before the timeout, on a + # call to publish() etc. + rlist = [self.socket(), self._sockpairR] + try: + socklist = select.select(rlist, wlist, [], timeout) + except TypeError as e: + # Socket isn't correct type, in likelihood connection is lost + return MQTT_ERR_CONN_LOST + except ValueError: + # Can occur if we just reconnected but rlist/wlist contain a -1 for + # some reason. + return MQTT_ERR_CONN_LOST + except: + return MQTT_ERR_UNKNOWN + + if self.socket() in socklist[0]: + rc = self.loop_read(max_packets) + if rc or (self._ssl is None and self._sock is None): + return rc + + if self._sockpairR in socklist[0]: + # Stimulate output write even though we didn't ask for it, because + # at that point the publish or other command wasn't present. + socklist[1].insert(0, self.socket()) + # Clear sockpairR - only ever a single byte written. + try: + self._sockpairR.recv(1) + except socket.error as err: + if err.errno != EAGAIN: + raise + + if self.socket() in socklist[1]: + rc = self.loop_write(max_packets) + if rc or (self._ssl is None and self._sock is None): + return rc + + return self.loop_misc() + + def publish(self, topic, payload=None, qos=0, retain=False): + """Publish a message on a topic. + + This causes a message to be sent to the broker and subsequently from + the broker to any clients subscribing to matching topics. + + topic: The topic that the message should be published on. + payload: The actual message to send. If not given, or set to None a + zero length message will be used. Passing an int or float will result + in the payload being converted to a string representing that number. If + you wish to send a true int/float, use struct.pack() to create the + payload you require. + qos: The quality of service level to use. + retain: If set to true, the message will be set as the "last known + good"/retained message for the topic. + + Returns a tuple (result, mid), where result is MQTT_ERR_SUCCESS to + indicate success or MQTT_ERR_NO_CONN if the client is not currently + connected. mid is the message ID for the publish request. The mid + value can be used to track the publish request by checking against the + mid argument in the on_publish() callback if it is defined. + + A ValueError will be raised if topic is None, has zero length or is + invalid (contains a wildcard), if qos is not one of 0, 1 or 2, or if + the length of the payload is greater than 268435455 bytes.""" + if topic is None or len(topic) == 0: + raise ValueError('Invalid topic.') + if qos<0 or qos>2: + raise ValueError('Invalid QoS level.') + if isinstance(payload, str) or isinstance(payload, bytearray): + local_payload = payload + elif sys.version_info[0] < 3 and isinstance(payload, unicode): + local_payload = payload + elif isinstance(payload, int) or isinstance(payload, float): + local_payload = str(payload) + elif payload is None: + local_payload = None + else: + raise TypeError('payload must be a string, bytearray, int, float or None.') + + if local_payload is not None and len(local_payload) > 268435455: + raise ValueError('Payload too large.') + + if self._topic_wildcard_len_check(topic) != MQTT_ERR_SUCCESS: + raise ValueError('Publish topic cannot contain wildcards.') + + local_mid = self._mid_generate() + + if qos == 0: + rc = self._send_publish(local_mid, topic, local_payload, qos, retain, False) + return (rc, local_mid) + else: + message = MQTTMessage() + message.timestamp = time.time() + + message.mid = local_mid + message.topic = topic + if local_payload is None or len(local_payload) == 0: + message.payload = None + else: + message.payload = local_payload + + message.qos = qos + message.retain = retain + message.dup = False + + self._out_message_mutex.acquire() + self._out_messages.append(message) + if self._max_inflight_messages == 0 or self._inflight_messages < self._max_inflight_messages: + self._inflight_messages = self._inflight_messages+1 + if qos == 1: + message.state = mqtt_ms_wait_for_puback + elif qos == 2: + message.state = mqtt_ms_wait_for_pubrec + self._out_message_mutex.release() + + rc = self._send_publish(message.mid, message.topic, message.payload, message.qos, message.retain, message.dup) + + # remove from inflight messages so it will be send after a connection is made + if rc is MQTT_ERR_NO_CONN: + with self._out_message_mutex: + self._inflight_messages -= 1 + message.state = mqtt_ms_publish + + return (rc, local_mid) + else: + message.state = mqtt_ms_queued; + self._out_message_mutex.release() + return (MQTT_ERR_SUCCESS, local_mid) + + def username_pw_set(self, username, password=None): + """Set a username and optionally a password for broker authentication. + + Must be called before connect() to have any effect. + Requires a broker that supports MQTT v3.1. + + username: The username to authenticate with. Need have no relationship to the client id. + password: The password to authenticate with. Optional, set to None if not required. + """ + self._username = username.encode('utf-8') + self._password = password + + def socket_factory_set(self, socket_factory): + """Set a socket factory to custom configure a different socket type for + mqtt connection. + Must be called before connect() to have any effect. + socket_factory: create_connection function which creates a socket to user's specification + """ + self._socket_factory = socket_factory + + def disconnect(self): + """Disconnect a connected client from the broker.""" + self._state_mutex.acquire() + self._state = mqtt_cs_disconnecting + self._state_mutex.release() + + self._backoffCore.stopStableConnectionTimer() + + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + return self._send_disconnect() + + def subscribe(self, topic, qos=0): + """Subscribe the client to one or more topics. + + This function may be called in three different ways: + + Simple string and integer + ------------------------- + e.g. subscribe("my/topic", 2) + + topic: A string specifying the subscription topic to subscribe to. + qos: The desired quality of service level for the subscription. + Defaults to 0. + + String and integer tuple + ------------------------ + e.g. subscribe(("my/topic", 1)) + + topic: A tuple of (topic, qos). Both topic and qos must be present in + the tuple. + qos: Not used. + + List of string and integer tuples + ------------------------ + e.g. subscribe([("my/topic", 0), ("another/topic", 2)]) + + This allows multiple topic subscriptions in a single SUBSCRIPTION + command, which is more efficient than using multiple calls to + subscribe(). + + topic: A list of tuple of format (topic, qos). Both topic and qos must + be present in all of the tuples. + qos: Not used. + + The function returns a tuple (result, mid), where result is + MQTT_ERR_SUCCESS to indicate success or (MQTT_ERR_NO_CONN, None) if the + client is not currently connected. mid is the message ID for the + subscribe request. The mid value can be used to track the subscribe + request by checking against the mid argument in the on_subscribe() + callback if it is defined. + + Raises a ValueError if qos is not 0, 1 or 2, or if topic is None or has + zero string length, or if topic is not a string, tuple or list. + """ + topic_qos_list = None + if isinstance(topic, str): + if qos<0 or qos>2: + raise ValueError('Invalid QoS level.') + if topic is None or len(topic) == 0: + raise ValueError('Invalid topic.') + topic_qos_list = [(topic.encode('utf-8'), qos)] + elif isinstance(topic, tuple): + if topic[1]<0 or topic[1]>2: + raise ValueError('Invalid QoS level.') + if topic[0] is None or len(topic[0]) == 0 or not isinstance(topic[0], str): + raise ValueError('Invalid topic.') + topic_qos_list = [(topic[0].encode('utf-8'), topic[1])] + elif isinstance(topic, list): + topic_qos_list = [] + for t in topic: + if t[1]<0 or t[1]>2: + raise ValueError('Invalid QoS level.') + if t[0] is None or len(t[0]) == 0 or not isinstance(t[0], str): + raise ValueError('Invalid topic.') + topic_qos_list.append((t[0].encode('utf-8'), t[1])) + + if topic_qos_list is None: + raise ValueError("No topic specified, or incorrect topic type.") + + if self._sock is None and self._ssl is None: + return (MQTT_ERR_NO_CONN, None) + + return self._send_subscribe(False, topic_qos_list) + + def unsubscribe(self, topic): + """Unsubscribe the client from one or more topics. + + topic: A single string, or list of strings that are the subscription + topics to unsubscribe from. + + Returns a tuple (result, mid), where result is MQTT_ERR_SUCCESS + to indicate success or (MQTT_ERR_NO_CONN, None) if the client is not + currently connected. + mid is the message ID for the unsubscribe request. The mid value can be + used to track the unsubscribe request by checking against the mid + argument in the on_unsubscribe() callback if it is defined. + + Raises a ValueError if topic is None or has zero string length, or is + not a string or list. + """ + topic_list = None + if topic is None: + raise ValueError('Invalid topic.') + if isinstance(topic, str): + if len(topic) == 0: + raise ValueError('Invalid topic.') + topic_list = [topic.encode('utf-8')] + elif isinstance(topic, list): + topic_list = [] + for t in topic: + if len(t) == 0 or not isinstance(t, str): + raise ValueError('Invalid topic.') + topic_list.append(t.encode('utf-8')) + + if topic_list is None: + raise ValueError("No topic specified, or incorrect topic type.") + + if self._sock is None and self._ssl is None: + return (MQTT_ERR_NO_CONN, None) + + return self._send_unsubscribe(False, topic_list) + + def loop_read(self, max_packets=1): + """Process read network events. Use in place of calling loop() if you + wish to handle your client reads as part of your own application. + + Use socket() to obtain the client socket to call select() or equivalent + on. + + Do not use if you are using the threaded interface loop_start().""" + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + max_packets = len(self._out_messages) + len(self._in_messages) + if max_packets < 1: + max_packets = 1 + + for i in range(0, max_packets): + rc = self._packet_read() + if rc > 0: + return self._loop_rc_handle(rc) + elif rc == MQTT_ERR_AGAIN: + return MQTT_ERR_SUCCESS + return MQTT_ERR_SUCCESS + + def loop_write(self, max_packets=1): + """Process read network events. Use in place of calling loop() if you + wish to handle your client reads as part of your own application. + + Use socket() to obtain the client socket to call select() or equivalent + on. + + Use want_write() to determine if there is data waiting to be written. + + Do not use if you are using the threaded interface loop_start().""" + + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + max_packets = len(self._out_packet) + 1 + if max_packets < 1: + max_packets = 1 + + for i in range(0, max_packets): + rc = self._packet_write() + if rc > 0: + return self._loop_rc_handle(rc) + elif rc == MQTT_ERR_AGAIN: + return MQTT_ERR_SUCCESS + return MQTT_ERR_SUCCESS + + def want_write(self): + """Call to determine if there is network data waiting to be written. + Useful if you are calling select() yourself rather than using loop(). + """ + if self._current_out_packet or len(self._out_packet) > 0: + return True + else: + return False + + def loop_misc(self): + """Process miscellaneous network events. Use in place of calling loop() if you + wish to call select() or equivalent on. + + Do not use if you are using the threaded interface loop_start().""" + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + now = time.time() + self._check_keepalive() + if self._last_retry_check+1 < now: + # Only check once a second at most + self._message_retry_check() + self._last_retry_check = now + + if self._ping_t > 0 and now - self._ping_t >= self._keepalive: + # client->ping_t != 0 means we are waiting for a pingresp. + # This hasn't happened in the keepalive time so we should disconnect. + if self._ssl: + self._ssl.close() + self._ssl = None + elif self._sock: + self._sock.close() + self._sock = None + + self._callback_mutex.acquire() + if self._state == mqtt_cs_disconnecting: + rc = MQTT_ERR_SUCCESS + else: + rc = 1 + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, rc) + self._in_callback = False + self._callback_mutex.release() + return MQTT_ERR_CONN_LOST + + return MQTT_ERR_SUCCESS + + def max_inflight_messages_set(self, inflight): + """Set the maximum number of messages with QoS>0 that can be part way + through their network flow at once. Defaults to 20.""" + if inflight < 0: + raise ValueError('Invalid inflight.') + self._max_inflight_messages = inflight + + def message_retry_set(self, retry): + """Set the timeout in seconds before a message with QoS>0 is retried. + 20 seconds by default.""" + if retry < 0: + raise ValueError('Invalid retry.') + + self._message_retry = retry + + def user_data_set(self, userdata): + """Set the user data variable passed to callbacks. May be any data type.""" + self._userdata = userdata + + def will_set(self, topic, payload=None, qos=0, retain=False): + """Set a Will to be sent by the broker in case the client disconnects unexpectedly. + + This must be called before connect() to have any effect. + + topic: The topic that the will message should be published on. + payload: The message to send as a will. If not given, or set to None a + zero length message will be used as the will. Passing an int or float + will result in the payload being converted to a string representing + that number. If you wish to send a true int/float, use struct.pack() to + create the payload you require. + qos: The quality of service level to use for the will. + retain: If set to true, the will message will be set as the "last known + good"/retained message for the topic. + + Raises a ValueError if qos is not 0, 1 or 2, or if topic is None or has + zero string length. + """ + if topic is None or len(topic) == 0: + raise ValueError('Invalid topic.') + if qos<0 or qos>2: + raise ValueError('Invalid QoS level.') + if isinstance(payload, str): + self._will_payload = payload.encode('utf-8') + elif isinstance(payload, bytearray): + self._will_payload = payload + elif isinstance(payload, int) or isinstance(payload, float): + self._will_payload = str(payload) + elif payload is None: + self._will_payload = None + else: + raise TypeError('payload must be a string, bytearray, int, float or None.') + + self._will = True + self._will_topic = topic.encode('utf-8') + self._will_qos = qos + self._will_retain = retain + + def will_clear(self): + """ Removes a will that was previously configured with will_set(). + + Must be called before connect() to have any effect.""" + self._will = False + self._will_topic = "" + self._will_payload = None + self._will_qos = 0 + self._will_retain = False + + def socket(self): + """Return the socket or ssl object for this client.""" + if self._ssl: + if self._useSecuredWebsocket: + return self._ssl.getSSLSocket() + else: + return self._ssl + else: + return self._sock + + def loop_forever(self, timeout=1.0, max_packets=1, retry_first_connection=False): + """This function call loop() for you in an infinite blocking loop. It + is useful for the case where you only want to run the MQTT client loop + in your program. + + loop_forever() will handle reconnecting for you. If you call + disconnect() in a callback it will return. + + + timeout: The time in seconds to wait for incoming/outgoing network + traffic before timing out and returning. + max_packets: Not currently used. + retry_first_connection: Should the first connection attempt be retried on failure. + + Raises socket.error on first connection failures unless retry_first_connection=True + """ + + run = True + + while run: + if self._state == mqtt_cs_connect_async: + try: + self.reconnect() + except socket.error: + if not retry_first_connection: + raise + self._easy_log(MQTT_LOG_DEBUG, "Connection failed, retrying") + self._backoffCore.backOff() + # time.sleep(1) + else: + break + + while run: + rc = MQTT_ERR_SUCCESS + while rc == MQTT_ERR_SUCCESS: + rc = self.loop(timeout, max_packets) + # We don't need to worry about locking here, because we've + # either called loop_forever() when in single threaded mode, or + # in multi threaded mode when loop_stop() has been called and + # so no other threads can access _current_out_packet, + # _out_packet or _messages. + if (self._thread_terminate is True + and self._current_out_packet is None + and len(self._out_packet) == 0 + and len(self._out_messages) == 0): + + rc = 1 + run = False + + self._state_mutex.acquire() + if self._state == mqtt_cs_disconnecting or run is False or self._thread_terminate is True: + run = False + self._state_mutex.release() + else: + self._state_mutex.release() + self._backoffCore.backOff() + # time.sleep(1) + + self._state_mutex.acquire() + if self._state == mqtt_cs_disconnecting or run is False or self._thread_terminate is True: + run = False + self._state_mutex.release() + else: + self._state_mutex.release() + try: + self.reconnect() + except socket.error as err: + pass + + return rc + + def loop_start(self): + """This is part of the threaded client interface. Call this once to + start a new thread to process network traffic. This provides an + alternative to repeatedly calling loop() yourself. + """ + if self._thread is not None: + return MQTT_ERR_INVAL + + self._thread_terminate = False + self._thread = threading.Thread(target=self._thread_main) + self._thread.daemon = True + self._thread.start() + + def loop_stop(self, force=False): + """This is part of the threaded client interface. Call this once to + stop the network thread previously created with loop_start(). This call + will block until the network thread finishes. + + The force parameter is currently ignored. + """ + if self._thread is None: + return MQTT_ERR_INVAL + + self._thread_terminate = True + self._thread.join() + self._thread = None + + def message_callback_add(self, sub, callback): + """Register a message callback for a specific topic. + Messages that match 'sub' will be passed to 'callback'. Any + non-matching messages will be passed to the default on_message + callback. + + Call multiple times with different 'sub' to define multiple topic + specific callbacks. + + Topic specific callbacks may be removed with + message_callback_remove().""" + if callback is None or sub is None: + raise ValueError("sub and callback must both be defined.") + + self._callback_mutex.acquire() + for i in range(0, len(self.on_message_filtered)): + if self.on_message_filtered[i][0] == sub: + self.on_message_filtered[i] = (sub, callback) + self._callback_mutex.release() + return + + self.on_message_filtered.append((sub, callback)) + self._callback_mutex.release() + + def message_callback_remove(self, sub): + """Remove a message callback previously registered with + message_callback_add().""" + if sub is None: + raise ValueError("sub must defined.") + + self._callback_mutex.acquire() + for i in range(0, len(self.on_message_filtered)): + if self.on_message_filtered[i][0] == sub: + self.on_message_filtered.pop(i) + self._callback_mutex.release() + return + self._callback_mutex.release() + + # ============================================================ + # Private functions + # ============================================================ + + def _loop_rc_handle(self, rc): + if rc: + if self._ssl: + self._ssl.close() + self._ssl = None + elif self._sock: + self._sock.close() + self._sock = None + + self._state_mutex.acquire() + if self._state == mqtt_cs_disconnecting: + rc = MQTT_ERR_SUCCESS + self._state_mutex.release() + self._callback_mutex.acquire() + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, rc) + self._in_callback = False + + self._callback_mutex.release() + return rc + + def _packet_read(self): + # This gets called if pselect() indicates that there is network data + # available - ie. at least one byte. What we do depends on what data we + # already have. + # If we've not got a command, attempt to read one and save it. This should + # always work because it's only a single byte. + # Then try to read the remaining length. This may fail because it is may + # be more than one byte - will need to save data pending next read if it + # does fail. + # Then try to read the remaining payload, where 'payload' here means the + # combined variable header and actual payload. This is the most likely to + # fail due to longer length, so save current data and current position. + # After all data is read, send to _mqtt_handle_packet() to deal with. + # Finally, free the memory and reset everything to starting conditions. + if self._in_packet['command'] == 0: + try: + if self._ssl: + command = self._ssl.read(1) + else: + command = self._sock.recv(1) + except socket.error as err: + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + else: + if len(command) == 0: + return 1 + command = struct.unpack("!B", command) + self._in_packet['command'] = command[0] + + if self._in_packet['have_remaining'] == 0: + # Read remaining + # Algorithm for decoding taken from pseudo code at + # http://publib.boulder.ibm.com/infocenter/wmbhelp/v6r0m0/topic/com.ibm.etools.mft.doc/ac10870_.htm + while True: + try: + if self._ssl: + byte = self._ssl.read(1) + else: + byte = self._sock.recv(1) + except socket.error as err: + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + else: + byte = struct.unpack("!B", byte) + byte = byte[0] + self._in_packet['remaining_count'].append(byte) + # Max 4 bytes length for remaining length as defined by protocol. + # Anything more likely means a broken/malicious client. + if len(self._in_packet['remaining_count']) > 4: + return MQTT_ERR_PROTOCOL + + self._in_packet['remaining_length'] = self._in_packet['remaining_length'] + (byte & 127)*self._in_packet['remaining_mult'] + self._in_packet['remaining_mult'] = self._in_packet['remaining_mult'] * 128 + + if (byte & 128) == 0: + break + + self._in_packet['have_remaining'] = 1 + self._in_packet['to_process'] = self._in_packet['remaining_length'] + + while self._in_packet['to_process'] > 0: + try: + if self._ssl: + data = self._ssl.read(self._in_packet['to_process']) + else: + data = self._sock.recv(self._in_packet['to_process']) + except socket.error as err: + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + else: + self._in_packet['to_process'] = self._in_packet['to_process'] - len(data) + self._in_packet['packet'] = self._in_packet['packet'] + data + + # All data for this packet is read. + self._in_packet['pos'] = 0 + rc = self._packet_handle() + + # Free data and reset values + self._in_packet = dict( + command=0, + have_remaining=0, + remaining_count=[], + remaining_mult=1, + remaining_length=0, + packet=b"", + to_process=0, + pos=0) + + self._msgtime_mutex.acquire() + self._last_msg_in = time.time() + self._msgtime_mutex.release() + return rc + + def _packet_write(self): + self._current_out_packet_mutex.acquire() + while self._current_out_packet: + packet = self._current_out_packet + + try: + if self._ssl: + write_length = self._ssl.write(packet['packet'][packet['pos']:]) + else: + write_length = self._sock.send(packet['packet'][packet['pos']:]) + except AttributeError: + self._current_out_packet_mutex.release() + return MQTT_ERR_SUCCESS + except socket.error as err: + self._current_out_packet_mutex.release() + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + + if write_length > 0: + packet['to_process'] = packet['to_process'] - write_length + packet['pos'] = packet['pos'] + write_length + + if packet['to_process'] == 0: + if (packet['command'] & 0xF0) == PUBLISH and packet['qos'] == 0: + self._callback_mutex.acquire() + if self.on_publish: + self._in_callback = True + self.on_publish(self, self._userdata, packet['mid']) + self._in_callback = False + + self._callback_mutex.release() + + if (packet['command'] & 0xF0) == DISCONNECT: + self._current_out_packet_mutex.release() + + self._msgtime_mutex.acquire() + self._last_msg_out = time.time() + self._msgtime_mutex.release() + + self._callback_mutex.acquire() + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, 0) + self._in_callback = False + self._callback_mutex.release() + + if self._ssl: + self._ssl.close() + self._ssl = None + if self._sock: + self._sock.close() + self._sock = None + return MQTT_ERR_SUCCESS + + self._out_packet_mutex.acquire() + if len(self._out_packet) > 0: + self._current_out_packet = self._out_packet.pop(0) + else: + self._current_out_packet = None + self._out_packet_mutex.release() + else: + pass # FIXME + + self._current_out_packet_mutex.release() + + self._msgtime_mutex.acquire() + self._last_msg_out = time.time() + self._msgtime_mutex.release() + return MQTT_ERR_SUCCESS + + def _easy_log(self, level, buf): + if self.on_log: + self.on_log(self, self._userdata, level, buf) + + def _check_keepalive(self): + now = time.time() + self._msgtime_mutex.acquire() + last_msg_out = self._last_msg_out + last_msg_in = self._last_msg_in + self._msgtime_mutex.release() + if (self._sock is not None or self._ssl is not None) and (now - last_msg_out >= self._keepalive or now - last_msg_in >= self._keepalive): + if self._state == mqtt_cs_connected and self._ping_t == 0: + self._send_pingreq() + self._msgtime_mutex.acquire() + self._last_msg_out = now + self._last_msg_in = now + self._msgtime_mutex.release() + else: + if self._ssl: + self._ssl.close() + self._ssl = None + elif self._sock: + self._sock.close() + self._sock = None + + if self._state == mqtt_cs_disconnecting: + rc = MQTT_ERR_SUCCESS + else: + rc = 1 + self._callback_mutex.acquire() + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, rc) + self._in_callback = False + self._callback_mutex.release() + + def _mid_generate(self): + self._last_mid = self._last_mid + 1 + if self._last_mid == 65536: + self._last_mid = 1 + return self._last_mid + + def _topic_wildcard_len_check(self, topic): + # Search for + or # in a topic. Return MQTT_ERR_INVAL if found. + # Also returns MQTT_ERR_INVAL if the topic string is too long. + # Returns MQTT_ERR_SUCCESS if everything is fine. + if '+' in topic or '#' in topic or len(topic) == 0 or len(topic) > 65535: + return MQTT_ERR_INVAL + else: + return MQTT_ERR_SUCCESS + + def _send_pingreq(self): + self._easy_log(MQTT_LOG_DEBUG, "Sending PINGREQ") + rc = self._send_simple_command(PINGREQ) + if rc == MQTT_ERR_SUCCESS: + self._ping_t = time.time() + return rc + + def _send_pingresp(self): + self._easy_log(MQTT_LOG_DEBUG, "Sending PINGRESP") + return self._send_simple_command(PINGRESP) + + def _send_puback(self, mid): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBACK (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBACK, mid, False) + + def _send_pubcomp(self, mid): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBCOMP (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBCOMP, mid, False) + + def _pack_remaining_length(self, packet, remaining_length): + remaining_bytes = [] + while True: + byte = remaining_length % 128 + remaining_length = remaining_length // 128 + # If there are more digits to encode, set the top bit of this digit + if remaining_length > 0: + byte = byte | 0x80 + + remaining_bytes.append(byte) + packet.extend(struct.pack("!B", byte)) + if remaining_length == 0: + # FIXME - this doesn't deal with incorrectly large payloads + return packet + + def _pack_str16(self, packet, data): + if sys.version_info[0] < 3: + if isinstance(data, bytearray): + packet.extend(struct.pack("!H", len(data))) + packet.extend(data) + elif isinstance(data, str): + udata = data.encode('utf-8') + pack_format = "!H" + str(len(udata)) + "s" + packet.extend(struct.pack(pack_format, len(udata), udata)) + elif isinstance(data, unicode): + udata = data.encode('utf-8') + pack_format = "!H" + str(len(udata)) + "s" + packet.extend(struct.pack(pack_format, len(udata), udata)) + else: + raise TypeError + else: + if isinstance(data, bytearray) or isinstance(data, bytes): + packet.extend(struct.pack("!H", len(data))) + packet.extend(data) + elif isinstance(data, str): + udata = data.encode('utf-8') + pack_format = "!H" + str(len(udata)) + "s" + packet.extend(struct.pack(pack_format, len(udata), udata)) + else: + raise TypeError + + def _send_publish(self, mid, topic, payload=None, qos=0, retain=False, dup=False): + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + utopic = topic.encode('utf-8') + command = PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain + packet = bytearray() + packet.extend(struct.pack("!B", command)) + if payload is None: + remaining_length = 2+len(utopic) + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBLISH (d"+str(dup)+", q"+str(qos)+", r"+str(int(retain))+", m"+str(mid)+", '"+topic+"' (NULL payload)") + else: + if isinstance(payload, str): + upayload = payload.encode('utf-8') + payloadlen = len(upayload) + elif isinstance(payload, bytearray): + payloadlen = len(payload) + elif isinstance(payload, unicode): + upayload = payload.encode('utf-8') + payloadlen = len(upayload) + + remaining_length = 2+len(utopic) + payloadlen + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBLISH (d"+str(dup)+", q"+str(qos)+", r"+str(int(retain))+", m"+str(mid)+", '"+topic+"', ... ("+str(payloadlen)+" bytes)") + + if qos > 0: + # For message id + remaining_length = remaining_length + 2 + + self._pack_remaining_length(packet, remaining_length) + self._pack_str16(packet, topic) + + if qos > 0: + # For message id + packet.extend(struct.pack("!H", mid)) + + if payload is not None: + if isinstance(payload, str): + pack_format = str(payloadlen) + "s" + packet.extend(struct.pack(pack_format, upayload)) + elif isinstance(payload, bytearray): + packet.extend(payload) + elif isinstance(payload, unicode): + pack_format = str(payloadlen) + "s" + packet.extend(struct.pack(pack_format, upayload)) + else: + raise TypeError('payload must be a string, unicode or a bytearray.') + + return self._packet_queue(PUBLISH, packet, mid, qos) + + def _send_pubrec(self, mid): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBREC (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBREC, mid, False) + + def _send_pubrel(self, mid, dup=False): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBREL (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBREL|2, mid, dup) + + def _send_command_with_mid(self, command, mid, dup): + # For PUBACK, PUBCOMP, PUBREC, and PUBREL + if dup: + command = command | 8 + + remaining_length = 2 + packet = struct.pack('!BBH', command, remaining_length, mid) + return self._packet_queue(command, packet, mid, 1) + + def _send_simple_command(self, command): + # For DISCONNECT, PINGREQ and PINGRESP + remaining_length = 0 + packet = struct.pack('!BB', command, remaining_length) + return self._packet_queue(command, packet, 0, 0) + + def _send_connect(self, keepalive, clean_session): + if self._protocol == MQTTv31: + protocol = PROTOCOL_NAMEv31 + proto_ver = 3 + else: + protocol = PROTOCOL_NAMEv311 + proto_ver = 4 + remaining_length = 2+len(protocol) + 1+1+2 + 2+len(self._client_id) + connect_flags = 0 + if clean_session: + connect_flags = connect_flags | 0x02 + + if self._will: + if self._will_payload is not None: + remaining_length = remaining_length + 2+len(self._will_topic) + 2+len(self._will_payload) + else: + remaining_length = remaining_length + 2+len(self._will_topic) + 2 + + connect_flags = connect_flags | 0x04 | ((self._will_qos&0x03) << 3) | ((self._will_retain&0x01) << 5) + + if self._username: + remaining_length = remaining_length + 2+len(self._username) + connect_flags = connect_flags | 0x80 + if self._password: + connect_flags = connect_flags | 0x40 + remaining_length = remaining_length + 2+len(self._password) + + command = CONNECT + packet = bytearray() + packet.extend(struct.pack("!B", command)) + + self._pack_remaining_length(packet, remaining_length) + packet.extend(struct.pack("!H"+str(len(protocol))+"sBBH", len(protocol), protocol, proto_ver, connect_flags, keepalive)) + + self._pack_str16(packet, self._client_id) + + if self._will: + self._pack_str16(packet, self._will_topic) + if self._will_payload is None or len(self._will_payload) == 0: + packet.extend(struct.pack("!H", 0)) + else: + self._pack_str16(packet, self._will_payload) + + if self._username: + self._pack_str16(packet, self._username) + + if self._password: + self._pack_str16(packet, self._password) + + self._keepalive = keepalive + return self._packet_queue(command, packet, 0, 0) + + def _send_disconnect(self): + return self._send_simple_command(DISCONNECT) + + def _send_subscribe(self, dup, topics): + remaining_length = 2 + for t in topics: + remaining_length = remaining_length + 2+len(t[0])+1 + + command = SUBSCRIBE | (dup<<3) | (1<<1) + packet = bytearray() + packet.extend(struct.pack("!B", command)) + self._pack_remaining_length(packet, remaining_length) + local_mid = self._mid_generate() + packet.extend(struct.pack("!H", local_mid)) + for t in topics: + self._pack_str16(packet, t[0]) + packet.extend(struct.pack("B", t[1])) + return (self._packet_queue(command, packet, local_mid, 1), local_mid) + + def _send_unsubscribe(self, dup, topics): + remaining_length = 2 + for t in topics: + remaining_length = remaining_length + 2+len(t) + + command = UNSUBSCRIBE | (dup<<3) | (1<<1) + packet = bytearray() + packet.extend(struct.pack("!B", command)) + self._pack_remaining_length(packet, remaining_length) + local_mid = self._mid_generate() + packet.extend(struct.pack("!H", local_mid)) + for t in topics: + self._pack_str16(packet, t) + return (self._packet_queue(command, packet, local_mid, 1), local_mid) + + def _message_retry_check_actual(self, messages, mutex): + mutex.acquire() + now = time.time() + for m in messages: + if m.timestamp + self._message_retry < now: + if m.state == mqtt_ms_wait_for_puback or m.state == mqtt_ms_wait_for_pubrec: + m.timestamp = now + m.dup = True + self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + elif m.state == mqtt_ms_wait_for_pubrel: + m.timestamp = now + m.dup = True + self._send_pubrec(m.mid) + elif m.state == mqtt_ms_wait_for_pubcomp: + m.timestamp = now + m.dup = True + self._send_pubrel(m.mid, True) + mutex.release() + + def _message_retry_check(self): + self._message_retry_check_actual(self._out_messages, self._out_message_mutex) + self._message_retry_check_actual(self._in_messages, self._in_message_mutex) + + def _messages_reconnect_reset_out(self): + self._out_message_mutex.acquire() + self._inflight_messages = 0 + for m in self._out_messages: + m.timestamp = 0 + if self._max_inflight_messages == 0 or self._inflight_messages < self._max_inflight_messages: + if m.qos == 0: + m.state = mqtt_ms_publish + elif m.qos == 1: + #self._inflight_messages = self._inflight_messages + 1 + if m.state == mqtt_ms_wait_for_puback: + m.dup = True + m.state = mqtt_ms_publish + elif m.qos == 2: + #self._inflight_messages = self._inflight_messages + 1 + if m.state == mqtt_ms_wait_for_pubcomp: + m.state = mqtt_ms_resend_pubrel + m.dup = True + else: + if m.state == mqtt_ms_wait_for_pubrec: + m.dup = True + m.state = mqtt_ms_publish + else: + m.state = mqtt_ms_queued + self._out_message_mutex.release() + + def _messages_reconnect_reset_in(self): + self._in_message_mutex.acquire() + for m in self._in_messages: + m.timestamp = 0 + if m.qos != 2: + self._in_messages.pop(self._in_messages.index(m)) + else: + # Preserve current state + pass + self._in_message_mutex.release() + + def _messages_reconnect_reset(self): + self._messages_reconnect_reset_out() + self._messages_reconnect_reset_in() + + def _packet_queue(self, command, packet, mid, qos): + mpkt = dict( + command = command, + mid = mid, + qos = qos, + pos = 0, + to_process = len(packet), + packet = packet) + + self._out_packet_mutex.acquire() + self._out_packet.append(mpkt) + if self._current_out_packet_mutex.acquire(False): + if self._current_out_packet is None and len(self._out_packet) > 0: + self._current_out_packet = self._out_packet.pop(0) + self._current_out_packet_mutex.release() + self._out_packet_mutex.release() + + # Write a single byte to sockpairW (connected to sockpairR) to break + # out of select() if in threaded mode. + try: + self._sockpairW.send(sockpair_data) + except socket.error as err: + if err.errno != EAGAIN: + raise + + if not self._in_callback and self._thread is None: + return self.loop_write() + else: + return MQTT_ERR_SUCCESS + + def _packet_handle(self): + cmd = self._in_packet['command']&0xF0 + if cmd == PINGREQ: + return self._handle_pingreq() + elif cmd == PINGRESP: + return self._handle_pingresp() + elif cmd == PUBACK: + return self._handle_pubackcomp("PUBACK") + elif cmd == PUBCOMP: + return self._handle_pubackcomp("PUBCOMP") + elif cmd == PUBLISH: + return self._handle_publish() + elif cmd == PUBREC: + return self._handle_pubrec() + elif cmd == PUBREL: + return self._handle_pubrel() + elif cmd == CONNACK: + return self._handle_connack() + elif cmd == SUBACK: + return self._handle_suback() + elif cmd == UNSUBACK: + return self._handle_unsuback() + else: + # If we don't recognise the command, return an error straight away. + self._easy_log(MQTT_LOG_ERR, "Error: Unrecognised command "+str(cmd)) + return MQTT_ERR_PROTOCOL + + def _handle_pingreq(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 0: + return MQTT_ERR_PROTOCOL + + self._easy_log(MQTT_LOG_DEBUG, "Received PINGREQ") + return self._send_pingresp() + + def _handle_pingresp(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 0: + return MQTT_ERR_PROTOCOL + + # No longer waiting for a PINGRESP. + self._ping_t = 0 + self._easy_log(MQTT_LOG_DEBUG, "Received PINGRESP") + return MQTT_ERR_SUCCESS + + def _handle_connack(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + if len(self._in_packet['packet']) != 2: + return MQTT_ERR_PROTOCOL + + (flags, result) = struct.unpack("!BB", self._in_packet['packet']) + if result == CONNACK_REFUSED_PROTOCOL_VERSION and self._protocol == MQTTv311: + self._easy_log(MQTT_LOG_DEBUG, "Received CONNACK ("+str(flags)+", "+str(result)+"), attempting downgrade to MQTT v3.1.") + # Downgrade to MQTT v3.1 + self._protocol = MQTTv31 + return self.reconnect() + + if result == 0: + self._state = mqtt_cs_connected + + self._easy_log(MQTT_LOG_DEBUG, "Received CONNACK ("+str(flags)+", "+str(result)+")") + self._callback_mutex.acquire() + if self.on_connect: + self._in_callback = True + + if sys.version_info[0] < 3: + argcount = self.on_connect.func_code.co_argcount + else: + argcount = self.on_connect.__code__.co_argcount + + if argcount == 3: + self.on_connect(self, self._userdata, result) + else: + flags_dict = dict() + flags_dict['session present'] = flags & 0x01 + self.on_connect(self, self._userdata, flags_dict, result) + self._in_callback = False + self._callback_mutex.release() + + # Start counting for stable connection + self._backoffCore.startStableConnectionTimer() + + if result == 0: + rc = 0 + self._out_message_mutex.acquire() + for m in self._out_messages: + m.timestamp = time.time() + if m.state == mqtt_ms_queued: + self.loop_write() # Process outgoing messages that have just been queued up + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + + if m.qos == 0: + self._in_callback = True # Don't call loop_write after _send_publish() + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + elif m.qos == 1: + if m.state == mqtt_ms_publish: + self._inflight_messages = self._inflight_messages + 1 + m.state = mqtt_ms_wait_for_puback + self._in_callback = True # Don't call loop_write after _send_publish() + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + elif m.qos == 2: + if m.state == mqtt_ms_publish: + self._inflight_messages = self._inflight_messages + 1 + m.state = mqtt_ms_wait_for_pubrec + self._in_callback = True # Don't call loop_write after _send_publish() + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + elif m.state == mqtt_ms_resend_pubrel: + self._inflight_messages = self._inflight_messages + 1 + m.state = mqtt_ms_wait_for_pubcomp + self._in_callback = True # Don't call loop_write after _send_pubrel() + rc = self._send_pubrel(m.mid, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + self.loop_write() # Process outgoing messages that have just been queued up + self._out_message_mutex.release() + return rc + elif result > 0 and result < 6: + return MQTT_ERR_CONN_REFUSED + else: + return MQTT_ERR_PROTOCOL + + def _handle_suback(self): + self._easy_log(MQTT_LOG_DEBUG, "Received SUBACK") + pack_format = "!H" + str(len(self._in_packet['packet'])-2) + 's' + (mid, packet) = struct.unpack(pack_format, self._in_packet['packet']) + pack_format = "!" + "B"*len(packet) + granted_qos = struct.unpack(pack_format, packet) + + self._callback_mutex.acquire() + if self.on_subscribe: + self._in_callback = True + self.on_subscribe(self, self._userdata, mid, granted_qos) + self._in_callback = False + self._callback_mutex.release() + + return MQTT_ERR_SUCCESS + + def _handle_publish(self): + rc = 0 + + header = self._in_packet['command'] + message = MQTTMessage() + message.dup = (header & 0x08)>>3 + message.qos = (header & 0x06)>>1 + message.retain = (header & 0x01) + + pack_format = "!H" + str(len(self._in_packet['packet'])-2) + 's' + (slen, packet) = struct.unpack(pack_format, self._in_packet['packet']) + pack_format = '!' + str(slen) + 's' + str(len(packet)-slen) + 's' + (message.topic, packet) = struct.unpack(pack_format, packet) + + if len(message.topic) == 0: + return MQTT_ERR_PROTOCOL + + if sys.version_info[0] >= 3: + message.topic = message.topic.decode('utf-8') + + if message.qos > 0: + pack_format = "!H" + str(len(packet)-2) + 's' + (message.mid, packet) = struct.unpack(pack_format, packet) + + message.payload = packet + + self._easy_log( + MQTT_LOG_DEBUG, + "Received PUBLISH (d"+str(message.dup)+ + ", q"+str(message.qos)+", r"+str(message.retain)+ + ", m"+str(message.mid)+", '"+message.topic+ + "', ... ("+str(len(message.payload))+" bytes)") + + message.timestamp = time.time() + if message.qos == 0: + self._handle_on_message(message) + return MQTT_ERR_SUCCESS + elif message.qos == 1: + rc = self._send_puback(message.mid) + self._handle_on_message(message) + return rc + elif message.qos == 2: + rc = self._send_pubrec(message.mid) + message.state = mqtt_ms_wait_for_pubrel + self._in_message_mutex.acquire() + self._in_messages.append(message) + self._in_message_mutex.release() + return rc + else: + return MQTT_ERR_PROTOCOL + + def _handle_pubrel(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + if len(self._in_packet['packet']) != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received PUBREL (Mid: "+str(mid)+")") + + self._in_message_mutex.acquire() + for i in range(len(self._in_messages)): + if self._in_messages[i].mid == mid: + + # Only pass the message on if we have removed it from the queue - this + # prevents multiple callbacks for the same message. + self._handle_on_message(self._in_messages[i]) + self._in_messages.pop(i) + self._inflight_messages = self._inflight_messages - 1 + if self._max_inflight_messages > 0: + self._out_message_mutex.acquire() + rc = self._update_inflight() + self._out_message_mutex.release() + if rc != MQTT_ERR_SUCCESS: + self._in_message_mutex.release() + return rc + + self._in_message_mutex.release() + return self._send_pubcomp(mid) + + self._in_message_mutex.release() + return MQTT_ERR_SUCCESS + + def _update_inflight(self): + # Dont lock message_mutex here + for m in self._out_messages: + if self._inflight_messages < self._max_inflight_messages: + if m.qos > 0 and m.state == mqtt_ms_queued: + self._inflight_messages = self._inflight_messages + 1 + if m.qos == 1: + m.state = mqtt_ms_wait_for_puback + elif m.qos == 2: + m.state = mqtt_ms_wait_for_pubrec + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + if rc != 0: + return rc + else: + return MQTT_ERR_SUCCESS + return MQTT_ERR_SUCCESS + + def _handle_pubrec(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received PUBREC (Mid: "+str(mid)+")") + + self._out_message_mutex.acquire() + for m in self._out_messages: + if m.mid == mid: + m.state = mqtt_ms_wait_for_pubcomp + m.timestamp = time.time() + self._out_message_mutex.release() + return self._send_pubrel(mid, False) + + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + + def _handle_unsuback(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received UNSUBACK (Mid: "+str(mid)+")") + self._callback_mutex.acquire() + if self.on_unsubscribe: + self._in_callback = True + self.on_unsubscribe(self, self._userdata, mid) + self._in_callback = False + self._callback_mutex.release() + return MQTT_ERR_SUCCESS + + def _handle_pubackcomp(self, cmd): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received "+cmd+" (Mid: "+str(mid)+")") + + self._out_message_mutex.acquire() + for i in range(len(self._out_messages)): + try: + if self._out_messages[i].mid == mid: + # Only inform the client the message has been sent once. + self._callback_mutex.acquire() + if self.on_publish: + self._out_message_mutex.release() + self._in_callback = True + self.on_publish(self, self._userdata, mid) + self._in_callback = False + self._out_message_mutex.acquire() + + self._callback_mutex.release() + self._out_messages.pop(i) + self._inflight_messages = self._inflight_messages - 1 + if self._max_inflight_messages > 0: + rc = self._update_inflight() + if rc != MQTT_ERR_SUCCESS: + self._out_message_mutex.release() + return rc + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + except IndexError: + # Have removed item so i>count. + # Not really an error. + pass + + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + + def _handle_on_message(self, message): + self._callback_mutex.acquire() + matched = False + for t in self.on_message_filtered: + if topic_matches_sub(t[0], message.topic): + self._in_callback = True + t[1](self, self._userdata, message) + self._in_callback = False + matched = True + + if matched == False and self.on_message: + self._in_callback = True + self.on_message(self, self._userdata, message) + self._in_callback = False + + self._callback_mutex.release() + + def _thread_main(self): + self._state_mutex.acquire() + if self._state == mqtt_cs_connect_async: + self._state_mutex.release() + self.reconnect() + else: + self._state_mutex.release() + + self.loop_forever() + + def _host_matches_cert(self, host, cert_host): + if cert_host[0:2] == "*.": + if cert_host.count("*") != 1: + return False + + host_match = host.split(".", 1)[1] + cert_match = cert_host.split(".", 1)[1] + if host_match == cert_match: + return True + else: + return False + else: + if host == cert_host: + return True + else: + return False + + def _tls_match_hostname(self): + try: + cert = self._ssl.getpeercert() + except AttributeError: + # the getpeercert can throw Attribute error: object has no attribute 'peer_certificate' + # Don't let that crash the whole client. See also: http://bugs.python.org/issue13721 + raise ssl.SSLError('Not connected') + + san = cert.get('subjectAltName') + if san: + have_san_dns = False + for (key, value) in san: + if key == 'DNS': + have_san_dns = True + if self._host_matches_cert(self._host.lower(), value.lower()) == True: + return + if key == 'IP Address': + have_san_dns = True + if value.lower().strip() == self._host.lower().strip(): + return + + if have_san_dns: + # Only check subject if subjectAltName dns not found. + raise ssl.SSLError('Certificate subject does not match remote hostname.') + subject = cert.get('subject') + if subject: + for ((key, value),) in subject: + if key == 'commonName': + if self._host_matches_cert(self._host.lower(), value.lower()) == True: + return + + raise ssl.SSLError('Certificate subject does not match remote hostname.') + + +# Compatibility class for easy porting from mosquitto.py. +class Mosquitto(Client): + def __init__(self, client_id="", clean_session=True, userdata=None): + super(Mosquitto, self).__init__(client_id, clean_session, userdata) diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/deviceShadow.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/deviceShadow.py new file mode 100644 index 0000000..f58240a --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/deviceShadow.py @@ -0,0 +1,430 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import json +import logging +import uuid +from threading import Timer, Lock, Thread + + +class _shadowRequestToken: + + URN_PREFIX_LENGTH = 9 + + def getNextToken(self): + return uuid.uuid4().urn[self.URN_PREFIX_LENGTH:] # We only need the uuid digits, not the urn prefix + + +class _basicJSONParser: + + def setString(self, srcString): + self._rawString = srcString + self._dictionObject = None + + def regenerateString(self): + return json.dumps(self._dictionaryObject) + + def getAttributeValue(self, srcAttributeKey): + return self._dictionaryObject.get(srcAttributeKey) + + def setAttributeValue(self, srcAttributeKey, srcAttributeValue): + self._dictionaryObject[srcAttributeKey] = srcAttributeValue + + def validateJSON(self): + try: + self._dictionaryObject = json.loads(self._rawString) + except ValueError: + return False + return True + + +class deviceShadow: + _logger = logging.getLogger(__name__) + + def __init__(self, srcShadowName, srcIsPersistentSubscribe, srcShadowManager): + """ + + The class that denotes a local/client-side device shadow instance. + + Users can perform shadow operations on this instance to retrieve and modify the + corresponding shadow JSON document in AWS IoT Cloud. The following shadow operations + are available: + + - Get + + - Update + + - Delete + + - Listen on delta + + - Cancel listening on delta + + This is returned from :code:`AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTShadowClient.createShadowWithName` function call. + No need to call directly from user scripts. + + """ + if srcShadowName is None or srcIsPersistentSubscribe is None or srcShadowManager is None: + raise TypeError("None type inputs detected.") + self._shadowName = srcShadowName + # Tool handler + self._shadowManagerHandler = srcShadowManager + self._basicJSONParserHandler = _basicJSONParser() + self._tokenHandler = _shadowRequestToken() + # Properties + self._isPersistentSubscribe = srcIsPersistentSubscribe + self._lastVersionInSync = -1 # -1 means not initialized + self._isGetSubscribed = False + self._isUpdateSubscribed = False + self._isDeleteSubscribed = False + self._shadowSubscribeCallbackTable = dict() + self._shadowSubscribeCallbackTable["get"] = None + self._shadowSubscribeCallbackTable["delete"] = None + self._shadowSubscribeCallbackTable["update"] = None + self._shadowSubscribeCallbackTable["delta"] = None + self._shadowSubscribeStatusTable = dict() + self._shadowSubscribeStatusTable["get"] = 0 + self._shadowSubscribeStatusTable["delete"] = 0 + self._shadowSubscribeStatusTable["update"] = 0 + self._tokenPool = dict() + self._dataStructureLock = Lock() + + def _doNonPersistentUnsubscribe(self, currentAction): + self._shadowManagerHandler.basicShadowUnsubscribe(self._shadowName, currentAction) + self._logger.info("Unsubscribed to " + currentAction + " accepted/rejected topics for deviceShadow: " + self._shadowName) + + def generalCallback(self, client, userdata, message): + # In Py3.x, message.payload comes in as a bytes(string) + # json.loads needs a string input + with self._dataStructureLock: + currentTopic = message.topic + currentAction = self._parseTopicAction(currentTopic) # get/delete/update/delta + currentType = self._parseTopicType(currentTopic) # accepted/rejected/delta + payloadUTF8String = message.payload.decode('utf-8') + # get/delete/update: Need to deal with token, timer and unsubscribe + if currentAction in ["get", "delete", "update"]: + # Check for token + self._basicJSONParserHandler.setString(payloadUTF8String) + if self._basicJSONParserHandler.validateJSON(): # Filter out invalid JSON + currentToken = self._basicJSONParserHandler.getAttributeValue(u"clientToken") + if currentToken is not None: + self._logger.debug("shadow message clientToken: " + currentToken) + if currentToken is not None and currentToken in self._tokenPool.keys(): # Filter out JSON without the desired token + # Sync local version when it is an accepted response + self._logger.debug("Token is in the pool. Type: " + currentType) + if currentType == "accepted": + incomingVersion = self._basicJSONParserHandler.getAttributeValue(u"version") + # If it is get/update accepted response, we need to sync the local version + if incomingVersion is not None and incomingVersion > self._lastVersionInSync and currentAction != "delete": + self._lastVersionInSync = incomingVersion + # If it is a delete accepted, we need to reset the version + else: + self._lastVersionInSync = -1 # The version will always be synced for the next incoming delta/GU-accepted response + # Cancel the timer and clear the token + self._tokenPool[currentToken].cancel() + del self._tokenPool[currentToken] + # Need to unsubscribe? + self._shadowSubscribeStatusTable[currentAction] -= 1 + if not self._isPersistentSubscribe and self._shadowSubscribeStatusTable.get(currentAction) <= 0: + self._shadowSubscribeStatusTable[currentAction] = 0 + processNonPersistentUnsubscribe = Thread(target=self._doNonPersistentUnsubscribe, args=[currentAction]) + processNonPersistentUnsubscribe.start() + # Custom callback + if self._shadowSubscribeCallbackTable.get(currentAction) is not None: + processCustomCallback = Thread(target=self._shadowSubscribeCallbackTable[currentAction], args=[payloadUTF8String, currentType, currentToken]) + processCustomCallback.start() + # delta: Watch for version + else: + currentType += "/" + self._parseTopicShadowName(currentTopic) + # Sync local version + self._basicJSONParserHandler.setString(payloadUTF8String) + if self._basicJSONParserHandler.validateJSON(): # Filter out JSON without version + incomingVersion = self._basicJSONParserHandler.getAttributeValue(u"version") + if incomingVersion is not None and incomingVersion > self._lastVersionInSync: + self._lastVersionInSync = incomingVersion + # Custom callback + if self._shadowSubscribeCallbackTable.get(currentAction) is not None: + processCustomCallback = Thread(target=self._shadowSubscribeCallbackTable[currentAction], args=[payloadUTF8String, currentType, None]) + processCustomCallback.start() + + def _parseTopicAction(self, srcTopic): + ret = None + fragments = srcTopic.split('/') + if fragments[5] == "delta": + ret = "delta" + else: + ret = fragments[4] + return ret + + def _parseTopicType(self, srcTopic): + fragments = srcTopic.split('/') + return fragments[5] + + def _parseTopicShadowName(self, srcTopic): + fragments = srcTopic.split('/') + return fragments[2] + + def _timerHandler(self, srcActionName, srcToken): + with self._dataStructureLock: + # Don't crash if we try to remove an unknown token + if srcToken not in self._tokenPool: + self._logger.warn('Tried to remove non-existent token from pool: %s' % str(srcToken)) + return + # Remove the token + del self._tokenPool[srcToken] + # Need to unsubscribe? + self._shadowSubscribeStatusTable[srcActionName] -= 1 + if not self._isPersistentSubscribe and self._shadowSubscribeStatusTable.get(srcActionName) <= 0: + self._shadowSubscribeStatusTable[srcActionName] = 0 + self._shadowManagerHandler.basicShadowUnsubscribe(self._shadowName, srcActionName) + # Notify time-out issue + if self._shadowSubscribeCallbackTable.get(srcActionName) is not None: + self._logger.info("Shadow request with token: " + str(srcToken) + " has timed out.") + self._shadowSubscribeCallbackTable[srcActionName]("REQUEST TIME OUT", "timeout", srcToken) + + def shadowGet(self, srcCallback, srcTimeout): + """ + **Description** + + Retrieve the device shadow JSON document from AWS IoT by publishing an empty JSON document to the + corresponding shadow topics. Shadow response topics will be subscribed to receive responses from + AWS IoT regarding the result of the get operation. Retrieved shadow JSON document will be available + in the registered callback. If no response is received within the provided timeout, a timeout + notification will be passed into the registered callback. + + **Syntax** + + .. code:: python + + # Retrieve the shadow JSON document from AWS IoT, with a timeout set to 5 seconds + BotShadow.shadowGet(customCallback, 5) + + **Parameters** + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + *srcTimeout* - Timeout to determine whether the request is invalid. When a request gets timeout, + a timeout notification will be generated and put into the registered callback to notify users. + + **Returns** + + The token used for tracing in this shadow request. + + """ + with self._dataStructureLock: + # Update callback data structure + self._shadowSubscribeCallbackTable["get"] = srcCallback + # Update number of pending feedback + self._shadowSubscribeStatusTable["get"] += 1 + # clientToken + currentToken = self._tokenHandler.getNextToken() + self._tokenPool[currentToken] = Timer(srcTimeout, self._timerHandler, ["get", currentToken]) + self._basicJSONParserHandler.setString("{}") + self._basicJSONParserHandler.validateJSON() + self._basicJSONParserHandler.setAttributeValue("clientToken", currentToken) + currentPayload = self._basicJSONParserHandler.regenerateString() + # Two subscriptions + if not self._isPersistentSubscribe or not self._isGetSubscribed: + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "get", self.generalCallback) + self._isGetSubscribed = True + self._logger.info("Subscribed to get accepted/rejected topics for deviceShadow: " + self._shadowName) + # One publish + self._shadowManagerHandler.basicShadowPublish(self._shadowName, "get", currentPayload) + # Start the timer + self._tokenPool[currentToken].start() + return currentToken + + def shadowDelete(self, srcCallback, srcTimeout): + """ + **Description** + + Delete the device shadow from AWS IoT by publishing an empty JSON document to the corresponding + shadow topics. Shadow response topics will be subscribed to receive responses from AWS IoT + regarding the result of the get operation. Responses will be available in the registered callback. + If no response is received within the provided timeout, a timeout notification will be passed into + the registered callback. + + **Syntax** + + .. code:: python + + # Delete the device shadow from AWS IoT, with a timeout set to 5 seconds + BotShadow.shadowDelete(customCallback, 5) + + **Parameters** + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + *srcTimeout* - Timeout to determine whether the request is invalid. When a request gets timeout, + a timeout notification will be generated and put into the registered callback to notify users. + + **Returns** + + The token used for tracing in this shadow request. + + """ + with self._dataStructureLock: + # Update callback data structure + self._shadowSubscribeCallbackTable["delete"] = srcCallback + # Update number of pending feedback + self._shadowSubscribeStatusTable["delete"] += 1 + # clientToken + currentToken = self._tokenHandler.getNextToken() + self._tokenPool[currentToken] = Timer(srcTimeout, self._timerHandler, ["delete", currentToken]) + self._basicJSONParserHandler.setString("{}") + self._basicJSONParserHandler.validateJSON() + self._basicJSONParserHandler.setAttributeValue("clientToken", currentToken) + currentPayload = self._basicJSONParserHandler.regenerateString() + # Two subscriptions + if not self._isPersistentSubscribe or not self._isDeleteSubscribed: + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "delete", self.generalCallback) + self._isDeleteSubscribed = True + self._logger.info("Subscribed to delete accepted/rejected topics for deviceShadow: " + self._shadowName) + # One publish + self._shadowManagerHandler.basicShadowPublish(self._shadowName, "delete", currentPayload) + # Start the timer + self._tokenPool[currentToken].start() + return currentToken + + def shadowUpdate(self, srcJSONPayload, srcCallback, srcTimeout): + """ + **Description** + + Update the device shadow JSON document string from AWS IoT by publishing the provided JSON + document to the corresponding shadow topics. Shadow response topics will be subscribed to + receive responses from AWS IoT regarding the result of the get operation. Response will be + available in the registered callback. If no response is received within the provided timeout, + a timeout notification will be passed into the registered callback. + + **Syntax** + + .. code:: python + + # Update the shadow JSON document from AWS IoT, with a timeout set to 5 seconds + BotShadow.shadowUpdate(newShadowJSONDocumentString, customCallback, 5) + + **Parameters** + + *srcJSONPayload* - JSON document string used to update shadow JSON document in AWS IoT. + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + *srcTimeout* - Timeout to determine whether the request is invalid. When a request gets timeout, + a timeout notification will be generated and put into the registered callback to notify users. + + **Returns** + + The token used for tracing in this shadow request. + + """ + # Validate JSON + self._basicJSONParserHandler.setString(srcJSONPayload) + if self._basicJSONParserHandler.validateJSON(): + with self._dataStructureLock: + # clientToken + currentToken = self._tokenHandler.getNextToken() + self._tokenPool[currentToken] = Timer(srcTimeout, self._timerHandler, ["update", currentToken]) + self._basicJSONParserHandler.setAttributeValue("clientToken", currentToken) + JSONPayloadWithToken = self._basicJSONParserHandler.regenerateString() + # Update callback data structure + self._shadowSubscribeCallbackTable["update"] = srcCallback + # Update number of pending feedback + self._shadowSubscribeStatusTable["update"] += 1 + # Two subscriptions + if not self._isPersistentSubscribe or not self._isUpdateSubscribed: + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "update", self.generalCallback) + self._isUpdateSubscribed = True + self._logger.info("Subscribed to update accepted/rejected topics for deviceShadow: " + self._shadowName) + # One publish + self._shadowManagerHandler.basicShadowPublish(self._shadowName, "update", JSONPayloadWithToken) + # Start the timer + self._tokenPool[currentToken].start() + else: + raise ValueError("Invalid JSON file.") + return currentToken + + def shadowRegisterDeltaCallback(self, srcCallback): + """ + **Description** + + Listen on delta topics for this device shadow by subscribing to delta topics. Whenever there + is a difference between the desired and reported state, the registered callback will be called + and the delta payload will be available in the callback. + + **Syntax** + + .. code:: python + + # Listen on delta topics for BotShadow + BotShadow.shadowRegisterDeltaCallback(customCallback) + + **Parameters** + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + **Returns** + + None + + """ + with self._dataStructureLock: + # Update callback data structure + self._shadowSubscribeCallbackTable["delta"] = srcCallback + # One subscription + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "delta", self.generalCallback) + self._logger.info("Subscribed to delta topic for deviceShadow: " + self._shadowName) + + def shadowUnregisterDeltaCallback(self): + """ + **Description** + + Cancel listening on delta topics for this device shadow by unsubscribing to delta topics. There will + be no delta messages received after this API call even though there is a difference between the + desired and reported state. + + **Syntax** + + .. code:: python + + # Cancel listening on delta topics for BotShadow + BotShadow.shadowUnregisterDeltaCallback() + + **Parameters** + + None + + **Returns** + + None + + """ + with self._dataStructureLock: + # Update callback data structure + del self._shadowSubscribeCallbackTable["delta"] + # One unsubscription + self._shadowManagerHandler.basicShadowUnsubscribe(self._shadowName, "delta") + self._logger.info("Unsubscribed to delta topics for deviceShadow: " + self._shadowName) diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/shadowManager.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/shadowManager.py new file mode 100644 index 0000000..3dafa74 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/shadow/shadowManager.py @@ -0,0 +1,83 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import logging +import time +from threading import Lock + +class _shadowAction: + _actionType = ["get", "update", "delete", "delta"] + + def __init__(self, srcShadowName, srcActionName): + if srcActionName is None or srcActionName not in self._actionType: + raise TypeError("Unsupported shadow action.") + self._shadowName = srcShadowName + self._actionName = srcActionName + self.isDelta = srcActionName == "delta" + if self.isDelta: + self._topicDelta = "$aws/things/" + str(self._shadowName) + "/shadow/update/delta" + else: + self._topicGeneral = "$aws/things/" + str(self._shadowName) + "/shadow/" + str(self._actionName) + self._topicAccept = "$aws/things/" + str(self._shadowName) + "/shadow/" + str(self._actionName) + "/accepted" + self._topicReject = "$aws/things/" + str(self._shadowName) + "/shadow/" + str(self._actionName) + "/rejected" + + def getTopicGeneral(self): + return self._topicGeneral + + def getTopicAccept(self): + return self._topicAccept + + def getTopicReject(self): + return self._topicReject + + def getTopicDelta(self): + return self._topicDelta + + +class shadowManager: + + _logger = logging.getLogger(__name__) + + def __init__(self, srcMQTTCore): + # Load in mqttCore + if srcMQTTCore is None: + raise TypeError("None type inputs detected.") + self._mqttCoreHandler = srcMQTTCore + self._shadowSubUnsubOperationLock = Lock() + + def basicShadowPublish(self, srcShadowName, srcShadowAction, srcPayload): + currentShadowAction = _shadowAction(srcShadowName, srcShadowAction) + self._mqttCoreHandler.publish(currentShadowAction.getTopicGeneral(), srcPayload, 0, False) + + def basicShadowSubscribe(self, srcShadowName, srcShadowAction, srcCallback): + with self._shadowSubUnsubOperationLock: + currentShadowAction = _shadowAction(srcShadowName, srcShadowAction) + if currentShadowAction.isDelta: + self._mqttCoreHandler.subscribe(currentShadowAction.getTopicDelta(), 0, srcCallback) + else: + self._mqttCoreHandler.subscribe(currentShadowAction.getTopicAccept(), 0, srcCallback) + self._mqttCoreHandler.subscribe(currentShadowAction.getTopicReject(), 0, srcCallback) + time.sleep(2) + + def basicShadowUnsubscribe(self, srcShadowName, srcShadowAction): + with self._shadowSubUnsubOperationLock: + currentShadowAction = _shadowAction(srcShadowName, srcShadowAction) + if currentShadowAction.isDelta: + self._mqttCoreHandler.unsubscribe(currentShadowAction.getTopicDelta()) + else: + self._logger.debug(currentShadowAction.getTopicAccept()) + self._mqttCoreHandler.unsubscribe(currentShadowAction.getTopicAccept()) + self._logger.debug(currentShadowAction.getTopicReject()) + self._mqttCoreHandler.unsubscribe(currentShadowAction.getTopicReject()) diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/enums.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/enums.py new file mode 100644 index 0000000..3aa3d2f --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/enums.py @@ -0,0 +1,19 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class DropBehaviorTypes(object): + DROP_OLDEST = 0 + DROP_NEWEST = 1 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/providers.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/providers.py new file mode 100644 index 0000000..d90789a --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/core/util/providers.py @@ -0,0 +1,92 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class CredentialsProvider(object): + + def __init__(self): + self._ca_path = "" + + def set_ca_path(self, ca_path): + self._ca_path = ca_path + + def get_ca_path(self): + return self._ca_path + + +class CertificateCredentialsProvider(CredentialsProvider): + + def __init__(self): + CredentialsProvider.__init__(self) + self._cert_path = "" + self._key_path = "" + + def set_cert_path(self,cert_path): + self._cert_path = cert_path + + def set_key_path(self, key_path): + self._key_path = key_path + + def get_cert_path(self): + return self._cert_path + + def get_key_path(self): + return self._key_path + + +class IAMCredentialsProvider(CredentialsProvider): + + def __init__(self): + CredentialsProvider.__init__(self) + self._aws_access_key_id = "" + self._aws_secret_access_key = "" + self._aws_session_token = "" + + def set_access_key_id(self, access_key_id): + self._aws_access_key_id = access_key_id + + def set_secret_access_key(self, secret_access_key): + self._aws_secret_access_key = secret_access_key + + def set_session_token(self, session_token): + self._aws_session_token = session_token + + def get_access_key_id(self): + return self._aws_access_key_id + + def get_secret_access_key(self): + return self._aws_secret_access_key + + def get_session_token(self): + return self._aws_session_token + + +class EndpointProvider(object): + + def __init__(self): + self._host = "" + self._port = -1 + + def set_host(self, host): + self._host = host + + def set_port(self, port): + self._port = port + + def get_host(self): + return self._host + + def get_port(self): + return self._port diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/AWSIoTExceptions.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/AWSIoTExceptions.py new file mode 100644 index 0000000..0de5401 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/AWSIoTExceptions.py @@ -0,0 +1,153 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import AWSIoTPythonSDK.exception.operationTimeoutException as operationTimeoutException +import AWSIoTPythonSDK.exception.operationError as operationError + + +# Serial Exception +class acceptTimeoutException(Exception): + def __init__(self, msg="Accept Timeout"): + self.message = msg + + +# MQTT Operation Timeout Exception +class connectTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Connect Timeout"): + self.message = msg + + +class disconnectTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Disconnect Timeout"): + self.message = msg + + +class publishTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Publish Timeout"): + self.message = msg + + +class subscribeTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Subscribe Timeout"): + self.message = msg + + +class unsubscribeTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Unsubscribe Timeout"): + self.message = msg + + +# MQTT Operation Error +class connectError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Connect Error: " + str(errorCode) + + +class disconnectError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Disconnect Error: " + str(errorCode) + + +class publishError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Publish Error: " + str(errorCode) + + +class publishQueueFullException(operationError.operationError): + def __init__(self): + self.message = "Internal Publish Queue Full" + + +class publishQueueDisabledException(operationError.operationError): + def __init__(self): + self.message = "Offline publish request dropped because queueing is disabled" + + +class subscribeError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Subscribe Error: " + str(errorCode) + + +class subscribeQueueFullException(operationError.operationError): + def __init__(self): + self.message = "Internal Subscribe Queue Full" + + +class subscribeQueueDisabledException(operationError.operationError): + def __init__(self): + self.message = "Offline subscribe request dropped because queueing is disabled" + + +class unsubscribeError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Unsubscribe Error: " + str(errorCode) + + +class unsubscribeQueueFullException(operationError.operationError): + def __init__(self): + self.message = "Internal Unsubscribe Queue Full" + + +class unsubscribeQueueDisabledException(operationError.operationError): + def __init__(self): + self.message = "Offline unsubscribe request dropped because queueing is disabled" + + +# Websocket Error +class wssNoKeyInEnvironmentError(operationError.operationError): + def __init__(self): + self.message = "No AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY detected in $ENV." + + +class wssHandShakeError(operationError.operationError): + def __init__(self): + self.message = "Error in WSS handshake." + + +# Greengrass Discovery Error +class DiscoveryDataNotFoundException(operationError.operationError): + def __init__(self): + self.message = "No discovery data found" + + +class DiscoveryTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, message="Discovery request timed out"): + self.message = message + + +class DiscoveryInvalidRequestException(operationError.operationError): + def __init__(self): + self.message = "Invalid discovery request" + + +class DiscoveryUnauthorizedException(operationError.operationError): + def __init__(self): + self.message = "Discovery request not authorized" + + +class DiscoveryThrottlingException(operationError.operationError): + def __init__(self): + self.message = "Too many discovery requests" + + +class DiscoveryFailure(operationError.operationError): + def __init__(self, message): + self.message = message + + +# Client Error +class ClientError(Exception): + def __init__(self, message): + self.message = message diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/__init__.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationError.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationError.py new file mode 100644 index 0000000..1c86dfc --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationError.py @@ -0,0 +1,19 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class operationError(Exception): + def __init__(self, msg="Operation Error"): + self.message = msg diff --git a/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationTimeoutException.py b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationTimeoutException.py new file mode 100644 index 0000000..737154e --- /dev/null +++ b/Device/aws-iot-device-sdk-python/AWSIoTPythonSDK/exception/operationTimeoutException.py @@ -0,0 +1,19 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class operationTimeoutException(Exception): + def __init__(self, msg="Operation Timeout"): + self.message = msg diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/MQTTLib.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/MQTTLib.py new file mode 100644 index 0000000..2a2527a --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/MQTTLib.py @@ -0,0 +1,1779 @@ +# +#/* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +from AWSIoTPythonSDK.core.util.providers import CertificateCredentialsProvider +from AWSIoTPythonSDK.core.util.providers import IAMCredentialsProvider +from AWSIoTPythonSDK.core.util.providers import EndpointProvider +from AWSIoTPythonSDK.core.jobs.thingJobManager import jobExecutionTopicType +from AWSIoTPythonSDK.core.jobs.thingJobManager import jobExecutionTopicReplyType +from AWSIoTPythonSDK.core.protocol.mqtt_core import MqttCore +import AWSIoTPythonSDK.core.shadow.shadowManager as shadowManager +import AWSIoTPythonSDK.core.shadow.deviceShadow as deviceShadow +import AWSIoTPythonSDK.core.jobs.thingJobManager as thingJobManager + +# Constants +# - Protocol types: +MQTTv3_1 = 3 +MQTTv3_1_1 = 4 + +DROP_OLDEST = 0 +DROP_NEWEST = 1 + +class AWSIoTMQTTClient: + + def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True): + """ + + The client class that connects to and accesses AWS IoT over MQTT v3.1/3.1.1. + + The following connection types are available: + + - TLSv1.2 Mutual Authentication + + X.509 certificate-based secured MQTT connection to AWS IoT + + - Websocket SigV4 + + IAM credential-based secured MQTT connection over Websocket to AWS IoT + + It provides basic synchronous MQTT operations in the classic MQTT publish-subscribe + model, along with configurations of on-top features: + + - Auto reconnect/resubscribe + + - Progressive reconnect backoff + + - Offline publish requests queueing with draining + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Create an AWS IoT MQTT Client using TLSv1.2 Mutual Authentication + myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient("testIoTPySDK") + # Create an AWS IoT MQTT Client using Websocket SigV4 + myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient("testIoTPySDK", useWebsocket=True) + + **Parameters** + + *clientID* - String that denotes the client identifier used to connect to AWS IoT. + If empty string were provided, client id for this connection will be randomly generated + n server side. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + :code:`AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient` object + + """ + self._mqtt_core = MqttCore(clientID, cleanSession, protocolType, useWebsocket) + + # Configuration APIs + def configureLastWill(self, topic, payload, QoS, retain=False): + """ + **Description** + + Used to configure the last will topic, payload and QoS of the client. Should be called before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0) + + **Parameters** + + *topic* - Topic name that last will publishes to. + + *payload* - Payload to publish for last will. + + *QoS* - Quality of Service. Could be 0 or 1. + + **Returns** + + None + + """ + self._mqtt_core.configure_last_will(topic, payload, QoS, retain) + + def clearLastWill(self): + """ + **Description** + + Used to clear the last will configuration that is previously set through configureLastWill. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.clearLastWill() + + **Parameter** + + None + + **Returns** + + None + + """ + self._mqtt_core.clear_last_will() + + def configureEndpoint(self, hostName, portNumber): + """ + **Description** + + Used to configure the host name and port number the client tries to connect to. Should be called + before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureEndpoint("random.iot.region.amazonaws.com", 8883) + + **Parameters** + + *hostName* - String that denotes the host name of the user-specific AWS IoT endpoint. + + *portNumber* - Integer that denotes the port number to connect to. Could be :code:`8883` for + TLSv1.2 Mutual Authentication or :code:`443` for Websocket SigV4 and TLSv1.2 Mutual Authentication + with ALPN extension. + + **Returns** + + None + + """ + endpoint_provider = EndpointProvider() + endpoint_provider.set_host(hostName) + endpoint_provider.set_port(portNumber) + self._mqtt_core.configure_endpoint(endpoint_provider) + if portNumber == 443 and not self._mqtt_core.use_wss(): + self._mqtt_core.configure_alpn_protocols() + + def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSessionToken=""): + """ + **Description** + + Used to configure/update the custom IAM credentials for Websocket SigV4 connection to + AWS IoT. Should be called before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureIAMCredentials(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken) + + .. note:: + + Hard-coding credentials into custom script is NOT recommended. Please use AWS Cognito identity service + or other credential provider. + + **Parameters** + + *AWSAccessKeyID* - AWS Access Key Id from user-specific IAM credentials. + + *AWSSecretAccessKey* - AWS Secret Access Key from user-specific IAM credentials. + + *AWSSessionToken* - AWS Session Token for temporary authentication from STS. + + **Returns** + + None + + """ + iam_credentials_provider = IAMCredentialsProvider() + iam_credentials_provider.set_access_key_id(AWSAccessKeyID) + iam_credentials_provider.set_secret_access_key(AWSSecretAccessKey) + iam_credentials_provider.set_session_token(AWSSessionToken) + self._mqtt_core.configure_iam_credentials(iam_credentials_provider) + + def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth certs config and Websocket rootCA config + """ + **Description** + + Used to configure the rootCA, private key and certificate files. Should be called before connect. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.configureCredentials("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE") + + **Parameters** + + *CAFilePath* - Path to read the root CA file. Required for all connection types. + + *KeyPath* - Path to read the private key. Required for X.509 certificate based connection. + + *CertificatePath* - Path to read the certificate. Required for X.509 certificate based connection. + + **Returns** + + None + + """ + cert_credentials_provider = CertificateCredentialsProvider() + cert_credentials_provider.set_ca_path(CAFilePath) + cert_credentials_provider.set_key_path(KeyPath) + cert_credentials_provider.set_cert_path(CertificatePath) + self._mqtt_core.configure_cert_credentials(cert_credentials_provider) + + def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond): + """ + **Description** + + Used to configure the auto-reconnect backoff timing. Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure the auto-reconnect backoff to start with 1 second and use 128 seconds as a maximum back off time. + # Connection over 20 seconds is considered stable and will reset the back off time back to its base. + myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 128, 20) + + **Parameters** + + *baseReconnectQuietTimeSecond* - The initial back off time to start with, in seconds. + Should be less than the stableConnectionTime. + + *maxReconnectQuietTimeSecond* - The maximum back off time, in seconds. + + *stableConnectionTimeSecond* - The number of seconds for a connection to last to be considered as stable. + Back off time will be reset to base once the connection is stable. + + **Returns** + + None + + """ + self._mqtt_core.configure_reconnect_back_off(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond) + + def configureOfflinePublishQueueing(self, queueSize, dropBehavior=DROP_NEWEST): + """ + **Description** + + Used to configure the queue size and drop behavior for the offline requests queueing. Should be + called before connect. Queueable offline requests include publish, subscribe and unsubscribe. + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Configure the offline queue for publish requests to be 20 in size and drop the oldest + request when the queue is full. + myAWSIoTMQTTClient.configureOfflinePublishQueueing(20, AWSIoTPyMQTT.DROP_OLDEST) + + **Parameters** + + *queueSize* - Size of the queue for offline publish requests queueing. + If set to 0, the queue is disabled. If set to -1, the queue size is set to be infinite. + + *dropBehavior* - the type of drop behavior when the queue is full. + Could be :code:`AWSIoTPythonSDK.core.util.enums.DropBehaviorTypes.DROP_OLDEST` or + :code:`AWSIoTPythonSDK.core.util.enums.DropBehaviorTypes.DROP_NEWEST`. + + **Returns** + + None + + """ + self._mqtt_core.configure_offline_requests_queue(queueSize, dropBehavior) + + def configureDrainingFrequency(self, frequencyInHz): + """ + **Description** + + Used to configure the draining speed to clear up the queued requests when the connection is back. + Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure the draining speed to be 2 requests/second + myAWSIoTMQTTClient.configureDrainingFrequency(2) + + .. note:: + + Make sure the draining speed is fast enough and faster than the publish rate. Slow draining + could result in inifinite draining process. + + **Parameters** + + *frequencyInHz* - The draining speed to clear the queued requests, in requests/second. + + **Returns** + + None + + """ + self._mqtt_core.configure_draining_interval_sec(1/float(frequencyInHz)) + + def configureConnectDisconnectTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the time in seconds to wait for a CONNACK or a disconnect to complete. + Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure connect/disconnect timeout to be 10 seconds + myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a CONNACK or a disconnect to complete. + + **Returns** + + None + + """ + self._mqtt_core.configure_connect_disconnect_timeout_sec(timeoutSecond) + + def configureMQTTOperationTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the timeout in seconds for MQTT QoS 1 publish, subscribe and unsubscribe. + Should be called before connect. + + **Syntax** + + .. code:: python + + # Configure MQTT operation timeout to be 5 seconds + myAWSIoTMQTTClient.configureMQTTOperationTimeout(5) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a PUBACK/SUBACK/UNSUBACK. + + **Returns** + + None + + """ + self._mqtt_core.configure_operation_timeout_sec(timeoutSecond) + + def configureUsernamePassword(self, username, password=None): + """ + **Description** + + Used to configure the username and password used in CONNECT packet. + + **Syntax** + + .. code:: python + + # Configure user name and password + myAWSIoTMQTTClient.configureUsernamePassword("myUsername", "myPassword") + + **Parameters** + + *username* - Username used in the username field of CONNECT packet. + + *password* - Password used in the password field of CONNECT packet. + + **Returns** + + None + + """ + self._mqtt_core.configure_username_password(username, password) + + def configureSocketFactory(self, socket_factory): + """ + **Description** + + Configure a socket factory to custom configure a different socket type for + mqtt connection. Creating a custom socket allows for configuration of a proxy + + **Syntax** + + .. code:: python + + # Configure socket factory + custom_args = {"arg1": "val1", "arg2": "val2"} + socket_factory = lambda: custom.create_connection((host, port), **custom_args) + myAWSIoTMQTTClient.configureSocketFactory(socket_factory) + + **Parameters** + + *socket_factory* - Anonymous function which creates a custom socket to spec. + + **Returns** + + None + + """ + self._mqtt_core.configure_socket_factory(socket_factory) + + def enableMetricsCollection(self): + """ + **Description** + + Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name + and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.enableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._mqtt_core.enable_metrics_collection() + + def disableMetricsCollection(self): + """ + **Description** + + Used to disable SDK metrics collection. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.disableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._mqtt_core.disable_metrics_collection() + + # MQTT functionality APIs + def connect(self, keepAliveIntervalSecond=600): + """ + **Description** + + Connect to AWS IoT, with user-specific keepalive interval configuration. + + **Syntax** + + .. code:: python + + # Connect to AWS IoT with default keepalive set to 600 seconds + myAWSIoTMQTTClient.connect() + # Connect to AWS IoT with keepalive interval set to 1200 seconds + myAWSIoTMQTTClient.connect(1200) + + **Parameters** + + *keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request. + A shorter keep-alive interval allows the client to detect disconnects more quickly. + Default set to 600 seconds. + + **Returns** + + True if the connect attempt succeeded. False if failed. + + """ + self._load_callbacks() + return self._mqtt_core.connect(keepAliveIntervalSecond) + + def connectAsync(self, keepAliveIntervalSecond=600, ackCallback=None): + """ + **Description** + + Connect asynchronously to AWS IoT, with user-specific keepalive interval configuration and CONNACK callback. + + **Syntax** + + .. code:: python + + # Connect to AWS IoT with default keepalive set to 600 seconds and a custom CONNACK callback + myAWSIoTMQTTClient.connectAsync(ackCallback=my_connack_callback) + # Connect to AWS IoT with default keepalive set to 1200 seconds and a custom CONNACK callback + myAWSIoTMQTTClient.connectAsync(keepAliveInternvalSecond=1200, ackCallback=myConnackCallback) + + **Parameters** + + *keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request. + Default set to 600 seconds. + + *ackCallback* - Callback to be invoked when the client receives a CONNACK. Should be in form + :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the connect request + and :code:`data` is the connect result code. + + **Returns** + + Connect request packet id, for tracking purpose in the corresponding callback. + + """ + self._load_callbacks() + return self._mqtt_core.connect_async(keepAliveIntervalSecond, ackCallback) + + def _load_callbacks(self): + self._mqtt_core.on_online = self.onOnline + self._mqtt_core.on_offline = self.onOffline + self._mqtt_core.on_message = self.onMessage + + def disconnect(self): + """ + **Description** + + Disconnect from AWS IoT. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.disconnect() + + **Parameters** + + None + + **Returns** + + True if the disconnect attempt succeeded. False if failed. + + """ + return self._mqtt_core.disconnect() + + def disconnectAsync(self, ackCallback=None): + """ + **Description** + + Disconnect asynchronously to AWS IoT. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.disconnectAsync(ackCallback=myDisconnectCallback) + + **Parameters** + + *ackCallback* - Callback to be invoked when the client finishes sending disconnect and internal clean-up. + Should be in form :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect + request and :code:`data` is the disconnect result code. + + **Returns** + + Disconnect request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.disconnect_async(ackCallback) + + def publish(self, topic, payload, QoS): + """ + **Description** + + Publish a new message to the desired topic with QoS. + + **Syntax** + + .. code:: python + + # Publish a QoS0 message "myPayload" to topic "myTopic" + myAWSIoTMQTTClient.publish("myTopic", "myPayload", 0) + # Publish a QoS1 message "myPayloadWithQos1" to topic "myTopic/sub" + myAWSIoTMQTTClient.publish("myTopic/sub", "myPayloadWithQos1", 1) + + **Parameters** + + *topic* - Topic name to publish to. + + *payload* - Payload to publish. + + *QoS* - Quality of Service. Could be 0 or 1. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + return self._mqtt_core.publish(topic, payload, QoS, False) # Disable retain for publish by now + + def publishAsync(self, topic, payload, QoS, ackCallback=None): + """ + **Description** + + Publish a new message asynchronously to the desired topic with QoS and PUBACK callback. Note that the ack + callback configuration for a QoS0 publish request will be ignored as there are no PUBACK reception. + + **Syntax** + + .. code:: python + + # Publish a QoS0 message "myPayload" to topic "myTopic" + myAWSIoTMQTTClient.publishAsync("myTopic", "myPayload", 0) + # Publish a QoS1 message "myPayloadWithQos1" to topic "myTopic/sub", with custom PUBACK callback + myAWSIoTMQTTClient.publishAsync("myTopic/sub", "myPayloadWithQos1", 1, ackCallback=myPubackCallback) + + **Parameters** + + *topic* - Topic name to publish to. + + *payload* - Payload to publish. + + *QoS* - Quality of Service. Could be 0 or 1. + + *ackCallback* - Callback to be invoked when the client receives a PUBACK. Should be in form + :code:`customCallback(mid)`, where :code:`mid` is the packet id for the disconnect request. + + **Returns** + + Publish request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.publish_async(topic, payload, QoS, False, ackCallback) + + def subscribe(self, topic, QoS, callback): + """ + **Description** + + Subscribe to the desired topic and register a callback. + + **Syntax** + + .. code:: python + + # Subscribe to "myTopic" with QoS0 and register a callback + myAWSIoTMQTTClient.subscribe("myTopic", 0, customCallback) + # Subscribe to "myTopic/#" with QoS1 and register a callback + myAWSIoTMQTTClient.subscribe("myTopic/#", 1, customCallback) + + **Parameters** + + *topic* - Topic name or filter to subscribe to. + + *QoS* - Quality of Service. Could be 0 or 1. + + *callback* - Function to be called when a new message for the subscribed topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + **Returns** + + True if the subscribe attempt succeeded. False if failed. + + """ + return self._mqtt_core.subscribe(topic, QoS, callback) + + def subscribeAsync(self, topic, QoS, ackCallback=None, messageCallback=None): + """ + **Description** + + Subscribe to the desired topic and register a message callback with SUBACK callback. + + **Syntax** + + .. code:: python + + # Subscribe to "myTopic" with QoS0, custom SUBACK callback and a message callback + myAWSIoTMQTTClient.subscribe("myTopic", 0, ackCallback=mySubackCallback, messageCallback=customMessageCallback) + # Subscribe to "myTopic/#" with QoS1, custom SUBACK callback and a message callback + myAWSIoTMQTTClient.subscribe("myTopic/#", 1, ackCallback=mySubackCallback, messageCallback=customMessageCallback) + + **Parameters** + + *topic* - Topic name or filter to subscribe to. + + *QoS* - Quality of Service. Could be 0 or 1. + + *ackCallback* - Callback to be invoked when the client receives a SUBACK. Should be in form + :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect request and + :code:`data` is the granted QoS for this subscription. + + *messageCallback* - Function to be called when a new message for the subscribed topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + **Returns** + + Subscribe request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.subscribe_async(topic, QoS, ackCallback, messageCallback) + + def unsubscribe(self, topic): + """ + **Description** + + Unsubscribe to the desired topic. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.unsubscribe("myTopic") + + **Parameters** + + *topic* - Topic name or filter to unsubscribe to. + + **Returns** + + True if the unsubscribe attempt succeeded. False if failed. + + """ + return self._mqtt_core.unsubscribe(topic) + + def unsubscribeAsync(self, topic, ackCallback=None): + """ + **Description** + + Unsubscribe to the desired topic with UNSUBACK callback. + + **Syntax** + + .. code:: python + + myAWSIoTMQTTClient.unsubscribe("myTopic", ackCallback=myUnsubackCallback) + + **Parameters** + + *topic* - Topic name or filter to unsubscribe to. + + *ackCallback* - Callback to be invoked when the client receives a UNSUBACK. Should be in form + :code:`customCallback(mid)`, where :code:`mid` is the packet id for the disconnect request. + + **Returns** + + Unsubscribe request packet id, for tracking purpose in the corresponding callback. + + """ + return self._mqtt_core.unsubscribe_async(topic, ackCallback) + + def onOnline(self): + """ + **Description** + + Callback that gets called when the client is online. The callback registration should happen before calling + connect/connectAsync. + + **Syntax** + + .. code:: python + + # Register an onOnline callback + myAWSIoTMQTTClient.onOnline = myOnOnlineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + def onOffline(self): + """ + **Description** + + Callback that gets called when the client is offline. The callback registration should happen before calling + connect/connectAsync. + + **Syntax** + + .. code:: python + + # Register an onOffline callback + myAWSIoTMQTTClient.onOffline = myOnOfflineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + def onMessage(self, message): + """ + **Description** + + Callback that gets called when the client receives a new message. The callback registration should happen before + calling connect/connectAsync. This callback, if present, will always be triggered regardless of whether there is + any message callback registered upon subscribe API call. It is for the purpose to aggregating the processing of + received messages in one function. + + **Syntax** + + .. code:: python + + # Register an onMessage callback + myAWSIoTMQTTClient.onMessage = myOnMessageCallback + + **Parameters** + + *message* - Received MQTT message. It contains the source topic as :code:`message.topic`, and the payload as + :code:`message.payload`. + + **Returns** + + None + + """ + pass + +class _AWSIoTMQTTDelegatingClient(object): + + def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None): + """ + + This class is used internally by the SDK and should not be instantiated directly. + + It delegates to a provided AWS IoT MQTT Client or creates a new one given the configuration + parameters and exposes core operations for subclasses provide convenience methods + + **Syntax** + + None + + **Parameters** + + *clientID* - String that denotes the client identifier used to connect to AWS IoT. + If empty string were provided, client id for this connection will be randomly generated + n server side. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + AWSIoTPythonSDK.MQTTLib._AWSIoTMQTTDelegatingClient object + + """ + # AWSIOTMQTTClient instance + self._AWSIoTMQTTClient = awsIoTMQTTClient if awsIoTMQTTClient is not None else AWSIoTMQTTClient(clientID, protocolType, useWebsocket, cleanSession) + + # Configuration APIs + def configureLastWill(self, topic, payload, QoS): + """ + **Description** + + Used to configure the last will topic, payload and QoS of the client. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0) + myJobsClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0) + + **Parameters** + + *topic* - Topic name that last will publishes to. + + *payload* - Payload to publish for last will. + + *QoS* - Quality of Service. Could be 0 or 1. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureLastWill(srcTopic, srcPayload, srcQos) + self._AWSIoTMQTTClient.configureLastWill(topic, payload, QoS) + + def clearLastWill(self): + """ + **Description** + + Used to clear the last will configuration that is previously set through configureLastWill. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill() + myJobsClient.clearLastWill() + + **Parameter** + + None + + **Returns** + + None + + """ + # AWSIoTMQTTClient.clearLastWill() + self._AWSIoTMQTTClient.clearLastWill() + + def configureEndpoint(self, hostName, portNumber): + """ + **Description** + + Used to configure the host name and port number the underneath AWS IoT MQTT Client tries to connect to. Should be called + before connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill("random.iot.region.amazonaws.com", 8883) + myJobsClient.clearLastWill("random.iot.region.amazonaws.com", 8883) + + **Parameters** + + *hostName* - String that denotes the host name of the user-specific AWS IoT endpoint. + + *portNumber* - Integer that denotes the port number to connect to. Could be :code:`8883` for + TLSv1.2 Mutual Authentication or :code:`443` for Websocket SigV4 and TLSv1.2 Mutual Authentication + with ALPN extension. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureEndpoint + self._AWSIoTMQTTClient.configureEndpoint(hostName, portNumber) + + def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken=""): + """ + **Description** + + Used to configure/update the custom IAM credentials for the underneath AWS IoT MQTT Client + for Websocket SigV4 connection to AWS IoT. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken) + myJobsClient.clearLastWill(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken) + + .. note:: + + Hard-coding credentials into custom script is NOT recommended. Please use AWS Cognito identity service + or other credential provider. + + **Parameters** + + *AWSAccessKeyID* - AWS Access Key Id from user-specific IAM credentials. + + *AWSSecretAccessKey* - AWS Secret Access Key from user-specific IAM credentials. + + *AWSSessionToken* - AWS Session Token for temporary authentication from STS. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureIAMCredentials + self._AWSIoTMQTTClient.configureIAMCredentials(AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken) + + def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth and Websocket + """ + **Description** + + Used to configure the rootCA, private key and certificate files. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.clearLastWill("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE") + myJobsClient.clearLastWill("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE") + + **Parameters** + + *CAFilePath* - Path to read the root CA file. Required for all connection types. + + *KeyPath* - Path to read the private key. Required for X.509 certificate based connection. + + *CertificatePath* - Path to read the certificate. Required for X.509 certificate based connection. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureCredentials + self._AWSIoTMQTTClient.configureCredentials(CAFilePath, KeyPath, CertificatePath) + + def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond): + """ + **Description** + + Used to configure the auto-reconnect backoff timing. Should be called before connect. This is a public + facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure the auto-reconnect backoff to start with 1 second and use 128 seconds as a maximum back off time. + # Connection over 20 seconds is considered stable and will reset the back off time back to its base. + myShadowClient.clearLastWill(1, 128, 20) + myJobsClient.clearLastWill(1, 128, 20) + + **Parameters** + + *baseReconnectQuietTimeSecond* - The initial back off time to start with, in seconds. + Should be less than the stableConnectionTime. + + *maxReconnectQuietTimeSecond* - The maximum back off time, in seconds. + + *stableConnectionTimeSecond* - The number of seconds for a connection to last to be considered as stable. + Back off time will be reset to base once the connection is stable. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureBackoffTime + self._AWSIoTMQTTClient.configureAutoReconnectBackoffTime(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond) + + def configureConnectDisconnectTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the time in seconds to wait for a CONNACK or a disconnect to complete. + Should be called before connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure connect/disconnect timeout to be 10 seconds + myShadowClient.configureConnectDisconnectTimeout(10) + myJobsClient.configureConnectDisconnectTimeout(10) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a CONNACK or a disconnect to complete. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureConnectDisconnectTimeout + self._AWSIoTMQTTClient.configureConnectDisconnectTimeout(timeoutSecond) + + def configureMQTTOperationTimeout(self, timeoutSecond): + """ + **Description** + + Used to configure the timeout in seconds for MQTT QoS 1 publish, subscribe and unsubscribe. + Should be called before connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure MQTT operation timeout to be 5 seconds + myShadowClient.configureMQTTOperationTimeout(5) + myJobsClient.configureMQTTOperationTimeout(5) + + **Parameters** + + *timeoutSecond* - Time in seconds to wait for a PUBACK/SUBACK/UNSUBACK. + + **Returns** + + None + + """ + # AWSIoTMQTTClient.configureMQTTOperationTimeout + self._AWSIoTMQTTClient.configureMQTTOperationTimeout(timeoutSecond) + + def configureUsernamePassword(self, username, password=None): + """ + **Description** + + Used to configure the username and password used in CONNECT packet. This is a public facing API + inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Configure user name and password + myShadowClient.configureUsernamePassword("myUsername", "myPassword") + myJobsClient.configureUsernamePassword("myUsername", "myPassword") + + **Parameters** + + *username* - Username used in the username field of CONNECT packet. + + *password* - Password used in the password field of CONNECT packet. + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.configureUsernamePassword(username, password) + + def configureSocketFactory(self, socket_factory): + """ + **Description** + + Configure a socket factory to custom configure a different socket type for + mqtt connection. Creating a custom socket allows for configuration of a proxy + + **Syntax** + + .. code:: python + + # Configure socket factory + custom_args = {"arg1": "val1", "arg2": "val2"} + socket_factory = lambda: custom.create_connection((host, port), **custom_args) + myAWSIoTMQTTClient.configureSocketFactory(socket_factory) + + **Parameters** + + *socket_factory* - Anonymous function which creates a custom socket to spec. + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.configureSocketFactory(socket_factory) + + def enableMetricsCollection(self): + """ + **Description** + + Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name + and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default. + This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.enableMetricsCollection() + myJobsClient.enableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.enableMetricsCollection() + + def disableMetricsCollection(self): + """ + **Description** + + Used to disable SDK metrics collection. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.disableMetricsCollection() + myJobsClient.disableMetricsCollection() + + **Parameters** + + None + + **Returns** + + None + + """ + self._AWSIoTMQTTClient.disableMetricsCollection() + + # Start the MQTT connection + def connect(self, keepAliveIntervalSecond=600): + """ + **Description** + + Connect to AWS IoT, with user-specific keepalive interval configuration. This is a public facing API inherited + by application level public clients. + + **Syntax** + + .. code:: python + + # Connect to AWS IoT with default keepalive set to 600 seconds + myShadowClient.connect() + myJobsClient.connect() + # Connect to AWS IoT with keepalive interval set to 1200 seconds + myShadowClient.connect(1200) + myJobsClient.connect(1200) + + **Parameters** + + *keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request. + Default set to 30 seconds. + + **Returns** + + True if the connect attempt succeeded. False if failed. + + """ + self._load_callbacks() + return self._AWSIoTMQTTClient.connect(keepAliveIntervalSecond) + + def _load_callbacks(self): + self._AWSIoTMQTTClient.onOnline = self.onOnline + self._AWSIoTMQTTClient.onOffline = self.onOffline + + # End the MQTT connection + def disconnect(self): + """ + **Description** + + Disconnect from AWS IoT. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + myShadowClient.disconnect() + myJobsClient.disconnect() + + **Parameters** + + None + + **Returns** + + True if the disconnect attempt succeeded. False if failed. + + """ + return self._AWSIoTMQTTClient.disconnect() + + # MQTT connection management API + def getMQTTConnection(self): + """ + **Description** + + Retrieve the AWS IoT MQTT Client used underneath, making it possible to perform + plain MQTT operations along with specialized operations using the same single connection. + This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Retrieve the AWS IoT MQTT Client used in the AWS IoT MQTT Delegating Client + thisAWSIoTMQTTClient = myShadowClient.getMQTTConnection() + thisAWSIoTMQTTClient = myJobsClient.getMQTTConnection() + # Perform plain MQTT operations using the same connection + thisAWSIoTMQTTClient.publish("Topic", "Payload", 1) + ... + + **Parameters** + + None + + **Returns** + + AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient object + + """ + # Return the internal AWSIoTMQTTClient instance + return self._AWSIoTMQTTClient + + def onOnline(self): + """ + **Description** + + Callback that gets called when the client is online. The callback registration should happen before calling + connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Register an onOnline callback + myShadowClient.onOnline = myOnOnlineCallback + myJobsClient.onOnline = myOnOnlineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + def onOffline(self): + """ + **Description** + + Callback that gets called when the client is offline. The callback registration should happen before calling + connect. This is a public facing API inherited by application level public clients. + + **Syntax** + + .. code:: python + + # Register an onOffline callback + myShadowClient.onOffline = myOnOfflineCallback + myJobsClient.onOffline = myOnOfflineCallback + + **Parameters** + + None + + **Returns** + + None + + """ + pass + + +class AWSIoTMQTTShadowClient(_AWSIoTMQTTDelegatingClient): + + def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None): + """ + + The client class that manages device shadow and accesses its functionality in AWS IoT over MQTT v3.1/3.1.1. + + It delegates to the AWS IoT MQTT Client and exposes devive shadow related operations. + It shares the same connection types, synchronous MQTT operations and partial on-top features + with the AWS IoT MQTT Client: + + - Auto reconnect/resubscribe + + Same as AWS IoT MQTT Client. + + - Progressive reconnect backoff + + Same as AWS IoT MQTT Client. + + - Offline publish requests queueing with draining + + Disabled by default. Queueing is not allowed for time-sensitive shadow requests/messages. + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Create an AWS IoT MQTT Shadow Client using TLSv1.2 Mutual Authentication + myAWSIoTMQTTShadowClient = AWSIoTPyMQTT.AWSIoTMQTTShadowClient("testIoTPySDK") + # Create an AWS IoT MQTT Shadow Client using Websocket SigV4 + myAWSIoTMQTTShadowClient = AWSIoTPyMQTT.AWSIoTMQTTShadowClient("testIoTPySDK", useWebsocket=True) + + **Parameters** + + *clientID* - String that denotes the client identifier used to connect to AWS IoT. + If empty string were provided, client id for this connection will be randomly generated + n server side. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTShadowClient object + + """ + super(AWSIoTMQTTShadowClient, self).__init__(clientID, protocolType, useWebsocket, cleanSession, awsIoTMQTTClient) + #leave passed in clients alone + if awsIoTMQTTClient is None: + # Configure it to disable offline Publish Queueing + self._AWSIoTMQTTClient.configureOfflinePublishQueueing(0) # Disable queueing, no queueing for time-sensitive shadow messages + self._AWSIoTMQTTClient.configureDrainingFrequency(10) + # Now retrieve the configured mqttCore and init a shadowManager instance + self._shadowManager = shadowManager.shadowManager(self._AWSIoTMQTTClient._mqtt_core) + + # Shadow management API + def createShadowHandlerWithName(self, shadowName, isPersistentSubscribe): + """ + **Description** + + Create a device shadow handler using the specified shadow name and isPersistentSubscribe. + + **Syntax** + + .. code:: python + + # Create a device shadow handler for shadow named "Bot1", using persistent subscription + Bot1Shadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("Bot1", True) + # Create a device shadow handler for shadow named "Bot2", using non-persistent subscription + Bot2Shadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("Bot2", False) + + **Parameters** + + *shadowName* - Name of the device shadow. + + *isPersistentSubscribe* - Whether to unsubscribe from shadow response (accepted/rejected) topics + when there is a response. Will subscribe at the first time the shadow request is made and will + not unsubscribe if isPersistentSubscribe is set. + + **Returns** + + AWSIoTPythonSDK.core.shadow.deviceShadow.deviceShadow object, which exposes the device shadow interface. + + """ + # Create and return a deviceShadow instance + return deviceShadow.deviceShadow(shadowName, isPersistentSubscribe, self._shadowManager) + # Shadow APIs are accessible in deviceShadow instance": + ### + # deviceShadow.shadowGet + # deviceShadow.shadowUpdate + # deviceShadow.shadowDelete + # deviceShadow.shadowRegisterDelta + # deviceShadow.shadowUnregisterDelta + +class AWSIoTMQTTThingJobsClient(_AWSIoTMQTTDelegatingClient): + + def __init__(self, clientID, thingName, QoS=0, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None): + """ + + The client class that specializes in handling jobs messages and accesses its functionality in AWS IoT over MQTT v3.1/3.1.1. + + It delegates to the AWS IoT MQTT Client and exposes jobs related operations. + It shares the same connection types, synchronous MQTT operations and partial on-top features + with the AWS IoT MQTT Client: + + - Auto reconnect/resubscribe + + Same as AWS IoT MQTT Client. + + - Progressive reconnect backoff + + Same as AWS IoT MQTT Client. + + - Offline publish requests queueing with draining + + Same as AWS IoT MQTT Client + + **Syntax** + + .. code:: python + + import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT + + # Create an AWS IoT MQTT Jobs Client using TLSv1.2 Mutual Authentication + myAWSIoTMQTTJobsClient = AWSIoTPyMQTT.AWSIoTMQTTThingJobsClient("testIoTPySDK") + # Create an AWS IoT MQTT Jobs Client using Websocket SigV4 + myAWSIoTMQTTJobsClient = AWSIoTPyMQTT.AWSIoTMQTTThingJobsClient("testIoTPySDK", useWebsocket=True) + + **Parameters** + + *clientID* - String that denotes the client identifier and client token for jobs requests + If empty string is provided, client id for this connection will be randomly generated + on server side. If an awsIotMQTTClient is specified, this will not override the client ID + for the existing MQTT connection and only impact the client token for jobs request payloads + + *thingName* - String that represents the thingName used to send requests to proper topics and subscribe + to proper topics. + + *QoS* - QoS used for all requests sent through this client + + *awsIoTMQTTClient* - An instance of AWSIoTMQTTClient to use if not None. If not None, clientID, protocolType, useWebSocket, + and cleanSession parameters are not used. Caller is expected to invoke connect() prior to calling the pub/sub methods on this client. + + *protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1` + + *useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not. + + **Returns** + + AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTJobsClient object + + """ + # AWSIOTMQTTClient instance + super(AWSIoTMQTTThingJobsClient, self).__init__(clientID, protocolType, useWebsocket, cleanSession, awsIoTMQTTClient) + self._thingJobManager = thingJobManager.thingJobManager(thingName, clientID) + self._QoS = QoS + + def createJobSubscription(self, callback, jobExecutionType=jobExecutionTopicType.JOB_WILDCARD_TOPIC, jobReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None): + """ + **Description** + + Synchronously creates an MQTT subscription to a jobs related topic based on the provided arguments + + **Syntax** + + .. code:: python + + #Subscribe to notify-next topic to monitor change in job referred to by $next + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) + #Subscribe to notify topic to monitor changes to jobs in pending list + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_NOTIFY_TOPIC) + #Subscribe to receive messages for job execution updates + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE) + #Subscribe to receive messages for describing a job execution + myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE, jobId) + + **Parameters** + + *callback* - Function to be called when a new message for the subscribed job topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + *jobExecutionType* - Member of the jobExecutionTopicType class specifying the jobs topic to subscribe to + Defaults to jobExecutionTopicType.JOB_WILDCARD_TOPIC + + *jobReplyType* - Member of the jobExecutionTopicReplyType class specifying the (optional) reply sub-topic to subscribe to + Defaults to jobExecutionTopicReplyType.JOB_REQUEST_TYPE which indicates the subscription isn't intended for a jobs reply topic + + *jobId* - JobId string if the topic type requires one. + Defaults to None + + **Returns** + + True if the subscribe attempt succeeded. False if failed. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionType, jobReplyType, jobId) + return self._AWSIoTMQTTClient.subscribe(topic, self._QoS, callback) + + def createJobSubscriptionAsync(self, ackCallback, callback, jobExecutionType=jobExecutionTopicType.JOB_WILDCARD_TOPIC, jobReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None): + """ + **Description** + + Asynchronously creates an MQTT subscription to a jobs related topic based on the provided arguments + + **Syntax** + + .. code:: python + + #Subscribe to notify-next topic to monitor change in job referred to by $next + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) + #Subscribe to notify topic to monitor changes to jobs in pending list + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_NOTIFY_TOPIC) + #Subscribe to receive messages for job execution updates + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE) + #Subscribe to receive messages for describing a job execution + myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE, jobId) + + **Parameters** + + *ackCallback* - Callback to be invoked when the client receives a SUBACK. Should be in form + :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect request and + :code:`data` is the granted QoS for this subscription. + + *callback* - Function to be called when a new message for the subscribed job topic + comes in. Should be in form :code:`customCallback(client, userdata, message)`, where + :code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are + here just to be aligned with the underneath Paho callback function signature. These fields are pending to be + deprecated and should not be depended on. + + *jobExecutionType* - Member of the jobExecutionTopicType class specifying the jobs topic to subscribe to + Defaults to jobExecutionTopicType.JOB_WILDCARD_TOPIC + + *jobReplyType* - Member of the jobExecutionTopicReplyType class specifying the (optional) reply sub-topic to subscribe to + Defaults to jobExecutionTopicReplyType.JOB_REQUEST_TYPE which indicates the subscription isn't intended for a jobs reply topic + + *jobId* - JobId of the topic if the topic type requires one. + Defaults to None + + **Returns** + + Subscribe request packet id, for tracking purpose in the corresponding callback. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionType, jobReplyType, jobId) + return self._AWSIoTMQTTClient.subscribeAsync(topic, self._QoS, ackCallback, callback) + + def sendJobsQuery(self, jobExecTopicType, jobId=None): + """ + **Description** + + Publishes an MQTT jobs related request for a potentially specific jobId (or wildcard) + + **Syntax** + + .. code:: python + + #send a request to describe the next job + myAWSIoTMQTTJobsClient.sendJobsQuery(jobExecutionTopicType.JOB_DESCRIBE_TOPIC, '$next') + #send a request to get list of pending jobs + myAWSIoTMQTTJobsClient.sendJobsQuery(jobExecutionTopicType.JOB_GET_PENDING_TOPIC) + + **Parameters** + + *jobExecutionType* - Member of the jobExecutionTopicType class that correlates the jobs topic to publish to + + *jobId* - JobId string if the topic type requires one. + Defaults to None + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecTopicType, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId) + payload = self._thingJobManager.serializeClientTokenPayload() + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) + + def sendJobsStartNext(self, statusDetails=None, stepTimeoutInMinutes=None): + """ + **Description** + + Publishes an MQTT message to the StartNextJobExecution topic. This will attempt to get the next pending + job execution and change its status to IN_PROGRESS. + + **Syntax** + + .. code:: python + + #Start next job (set status to IN_PROGRESS) and update with optional statusDetails + myAWSIoTMQTTJobsClient.sendJobsStartNext({'StartedBy': 'myClientId'}) + + **Parameters** + + *statusDetails* - Dictionary containing the key value pairs to use for the status details of the job execution + + *stepTimeoutInMinutes - Specifies the amount of time this device has to finish execution of this job. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_START_NEXT_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE) + payload = self._thingJobManager.serializeStartNextPendingJobExecutionPayload(statusDetails, stepTimeoutInMinutes) + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) + + def sendJobsUpdate(self, jobId, status, statusDetails=None, expectedVersion=0, executionNumber=0, includeJobExecutionState=False, includeJobDocument=False, stepTimeoutInMinutes=None): + """ + **Description** + + Publishes an MQTT message to a corresponding job execution specific topic to update its status according to the parameters. + Can be used to change a job from QUEUED to IN_PROGRESS to SUCEEDED or FAILED. + + **Syntax** + + .. code:: python + + #Update job with id 'jobId123' to succeeded state, specifying new status details, with expectedVersion=1, executionNumber=2. + #For the response, include job execution state and not the job document + myAWSIoTMQTTJobsClient.sendJobsUpdate('jobId123', jobExecutionStatus.JOB_EXECUTION_SUCCEEDED, statusDetailsMap, 1, 2, True, False) + + + #Update job with id 'jobId456' to failed state + myAWSIoTMQTTJobsClient.sendJobsUpdate('jobId456', jobExecutionStatus.JOB_EXECUTION_FAILED) + + **Parameters** + + *jobId* - JobID String of the execution to update the status of + + *status* - job execution status to change the job execution to. Member of jobExecutionStatus + + *statusDetails* - new status details to set on the job execution + + *expectedVersion* - The expected current version of the job execution. IoT jobs increments expectedVersion each time you update the job execution. + If the version of the job execution stored in Jobs does not match, the update is rejected with a VersionMismatch error, and an ErrorResponse + that contains the current job execution status data is returned. (This makes it unnecessary to perform a separate DescribeJobExecution request + n order to obtain the job execution status data.) + + *executionNumber* - A number that identifies a particular job execution on a particular device. If not specified, the latest job execution is used. + + *includeJobExecutionState* - When included and set to True, the response contains the JobExecutionState field. The default is False. + + *includeJobDocument* - When included and set to True, the response contains the JobDocument. The default is False. + + *stepTimeoutInMinutes - Specifies the amount of time this device has to finish execution of this job. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId) + payload = self._thingJobManager.serializeJobExecutionUpdatePayload(status, statusDetails, expectedVersion, executionNumber, includeJobExecutionState, includeJobDocument, stepTimeoutInMinutes) + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) + + def sendJobsDescribe(self, jobId, executionNumber=0, includeJobDocument=True): + """ + **Description** + + Publishes a method to the describe topic for a particular job. + + **Syntax** + + .. code:: python + + #Describe job with id 'jobId1' of any executionNumber, job document will be included in response + myAWSIoTMQTTJobsClient.sendJobsDescribe('jobId1') + + #Describe job with id 'jobId2', with execution number of 2, and includeJobDocument in the response + myAWSIoTMQTTJobsClient.sendJobsDescribe('jobId2', 2, True) + + **Parameters** + + *jobId* - jobID to describe. This is allowed to be a wildcard such as '$next' + + *executionNumber* - A number that identifies a particular job execution on a particular device. If not specified, the latest job execution is used. + + *includeJobDocument* - When included and set to True, the response contains the JobDocument. + + **Returns** + + True if the publish request has been sent to paho. False if the request did not reach paho. + + """ + topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId) + payload = self._thingJobManager.serializeDescribeJobExecutionPayload(executionNumber, includeJobDocument) + return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS) diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/__init__.py new file mode 100644 index 0000000..eda1560 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/__init__.py @@ -0,0 +1,3 @@ +__version__ = "1.4.8" + + diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/models.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/models.py new file mode 100644 index 0000000..ed8256d --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/models.py @@ -0,0 +1,466 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import json + + +KEY_GROUP_LIST = "GGGroups" +KEY_GROUP_ID = "GGGroupId" +KEY_CORE_LIST = "Cores" +KEY_CORE_ARN = "thingArn" +KEY_CA_LIST = "CAs" +KEY_CONNECTIVITY_INFO_LIST = "Connectivity" +KEY_CONNECTIVITY_INFO_ID = "Id" +KEY_HOST_ADDRESS = "HostAddress" +KEY_PORT_NUMBER = "PortNumber" +KEY_METADATA = "Metadata" + + +class ConnectivityInfo(object): + """ + + Class the stores one set of the connectivity information. + This is the data model for easy access to the discovery information from the discovery request function call. No + need to call directly from user scripts. + + """ + + def __init__(self, id, host, port, metadata): + self._id = id + self._host = host + self._port = port + self._metadata = metadata + + @property + def id(self): + """ + + Connectivity Information Id. + + """ + return self._id + + @property + def host(self): + """ + + Host address. + + """ + return self._host + + @property + def port(self): + """ + + Port number. + + """ + return self._port + + @property + def metadata(self): + """ + + Metadata string. + + """ + return self._metadata + + +class CoreConnectivityInfo(object): + """ + + Class that stores the connectivity information for a Greengrass core. + This is the data model for easy access to the discovery information from the discovery request function call. No + need to call directly from user scripts. + + """ + + def __init__(self, coreThingArn, groupId): + self._core_thing_arn = coreThingArn + self._group_id = groupId + self._connectivity_info_dict = dict() + + @property + def coreThingArn(self): + """ + + Thing arn for this Greengrass core. + + """ + return self._core_thing_arn + + @property + def groupId(self): + """ + + Greengrass group id that this Greengrass core belongs to. + + """ + return self._group_id + + @property + def connectivityInfoList(self): + """ + + The list of connectivity information that this Greengrass core has. + + """ + return list(self._connectivity_info_dict.values()) + + def getConnectivityInfo(self, id): + """ + + **Description** + + Used for quickly accessing a certain set of connectivity information by id. + + **Syntax** + + .. code:: python + + myCoreConnectivityInfo.getConnectivityInfo("CoolId") + + **Parameters** + + *id* - The id for the desired connectivity information. + + **Return** + + :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.ConnectivityInfo` object. + + """ + return self._connectivity_info_dict.get(id) + + def appendConnectivityInfo(self, connectivityInfo): + """ + + **Description** + + Used for adding a new set of connectivity information to the list for this Greengrass core. This is used by the + SDK internally. No need to call directly from user scripts. + + **Syntax** + + .. code:: python + + myCoreConnectivityInfo.appendConnectivityInfo(newInfo) + + **Parameters** + + *connectivityInfo* - :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.ConnectivityInfo` object. + + **Returns** + + None + + """ + self._connectivity_info_dict[connectivityInfo.id] = connectivityInfo + + +class GroupConnectivityInfo(object): + """ + + Class that stores the connectivity information for a specific Greengrass group. + This is the data model for easy access to the discovery information from the discovery request function call. No + need to call directly from user scripts. + + """ + def __init__(self, groupId): + self._group_id = groupId + self._core_connectivity_info_dict = dict() + self._ca_list = list() + + @property + def groupId(self): + """ + + Id for this Greengrass group. + + """ + return self._group_id + + @property + def coreConnectivityInfoList(self): + """ + + A list of Greengrass cores + (:code:`AWSIoTPythonSDK.core.greengrass.discovery.models.CoreConnectivityInfo` object) that belong to this + Greengrass group. + + """ + return list(self._core_connectivity_info_dict.values()) + + @property + def caList(self): + """ + + A list of CA content strings for this Greengrass group. + + """ + return self._ca_list + + def getCoreConnectivityInfo(self, coreThingArn): + """ + + **Description** + + Used to retrieve the corresponding :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.CoreConnectivityInfo` + object by core thing arn. + + **Syntax** + + .. code:: python + + myGroupConnectivityInfo.getCoreConnectivityInfo("YourOwnArnString") + + **Parameters** + + coreThingArn - Thing arn for the desired Greengrass core. + + **Returns** + + :code:`AWSIoTPythonSDK.core.greengrass.discovery.CoreConnectivityInfo` object. + + """ + return self._core_connectivity_info_dict.get(coreThingArn) + + def appendCoreConnectivityInfo(self, coreConnectivityInfo): + """ + + **Description** + + Used to append new core connectivity information to this group connectivity information. This is used by the + SDK internally. No need to call directly from user scripts. + + **Syntax** + + .. code:: python + + myGroupConnectivityInfo.appendCoreConnectivityInfo(newCoreConnectivityInfo) + + **Parameters** + + *coreConnectivityInfo* - :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.CoreConnectivityInfo` object. + + **Returns** + + None + + """ + self._core_connectivity_info_dict[coreConnectivityInfo.coreThingArn] = coreConnectivityInfo + + def appendCa(self, ca): + """ + + **Description** + + Used to append new CA content string to this group connectivity information. This is used by the SDK internally. + No need to call directly from user scripts. + + **Syntax** + + .. code:: python + + myGroupConnectivityInfo.appendCa("CaContentString") + + **Parameters** + + *ca* - Group CA content string. + + **Returns** + + None + + """ + self._ca_list.append(ca) + + +class DiscoveryInfo(object): + """ + + Class that stores the discovery information coming back from the discovery request. + This is the data model for easy access to the discovery information from the discovery request function call. No + need to call directly from user scripts. + + """ + def __init__(self, rawJson): + self._raw_json = rawJson + + @property + def rawJson(self): + """ + + JSON response string that contains the discovery information. This is reserved in case users want to do + some process by themselves. + + """ + return self._raw_json + + def getAllCores(self): + """ + + **Description** + + Used to retrieve the list of :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.CoreConnectivityInfo` + object for this discovery information. The retrieved cores could be from different Greengrass groups. This is + designed for uses who want to iterate through all available cores at the same time, regardless of which group + those cores are in. + + **Syntax** + + .. code:: python + + myDiscoveryInfo.getAllCores() + + **Parameters** + + None + + **Returns** + + List of :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.CoreConnectivtyInfo` object. + + """ + groups_list = self.getAllGroups() + core_list = list() + + for group in groups_list: + core_list.extend(group.coreConnectivityInfoList) + + return core_list + + def getAllCas(self): + """ + + **Description** + + Used to retrieve the list of :code:`(groupId, caContent)` pair for this discovery information. The retrieved + pairs could be from different Greengrass groups. This is designed for users who want to iterate through all + available cores/groups/CAs at the same time, regardless of which group those CAs belong to. + + **Syntax** + + .. code:: python + + myDiscoveryInfo.getAllCas() + + **Parameters** + + None + + **Returns** + + List of :code:`(groupId, caContent)` string pair, where :code:`caContent` is the CA content string and + :code:`groupId` is the group id that this CA belongs to. + + """ + group_list = self.getAllGroups() + ca_list = list() + + for group in group_list: + for ca in group.caList: + ca_list.append((group.groupId, ca)) + + return ca_list + + def getAllGroups(self): + """ + + **Description** + + Used to retrieve the list of :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.GroupConnectivityInfo` + object for this discovery information. This is designed for users who want to iterate through all available + groups that this Greengrass aware device (GGAD) belongs to. + + **Syntax** + + .. code:: python + + myDiscoveryInfo.getAllGroups() + + **Parameters** + + None + + **Returns** + + List of :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.GroupConnectivityInfo` object. + + """ + groups_dict = self.toObjectAtGroupLevel() + return list(groups_dict.values()) + + def toObjectAtGroupLevel(self): + """ + + **Description** + + Used to get a dictionary of Greengrass group discovery information, with group id string as key and the + corresponding :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.GroupConnectivityInfo` object as the + value. This is designed for users who know exactly which group, which core and which set of connectivity info + they want to use for the Greengrass aware device to connect. + + **Syntax** + + .. code:: python + + # Get to the targeted connectivity information for a specific core in a specific group + groupLevelDiscoveryInfoObj = myDiscoveryInfo.toObjectAtGroupLevel() + groupConnectivityInfoObj = groupLevelDiscoveryInfoObj.toObjectAtGroupLevel("IKnowMyGroupId") + coreConnectivityInfoObj = groupConnectivityInfoObj.getCoreConnectivityInfo("IKnowMyCoreThingArn") + connectivityInfo = coreConnectivityInfoObj.getConnectivityInfo("IKnowMyConnectivityInfoSetId") + # Now retrieve the detailed information + caList = groupConnectivityInfoObj.caList + host = connectivityInfo.host + port = connectivityInfo.port + metadata = connectivityInfo.metadata + # Actual connecting logic follows... + + """ + groups_object = json.loads(self._raw_json) + groups_dict = dict() + + for group_object in groups_object[KEY_GROUP_LIST]: + group_info = self._decode_group_info(group_object) + groups_dict[group_info.groupId] = group_info + + return groups_dict + + def _decode_group_info(self, group_object): + group_id = group_object[KEY_GROUP_ID] + group_info = GroupConnectivityInfo(group_id) + + for core in group_object[KEY_CORE_LIST]: + core_info = self._decode_core_info(core, group_id) + group_info.appendCoreConnectivityInfo(core_info) + + for ca in group_object[KEY_CA_LIST]: + group_info.appendCa(ca) + + return group_info + + def _decode_core_info(self, core_object, group_id): + core_info = CoreConnectivityInfo(core_object[KEY_CORE_ARN], group_id) + + for connectivity_info_object in core_object[KEY_CONNECTIVITY_INFO_LIST]: + connectivity_info = ConnectivityInfo(connectivity_info_object[KEY_CONNECTIVITY_INFO_ID], + connectivity_info_object[KEY_HOST_ADDRESS], + connectivity_info_object[KEY_PORT_NUMBER], + connectivity_info_object.get(KEY_METADATA,'')) + core_info.appendConnectivityInfo(connectivity_info) + + return core_info diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/providers.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/providers.py new file mode 100644 index 0000000..646d79d --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/greengrass/discovery/providers.py @@ -0,0 +1,426 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +from AWSIoTPythonSDK.exception.AWSIoTExceptions import DiscoveryInvalidRequestException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import DiscoveryUnauthorizedException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import DiscoveryDataNotFoundException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import DiscoveryThrottlingException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import DiscoveryTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import DiscoveryFailure +from AWSIoTPythonSDK.core.greengrass.discovery.models import DiscoveryInfo +from AWSIoTPythonSDK.core.protocol.connection.alpn import SSLContextBuilder +import re +import sys +import ssl +import time +import errno +import logging +import socket +import platform +if platform.system() == 'Windows': + EAGAIN = errno.WSAEWOULDBLOCK +else: + EAGAIN = errno.EAGAIN + + +class DiscoveryInfoProvider(object): + + REQUEST_TYPE_PREFIX = "GET " + PAYLOAD_PREFIX = "/greengrass/discover/thing/" + PAYLOAD_SUFFIX = " HTTP/1.1\r\n" # Space in the front + HOST_PREFIX = "Host: " + HOST_SUFFIX = "\r\n\r\n" + HTTP_PROTOCOL = r"HTTP/1.1 " + CONTENT_LENGTH = r"content-length: " + CONTENT_LENGTH_PATTERN = CONTENT_LENGTH + r"([0-9]+)\r\n" + HTTP_RESPONSE_CODE_PATTERN = HTTP_PROTOCOL + r"([0-9]+) " + + HTTP_SC_200 = "200" + HTTP_SC_400 = "400" + HTTP_SC_401 = "401" + HTTP_SC_404 = "404" + HTTP_SC_429 = "429" + + LOW_LEVEL_RC_COMPLETE = 0 + LOW_LEVEL_RC_TIMEOUT = -1 + + _logger = logging.getLogger(__name__) + + def __init__(self, caPath="", certPath="", keyPath="", host="", port=8443, timeoutSec=120): + """ + + The class that provides functionality to perform a Greengrass discovery process to the cloud. + + Users can perform Greengrass discovery process for a specific Greengrass aware device to retrieve + connectivity/identity information of Greengrass cores within the same group. + + **Syntax** + + .. code:: python + + from AWSIoTPythonSDK.core.greengrass.discovery.providers import DiscoveryInfoProvider + + # Create a discovery information provider + myDiscoveryInfoProvider = DiscoveryInfoProvider() + # Create a discovery information provider with custom configuration + myDiscoveryInfoProvider = DiscoveryInfoProvider(caPath=myCAPath, certPath=myCertPath, keyPath=myKeyPath, host=myHost, timeoutSec=myTimeoutSec) + + **Parameters** + + *caPath* - Path to read the root CA file. + + *certPath* - Path to read the certificate file. + + *keyPath* - Path to read the private key file. + + *host* - String that denotes the host name of the user-specific AWS IoT endpoint. + + *port* - Integer that denotes the port number to connect to. For discovery purpose, it is 8443 by default. + + *timeoutSec* - Time out configuration in seconds to consider a discovery request sending/response waiting has + been timed out. + + **Returns** + + AWSIoTPythonSDK.core.greengrass.discovery.providers.DiscoveryInfoProvider object + + """ + self._ca_path = caPath + self._cert_path = certPath + self._key_path = keyPath + self._host = host + self._port = port + self._timeout_sec = timeoutSec + self._expected_exception_map = { + self.HTTP_SC_400 : DiscoveryInvalidRequestException(), + self.HTTP_SC_401 : DiscoveryUnauthorizedException(), + self.HTTP_SC_404 : DiscoveryDataNotFoundException(), + self.HTTP_SC_429 : DiscoveryThrottlingException() + } + + def configureEndpoint(self, host, port=8443): + """ + + **Description** + + Used to configure the host address and port number for the discovery request to hit. Should be called before + the discovery request happens. + + **Syntax** + + .. code:: python + + # Using default port configuration, 8443 + myDiscoveryInfoProvider.configureEndpoint(host="prefix.iot.us-east-1.amazonaws.com") + # Customize port configuration + myDiscoveryInfoProvider.configureEndpoint(host="prefix.iot.us-east-1.amazonaws.com", port=8888) + + **Parameters** + + *host* - String that denotes the host name of the user-specific AWS IoT endpoint. + + *port* - Integer that denotes the port number to connect to. For discovery purpose, it is 8443 by default. + + **Returns** + + None + + """ + self._host = host + self._port = port + + def configureCredentials(self, caPath, certPath, keyPath): + """ + + **Description** + + Used to configure the credentials for discovery request. Should be called before the discovery request happens. + + **Syntax** + + .. code:: python + + myDiscoveryInfoProvider.configureCredentials("my/ca/path", "my/cert/path", "my/key/path") + + **Parameters** + + *caPath* - Path to read the root CA file. + + *certPath* - Path to read the certificate file. + + *keyPath* - Path to read the private key file. + + **Returns** + + None + + """ + self._ca_path = caPath + self._cert_path = certPath + self._key_path = keyPath + + def configureTimeout(self, timeoutSec): + """ + + **Description** + + Used to configure the time out in seconds for discovery request sending/response waiting. Should be called before + the discovery request happens. + + **Syntax** + + .. code:: python + + # Configure the time out for discovery to be 10 seconds + myDiscoveryInfoProvider.configureTimeout(10) + + **Parameters** + + *timeoutSec* - Time out configuration in seconds to consider a discovery request sending/response waiting has + been timed out. + + **Returns** + + None + + """ + self._timeout_sec = timeoutSec + + def discover(self, thingName): + """ + + **Description** + + Perform the discovery request for the given Greengrass aware device thing name. + + **Syntax** + + .. code:: python + + myDiscoveryInfoProvider.discover(thingName="myGGAD") + + **Parameters** + + *thingName* - Greengrass aware device thing name. + + **Returns** + + :code:`AWSIoTPythonSDK.core.greengrass.discovery.models.DiscoveryInfo` object. + + """ + self._logger.info("Starting discover request...") + self._logger.info("Endpoint: " + self._host + ":" + str(self._port)) + self._logger.info("Target thing: " + thingName) + sock = self._create_tcp_connection() + ssl_sock = self._create_ssl_connection(sock) + self._raise_on_timeout(self._send_discovery_request(ssl_sock, thingName)) + status_code, response_body = self._receive_discovery_response(ssl_sock) + + return self._raise_if_not_200(status_code, response_body) + + def _create_tcp_connection(self): + self._logger.debug("Creating tcp connection...") + try: + if (sys.version_info[0] == 2 and sys.version_info[1] < 7) or (sys.version_info[0] == 3 and sys.version_info[1] < 2): + sock = socket.create_connection((self._host, self._port)) + else: + sock = socket.create_connection((self._host, self._port), source_address=("", 0)) + return sock + except socket.error as err: + if err.errno != errno.EINPROGRESS and err.errno != errno.EWOULDBLOCK and err.errno != EAGAIN: + raise + self._logger.debug("Created tcp connection.") + + def _create_ssl_connection(self, sock): + self._logger.debug("Creating ssl connection...") + + ssl_protocol_version = ssl.PROTOCOL_SSLv23 + + if self._port == 443: + ssl_context = SSLContextBuilder()\ + .with_ca_certs(self._ca_path)\ + .with_cert_key_pair(self._cert_path, self._key_path)\ + .with_cert_reqs(ssl.CERT_REQUIRED)\ + .with_check_hostname(True)\ + .with_ciphers(None)\ + .with_alpn_protocols(['x-amzn-http-ca'])\ + .build() + ssl_sock = ssl_context.wrap_socket(sock, server_hostname=self._host, do_handshake_on_connect=False) + ssl_sock.do_handshake() + else: + ssl_sock = ssl.wrap_socket(sock, + certfile=self._cert_path, + keyfile=self._key_path, + ca_certs=self._ca_path, + cert_reqs=ssl.CERT_REQUIRED, + ssl_version=ssl_protocol_version) + + self._logger.debug("Matching host name...") + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 2): + self._tls_match_hostname(ssl_sock) + else: + ssl.match_hostname(ssl_sock.getpeercert(), self._host) + + return ssl_sock + + def _tls_match_hostname(self, ssl_sock): + try: + cert = ssl_sock.getpeercert() + except AttributeError: + # the getpeercert can throw Attribute error: object has no attribute 'peer_certificate' + # Don't let that crash the whole client. See also: http://bugs.python.org/issue13721 + raise ssl.SSLError('Not connected') + + san = cert.get('subjectAltName') + if san: + have_san_dns = False + for (key, value) in san: + if key == 'DNS': + have_san_dns = True + if self._host_matches_cert(self._host.lower(), value.lower()) == True: + return + if key == 'IP Address': + have_san_dns = True + if value.lower() == self._host.lower(): + return + + if have_san_dns: + # Only check subject if subjectAltName dns not found. + raise ssl.SSLError('Certificate subject does not match remote hostname.') + subject = cert.get('subject') + if subject: + for ((key, value),) in subject: + if key == 'commonName': + if self._host_matches_cert(self._host.lower(), value.lower()) == True: + return + + raise ssl.SSLError('Certificate subject does not match remote hostname.') + + def _host_matches_cert(self, host, cert_host): + if cert_host[0:2] == "*.": + if cert_host.count("*") != 1: + return False + + host_match = host.split(".", 1)[1] + cert_match = cert_host.split(".", 1)[1] + if host_match == cert_match: + return True + else: + return False + else: + if host == cert_host: + return True + else: + return False + + def _send_discovery_request(self, ssl_sock, thing_name): + request = self.REQUEST_TYPE_PREFIX + \ + self.PAYLOAD_PREFIX + \ + thing_name + \ + self.PAYLOAD_SUFFIX + \ + self.HOST_PREFIX + \ + self._host + ":" + str(self._port) + \ + self.HOST_SUFFIX + self._logger.debug("Sending discover request: " + request) + + start_time = time.time() + desired_length_to_write = len(request) + actual_length_written = 0 + while True: + try: + length_written = ssl_sock.write(request.encode("utf-8")) + actual_length_written += length_written + except socket.error as err: + if err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE: + pass + if actual_length_written == desired_length_to_write: + return self.LOW_LEVEL_RC_COMPLETE + if start_time + self._timeout_sec < time.time(): + return self.LOW_LEVEL_RC_TIMEOUT + + def _receive_discovery_response(self, ssl_sock): + self._logger.debug("Receiving discover response header...") + rc1, response_header = self._receive_until(ssl_sock, self._got_two_crlfs) + status_code, body_length = self._handle_discovery_response_header(rc1, response_header.decode("utf-8")) + + self._logger.debug("Receiving discover response body...") + rc2, response_body = self._receive_until(ssl_sock, self._got_enough_bytes, body_length) + response_body = self._handle_discovery_response_body(rc2, response_body.decode("utf-8")) + + return status_code, response_body + + def _receive_until(self, ssl_sock, criteria_function, extra_data=None): + start_time = time.time() + response = bytearray() + number_bytes_read = 0 + while True: # Python does not have do-while + try: + response.append(self._convert_to_int_py3(ssl_sock.read(1))) + number_bytes_read += 1 + except socket.error as err: + if err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE: + pass + + if criteria_function((number_bytes_read, response, extra_data)): + return self.LOW_LEVEL_RC_COMPLETE, response + if start_time + self._timeout_sec < time.time(): + return self.LOW_LEVEL_RC_TIMEOUT, response + + def _convert_to_int_py3(self, input_char): + try: + return ord(input_char) + except: + return input_char + + def _got_enough_bytes(self, data): + number_bytes_read, response, target_length = data + return number_bytes_read == int(target_length) + + def _got_two_crlfs(self, data): + number_bytes_read, response, extra_data_unused = data + number_of_crlf = 2 + has_enough_bytes = number_bytes_read > number_of_crlf * 2 - 1 + if has_enough_bytes: + end_of_received = response[number_bytes_read - number_of_crlf * 2 : number_bytes_read] + expected_end_of_response = b"\r\n" * number_of_crlf + return end_of_received == expected_end_of_response + else: + return False + + def _handle_discovery_response_header(self, rc, response): + self._raise_on_timeout(rc) + http_status_code_matcher = re.compile(self.HTTP_RESPONSE_CODE_PATTERN) + http_status_code_matched_groups = http_status_code_matcher.match(response) + content_length_matcher = re.compile(self.CONTENT_LENGTH_PATTERN) + content_length_matched_groups = content_length_matcher.search(response) + return http_status_code_matched_groups.group(1), content_length_matched_groups.group(1) + + def _handle_discovery_response_body(self, rc, response): + self._raise_on_timeout(rc) + return response + + def _raise_on_timeout(self, rc): + if rc == self.LOW_LEVEL_RC_TIMEOUT: + raise DiscoveryTimeoutException() + + def _raise_if_not_200(self, status_code, response_body): # response_body here is str in Py3 + if status_code != self.HTTP_SC_200: + expected_exception = self._expected_exception_map.get(status_code) + if expected_exception: + raise expected_exception + else: + raise DiscoveryFailure(response_body) + return DiscoveryInfo(response_body) diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/jobs/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/jobs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/jobs/thingJobManager.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/jobs/thingJobManager.py new file mode 100644 index 0000000..d2396b2 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/jobs/thingJobManager.py @@ -0,0 +1,156 @@ +# /* +# * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import json + +_BASE_THINGS_TOPIC = "$aws/things/" +_NOTIFY_OPERATION = "notify" +_NOTIFY_NEXT_OPERATION = "notify-next" +_GET_OPERATION = "get" +_START_NEXT_OPERATION = "start-next" +_WILDCARD_OPERATION = "+" +_UPDATE_OPERATION = "update" +_ACCEPTED_REPLY = "accepted" +_REJECTED_REPLY = "rejected" +_WILDCARD_REPLY = "#" + +#Members of this enum are tuples +_JOB_ID_REQUIRED_INDEX = 1 +_JOB_OPERATION_INDEX = 2 + +_STATUS_KEY = 'status' +_STATUS_DETAILS_KEY = 'statusDetails' +_EXPECTED_VERSION_KEY = 'expectedVersion' +_EXEXCUTION_NUMBER_KEY = 'executionNumber' +_INCLUDE_JOB_EXECUTION_STATE_KEY = 'includeJobExecutionState' +_INCLUDE_JOB_DOCUMENT_KEY = 'includeJobDocument' +_CLIENT_TOKEN_KEY = 'clientToken' +_STEP_TIMEOUT_IN_MINUTES_KEY = 'stepTimeoutInMinutes' + +#The type of job topic. +class jobExecutionTopicType(object): + JOB_UNRECOGNIZED_TOPIC = (0, False, '') + JOB_GET_PENDING_TOPIC = (1, False, _GET_OPERATION) + JOB_START_NEXT_TOPIC = (2, False, _START_NEXT_OPERATION) + JOB_DESCRIBE_TOPIC = (3, True, _GET_OPERATION) + JOB_UPDATE_TOPIC = (4, True, _UPDATE_OPERATION) + JOB_NOTIFY_TOPIC = (5, False, _NOTIFY_OPERATION) + JOB_NOTIFY_NEXT_TOPIC = (6, False, _NOTIFY_NEXT_OPERATION) + JOB_WILDCARD_TOPIC = (7, False, _WILDCARD_OPERATION) + +#Members of this enum are tuples +_JOB_SUFFIX_INDEX = 1 +#The type of reply topic, or #JOB_REQUEST_TYPE for topics that are not replies. +class jobExecutionTopicReplyType(object): + JOB_UNRECOGNIZED_TOPIC_TYPE = (0, '') + JOB_REQUEST_TYPE = (1, '') + JOB_ACCEPTED_REPLY_TYPE = (2, '/' + _ACCEPTED_REPLY) + JOB_REJECTED_REPLY_TYPE = (3, '/' + _REJECTED_REPLY) + JOB_WILDCARD_REPLY_TYPE = (4, '/' + _WILDCARD_REPLY) + +_JOB_STATUS_INDEX = 1 +class jobExecutionStatus(object): + JOB_EXECUTION_STATUS_NOT_SET = (0, None) + JOB_EXECUTION_QUEUED = (1, 'QUEUED') + JOB_EXECUTION_IN_PROGRESS = (2, 'IN_PROGRESS') + JOB_EXECUTION_FAILED = (3, 'FAILED') + JOB_EXECUTION_SUCCEEDED = (4, 'SUCCEEDED') + JOB_EXECUTION_CANCELED = (5, 'CANCELED') + JOB_EXECUTION_REJECTED = (6, 'REJECTED') + JOB_EXECUTION_UNKNOWN_STATUS = (99, None) + +def _getExecutionStatus(jobStatus): + try: + return jobStatus[_JOB_STATUS_INDEX] + except KeyError: + return None + +def _isWithoutJobIdTopicType(srcJobExecTopicType): + return (srcJobExecTopicType == jobExecutionTopicType.JOB_GET_PENDING_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_START_NEXT_TOPIC + or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) + +class thingJobManager: + def __init__(self, thingName, clientToken = None): + self._thingName = thingName + self._clientToken = clientToken + + def getJobTopic(self, srcJobExecTopicType, srcJobExecTopicReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None): + if self._thingName is None: + return None + + #Verify topics that only support request type, actually have request type specified for reply + if (srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) and srcJobExecTopicReplyType != jobExecutionTopicReplyType.JOB_REQUEST_TYPE: + return None + + #Verify topics that explicitly do not want a job ID do not have one specified + if (jobId is not None and _isWithoutJobIdTopicType(srcJobExecTopicType)): + return None + + #Verify job ID is present if the topic requires one + if jobId is None and srcJobExecTopicType[_JOB_ID_REQUIRED_INDEX]: + return None + + #Ensure the job operation is a non-empty string + if srcJobExecTopicType[_JOB_OPERATION_INDEX] == '': + return None + + if srcJobExecTopicType[_JOB_ID_REQUIRED_INDEX]: + return '{0}{1}/jobs/{2}/{3}{4}'.format(_BASE_THINGS_TOPIC, self._thingName, str(jobId), srcJobExecTopicType[_JOB_OPERATION_INDEX], srcJobExecTopicReplyType[_JOB_SUFFIX_INDEX]) + elif srcJobExecTopicType == jobExecutionTopicType.JOB_WILDCARD_TOPIC: + return '{0}{1}/jobs/#'.format(_BASE_THINGS_TOPIC, self._thingName) + else: + return '{0}{1}/jobs/{2}{3}'.format(_BASE_THINGS_TOPIC, self._thingName, srcJobExecTopicType[_JOB_OPERATION_INDEX], srcJobExecTopicReplyType[_JOB_SUFFIX_INDEX]) + + def serializeJobExecutionUpdatePayload(self, status, statusDetails=None, expectedVersion=0, executionNumber=0, includeJobExecutionState=False, includeJobDocument=False, stepTimeoutInMinutes=None): + executionStatus = _getExecutionStatus(status) + if executionStatus is None: + return None + payload = {_STATUS_KEY: executionStatus} + if statusDetails: + payload[_STATUS_DETAILS_KEY] = statusDetails + if expectedVersion > 0: + payload[_EXPECTED_VERSION_KEY] = str(expectedVersion) + if executionNumber > 0: + payload[_EXEXCUTION_NUMBER_KEY] = str(executionNumber) + if includeJobExecutionState: + payload[_INCLUDE_JOB_EXECUTION_STATE_KEY] = True + if includeJobDocument: + payload[_INCLUDE_JOB_DOCUMENT_KEY] = True + if self._clientToken is not None: + payload[_CLIENT_TOKEN_KEY] = self._clientToken + if stepTimeoutInMinutes is not None: + payload[_STEP_TIMEOUT_IN_MINUTES_KEY] = stepTimeoutInMinutes + return json.dumps(payload) + + def serializeDescribeJobExecutionPayload(self, executionNumber=0, includeJobDocument=True): + payload = {_INCLUDE_JOB_DOCUMENT_KEY: includeJobDocument} + if executionNumber > 0: + payload[_EXEXCUTION_NUMBER_KEY] = executionNumber + if self._clientToken is not None: + payload[_CLIENT_TOKEN_KEY] = self._clientToken + return json.dumps(payload) + + def serializeStartNextPendingJobExecutionPayload(self, statusDetails=None, stepTimeoutInMinutes=None): + payload = {} + if self._clientToken is not None: + payload[_CLIENT_TOKEN_KEY] = self._clientToken + if statusDetails is not None: + payload[_STATUS_DETAILS_KEY] = statusDetails + if stepTimeoutInMinutes is not None: + payload[_STEP_TIMEOUT_IN_MINUTES_KEY] = stepTimeoutInMinutes + return json.dumps(payload) + + def serializeClientTokenPayload(self): + return json.dumps({_CLIENT_TOKEN_KEY: self._clientToken}) if self._clientToken is not None else '{}' diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/alpn.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/alpn.py new file mode 100644 index 0000000..8da98dd --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/alpn.py @@ -0,0 +1,63 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +try: + import ssl +except: + ssl = None + + +class SSLContextBuilder(object): + + def __init__(self): + self.check_supportability() + self._ssl_context = ssl.create_default_context() + + def check_supportability(self): + if ssl is None: + raise RuntimeError("This platform has no SSL/TLS.") + if not hasattr(ssl, "SSLContext"): + raise NotImplementedError("This platform does not support SSLContext. Python 2.7.10+/3.5+ is required.") + if not hasattr(ssl.SSLContext, "set_alpn_protocols"): + raise NotImplementedError("This platform does not support ALPN as TLS extensions. Python 2.7.10+/3.5+ is required.") + + def with_ca_certs(self, ca_certs): + self._ssl_context.load_verify_locations(ca_certs) + return self + + def with_cert_key_pair(self, cert_file, key_file): + self._ssl_context.load_cert_chain(cert_file, key_file) + return self + + def with_cert_reqs(self, cert_reqs): + self._ssl_context.verify_mode = cert_reqs + return self + + def with_check_hostname(self, check_hostname): + self._ssl_context.check_hostname = check_hostname + return self + + def with_ciphers(self, ciphers): + if ciphers is not None: + self._ssl_context.set_ciphers(ciphers) # set_ciphers() does not allow None input. Use default (do nothing) if None + return self + + def with_alpn_protocols(self, alpn_protocols): + self._ssl_context.set_alpn_protocols(alpn_protocols) + return self + + def build(self): + return self._ssl_context diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/cores.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/cores.py new file mode 100644 index 0000000..df12470 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/connection/cores.py @@ -0,0 +1,699 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +# This class implements the progressive backoff logic for auto-reconnect. +# It manages the reconnect wait time for the current reconnect, controling +# when to increase it and when to reset it. + + +import re +import sys +import ssl +import errno +import struct +import socket +import base64 +import time +import threading +import logging +import os +from datetime import datetime +import hashlib +import hmac +from AWSIoTPythonSDK.exception.AWSIoTExceptions import ClientError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssNoKeyInEnvironmentError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssHandShakeError +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC +try: + from urllib.parse import quote # Python 3+ +except ImportError: + from urllib import quote +# INI config file handling +try: + from configparser import ConfigParser # Python 3+ + from configparser import NoOptionError + from configparser import NoSectionError +except ImportError: + from ConfigParser import ConfigParser + from ConfigParser import NoOptionError + from ConfigParser import NoSectionError + + +class ProgressiveBackOffCore: + # Logger + _logger = logging.getLogger(__name__) + + def __init__(self, srcBaseReconnectTimeSecond=1, srcMaximumReconnectTimeSecond=32, srcMinimumConnectTimeSecond=20): + # The base reconnection time in seconds, default 1 + self._baseReconnectTimeSecond = srcBaseReconnectTimeSecond + # The maximum reconnection time in seconds, default 32 + self._maximumReconnectTimeSecond = srcMaximumReconnectTimeSecond + # The minimum time in milliseconds that a connection must be maintained in order to be considered stable + # Default 20 + self._minimumConnectTimeSecond = srcMinimumConnectTimeSecond + # Current backOff time in seconds, init to equal to 0 + self._currentBackoffTimeSecond = 1 + # Handler for timer + self._resetBackoffTimer = None + + # For custom progressiveBackoff timing configuration + def configTime(self, srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSecond, srcMinimumConnectTimeSecond): + if srcBaseReconnectTimeSecond < 0 or srcMaximumReconnectTimeSecond < 0 or srcMinimumConnectTimeSecond < 0: + self._logger.error("init: Negative time configuration detected.") + raise ValueError("Negative time configuration detected.") + if srcBaseReconnectTimeSecond >= srcMinimumConnectTimeSecond: + self._logger.error("init: Min connect time should be bigger than base reconnect time.") + raise ValueError("Min connect time should be bigger than base reconnect time.") + self._baseReconnectTimeSecond = srcBaseReconnectTimeSecond + self._maximumReconnectTimeSecond = srcMaximumReconnectTimeSecond + self._minimumConnectTimeSecond = srcMinimumConnectTimeSecond + self._currentBackoffTimeSecond = 1 + + # Block the reconnect logic for _currentBackoffTimeSecond + # Update the currentBackoffTimeSecond for the next reconnect + # Cancel the in-waiting timer for resetting backOff time + # This should get called only when a disconnect/reconnect happens + def backOff(self): + self._logger.debug("backOff: current backoff time is: " + str(self._currentBackoffTimeSecond) + " sec.") + if self._resetBackoffTimer is not None: + # Cancel the timer + self._resetBackoffTimer.cancel() + # Block the reconnect logic + time.sleep(self._currentBackoffTimeSecond) + # Update the backoff time + if self._currentBackoffTimeSecond == 0: + # This is the first attempt to connect, set it to base + self._currentBackoffTimeSecond = self._baseReconnectTimeSecond + else: + # r_cur = min(2^n*r_base, r_max) + self._currentBackoffTimeSecond = min(self._maximumReconnectTimeSecond, self._currentBackoffTimeSecond * 2) + + # Start the timer for resetting _currentBackoffTimeSecond + # Will be cancelled upon calling backOff + def startStableConnectionTimer(self): + self._resetBackoffTimer = threading.Timer(self._minimumConnectTimeSecond, + self._connectionStableThenResetBackoffTime) + self._resetBackoffTimer.start() + + def stopStableConnectionTimer(self): + if self._resetBackoffTimer is not None: + # Cancel the timer + self._resetBackoffTimer.cancel() + + # Timer callback to reset _currentBackoffTimeSecond + # If the connection is stable for longer than _minimumConnectTimeSecond, + # reset the currentBackoffTimeSecond to _baseReconnectTimeSecond + def _connectionStableThenResetBackoffTime(self): + self._logger.debug( + "stableConnection: Resetting the backoff time to: " + str(self._baseReconnectTimeSecond) + " sec.") + self._currentBackoffTimeSecond = self._baseReconnectTimeSecond + + +class SigV4Core: + + _logger = logging.getLogger(__name__) + + def __init__(self): + self._aws_access_key_id = "" + self._aws_secret_access_key = "" + self._aws_session_token = "" + self._credentialConfigFilePath = "~/.aws/credentials" + + def setIAMCredentials(self, srcAWSAccessKeyID, srcAWSSecretAccessKey, srcAWSSessionToken): + self._aws_access_key_id = srcAWSAccessKeyID + self._aws_secret_access_key = srcAWSSecretAccessKey + self._aws_session_token = srcAWSSessionToken + + def _createAmazonDate(self): + # Returned as a unicode string in Py3.x + amazonDate = [] + currentTime = datetime.utcnow() + YMDHMS = currentTime.strftime('%Y%m%dT%H%M%SZ') + YMD = YMDHMS[0:YMDHMS.index('T')] + amazonDate.append(YMD) + amazonDate.append(YMDHMS) + return amazonDate + + def _sign(self, key, message): + # Returned as a utf-8 byte string in Py3.x + return hmac.new(key, message.encode('utf-8'), hashlib.sha256).digest() + + def _getSignatureKey(self, key, dateStamp, regionName, serviceName): + # Returned as a utf-8 byte string in Py3.x + kDate = self._sign(('AWS4' + key).encode('utf-8'), dateStamp) + kRegion = self._sign(kDate, regionName) + kService = self._sign(kRegion, serviceName) + kSigning = self._sign(kService, 'aws4_request') + return kSigning + + def _checkIAMCredentials(self): + # Check custom config + ret = self._checkKeyInCustomConfig() + # Check environment variables + if not ret: + ret = self._checkKeyInEnv() + # Check files + if not ret: + ret = self._checkKeyInFiles() + # All credentials returned as unicode strings in Py3.x + return ret + + def _checkKeyInEnv(self): + ret = dict() + self._aws_access_key_id = os.environ.get('AWS_ACCESS_KEY_ID') + self._aws_secret_access_key = os.environ.get('AWS_SECRET_ACCESS_KEY') + self._aws_session_token = os.environ.get('AWS_SESSION_TOKEN') + if self._aws_access_key_id is not None and self._aws_secret_access_key is not None: + ret["aws_access_key_id"] = self._aws_access_key_id + ret["aws_secret_access_key"] = self._aws_secret_access_key + # We do not necessarily need session token... + if self._aws_session_token is not None: + ret["aws_session_token"] = self._aws_session_token + self._logger.debug("IAM credentials from env var.") + return ret + + def _checkKeyInINIDefault(self, srcConfigParser, sectionName): + ret = dict() + # Check aws_access_key_id and aws_secret_access_key + try: + ret["aws_access_key_id"] = srcConfigParser.get(sectionName, "aws_access_key_id") + ret["aws_secret_access_key"] = srcConfigParser.get(sectionName, "aws_secret_access_key") + except NoOptionError: + self._logger.warn("Cannot find IAM keyID/secretKey in credential file.") + # We do not continue searching if we cannot even get IAM id/secret right + if len(ret) == 2: + # Check aws_session_token, optional + try: + ret["aws_session_token"] = srcConfigParser.get(sectionName, "aws_session_token") + except NoOptionError: + self._logger.debug("No AWS Session Token found.") + return ret + + def _checkKeyInFiles(self): + credentialFile = None + credentialConfig = None + ret = dict() + # Should be compatible with aws cli default credential configuration + # *NIX/Windows + try: + # See if we get the file + credentialConfig = ConfigParser() + credentialFilePath = os.path.expanduser(self._credentialConfigFilePath) # Is it compatible with windows? \/ + credentialConfig.read(credentialFilePath) + # Now we have the file, start looking for credentials... + # 'default' section + ret = self._checkKeyInINIDefault(credentialConfig, "default") + if not ret: + # 'DEFAULT' section + ret = self._checkKeyInINIDefault(credentialConfig, "DEFAULT") + self._logger.debug("IAM credentials from file.") + except IOError: + self._logger.debug("No IAM credential configuration file in " + credentialFilePath) + except NoSectionError: + self._logger.error("Cannot find IAM 'default' section.") + return ret + + def _checkKeyInCustomConfig(self): + ret = dict() + if self._aws_access_key_id != "" and self._aws_secret_access_key != "": + ret["aws_access_key_id"] = self._aws_access_key_id + ret["aws_secret_access_key"] = self._aws_secret_access_key + # We do not necessarily need session token... + if self._aws_session_token != "": + ret["aws_session_token"] = self._aws_session_token + self._logger.debug("IAM credentials from custom config.") + return ret + + def createWebsocketEndpoint(self, host, port, region, method, awsServiceName, path): + # Return the endpoint as unicode string in 3.x + # Gather all the facts + amazonDate = self._createAmazonDate() + amazonDateSimple = amazonDate[0] # Unicode in 3.x + amazonDateComplex = amazonDate[1] # Unicode in 3.x + allKeys = self._checkIAMCredentials() # Unicode in 3.x + if not self._hasCredentialsNecessaryForWebsocket(allKeys): + raise wssNoKeyInEnvironmentError() + else: + # Because of self._hasCredentialsNecessaryForWebsocket(...), keyID and secretKey should not be None from here + keyID = allKeys["aws_access_key_id"] + secretKey = allKeys["aws_secret_access_key"] + # amazonDateSimple and amazonDateComplex are guaranteed not to be None + queryParameters = "X-Amz-Algorithm=AWS4-HMAC-SHA256" + \ + "&X-Amz-Credential=" + keyID + "%2F" + amazonDateSimple + "%2F" + region + "%2F" + awsServiceName + "%2Faws4_request" + \ + "&X-Amz-Date=" + amazonDateComplex + \ + "&X-Amz-Expires=86400" + \ + "&X-Amz-SignedHeaders=host" # Unicode in 3.x + hashedPayload = hashlib.sha256(str("").encode('utf-8')).hexdigest() # Unicode in 3.x + # Create the string to sign + signedHeaders = "host" + canonicalHeaders = "host:" + host + "\n" + canonicalRequest = method + "\n" + path + "\n" + queryParameters + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedPayload # Unicode in 3.x + hashedCanonicalRequest = hashlib.sha256(str(canonicalRequest).encode('utf-8')).hexdigest() # Unicoede in 3.x + stringToSign = "AWS4-HMAC-SHA256\n" + amazonDateComplex + "\n" + amazonDateSimple + "/" + region + "/" + awsServiceName + "/aws4_request\n" + hashedCanonicalRequest # Unicode in 3.x + # Sign it + signingKey = self._getSignatureKey(secretKey, amazonDateSimple, region, awsServiceName) + signature = hmac.new(signingKey, (stringToSign).encode("utf-8"), hashlib.sha256).hexdigest() + # generate url + url = "wss://" + host + ":" + str(port) + path + '?' + queryParameters + "&X-Amz-Signature=" + signature + # See if we have STS token, if we do, add it + awsSessionTokenCandidate = allKeys.get("aws_session_token") + if awsSessionTokenCandidate is not None and len(awsSessionTokenCandidate) != 0: + aws_session_token = allKeys["aws_session_token"] + url += "&X-Amz-Security-Token=" + quote(aws_session_token.encode("utf-8")) # Unicode in 3.x + self._logger.debug("createWebsocketEndpoint: Websocket URL: " + url) + return url + + def _hasCredentialsNecessaryForWebsocket(self, allKeys): + awsAccessKeyIdCandidate = allKeys.get("aws_access_key_id") + awsSecretAccessKeyCandidate = allKeys.get("aws_secret_access_key") + # None value is NOT considered as valid entries + validEntries = awsAccessKeyIdCandidate is not None and awsAccessKeyIdCandidate is not None + if validEntries: + # Empty value is NOT considered as valid entries + validEntries &= (len(awsAccessKeyIdCandidate) != 0 and len(awsSecretAccessKeyCandidate) != 0) + return validEntries + + +# This is an internal class that buffers the incoming bytes into an +# internal buffer until it gets the full desired length of bytes. +# At that time, this bufferedReader will be reset. +# *Error handling: +# For retry errors (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE, EAGAIN), +# leave them to the paho _packet_read for further handling (ignored and try +# again when data is available. +# For other errors, leave them to the paho _packet_read for error reporting. + + +class _BufferedReader: + _sslSocket = None + _internalBuffer = None + _remainedLength = -1 + _bufferingInProgress = False + + def __init__(self, sslSocket): + self._sslSocket = sslSocket + self._internalBuffer = bytearray() + self._bufferingInProgress = False + + def _reset(self): + self._internalBuffer = bytearray() + self._remainedLength = -1 + self._bufferingInProgress = False + + def read(self, numberOfBytesToBeBuffered): + if not self._bufferingInProgress: # If last read is completed... + self._remainedLength = numberOfBytesToBeBuffered + self._bufferingInProgress = True # Now we start buffering a new length of bytes + + while self._remainedLength > 0: # Read in a loop, always try to read in the remained length + # If the data is temporarily not available, socket.error will be raised and catched by paho + dataChunk = self._sslSocket.read(self._remainedLength) + # There is a chance where the server terminates the connection without closing the socket. + # If that happens, let's raise an exception and enter the reconnect flow. + if not dataChunk: + raise socket.error(errno.ECONNABORTED, 0) + self._internalBuffer.extend(dataChunk) # Buffer the data + self._remainedLength -= len(dataChunk) # Update the remained length + + # The requested length of bytes is buffered, recover the context and return it + # Otherwise error should be raised + ret = self._internalBuffer + self._reset() + return ret # This should always be bytearray + + +# This is the internal class that sends requested data out chunk by chunk according +# to the availablity of the socket write operation. If the requested bytes of data +# (after encoding) needs to be sent out in separate socket write operations (most +# probably be interrupted by the error socket.error (errno = ssl.SSL_ERROR_WANT_WRITE).) +# , the write pointer is stored to ensure that the continued bytes will be sent next +# time this function gets called. +# *Error handling: +# For retry errors (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE, EAGAIN), +# leave them to the paho _packet_read for further handling (ignored and try +# again when data is available. +# For other errors, leave them to the paho _packet_read for error reporting. + + +class _BufferedWriter: + _sslSocket = None + _internalBuffer = None + _writingInProgress = False + _requestedDataLength = -1 + + def __init__(self, sslSocket): + self._sslSocket = sslSocket + self._internalBuffer = bytearray() + self._writingInProgress = False + self._requestedDataLength = -1 + + def _reset(self): + self._internalBuffer = bytearray() + self._writingInProgress = False + self._requestedDataLength = -1 + + # Input data for this function needs to be an encoded wss frame + # Always request for packet[pos=0:] (raw MQTT data) + def write(self, encodedData, payloadLength): + # encodedData should always be bytearray + # Check if we have a frame that is partially sent + if not self._writingInProgress: + self._internalBuffer = encodedData + self._writingInProgress = True + self._requestedDataLength = payloadLength + # Now, write as much as we can + lengthWritten = self._sslSocket.write(self._internalBuffer) + self._internalBuffer = self._internalBuffer[lengthWritten:] + # This MQTT packet has been sent out in a wss frame, completely + if len(self._internalBuffer) == 0: + ret = self._requestedDataLength + self._reset() + return ret + # This socket write is half-baked... + else: + return 0 # Ensure that the 'pos' inside the MQTT packet never moves since we have not finished the transmission of this encoded frame + + +class SecuredWebSocketCore: + # Websocket Constants + _OP_CONTINUATION = 0x0 + _OP_TEXT = 0x1 + _OP_BINARY = 0x2 + _OP_CONNECTION_CLOSE = 0x8 + _OP_PING = 0x9 + _OP_PONG = 0xa + # Websocket Connect Status + _WebsocketConnectInit = -1 + _WebsocketDisconnected = 1 + + _logger = logging.getLogger(__name__) + + def __init__(self, socket, hostAddress, portNumber, AWSAccessKeyID="", AWSSecretAccessKey="", AWSSessionToken=""): + self._connectStatus = self._WebsocketConnectInit + # Handlers + self._sslSocket = socket + self._sigV4Handler = self._createSigV4Core() + self._sigV4Handler.setIAMCredentials(AWSAccessKeyID, AWSSecretAccessKey, AWSSessionToken) + # Endpoint Info + self._hostAddress = hostAddress + self._portNumber = portNumber + # Section Flags + self._hasOpByte = False + self._hasPayloadLengthFirst = False + self._hasPayloadLengthExtended = False + self._hasMaskKey = False + self._hasPayload = False + # Properties for current websocket frame + self._isFIN = False + self._RSVBits = None + self._opCode = None + self._needMaskKey = False + self._payloadLengthBytesLength = 1 + self._payloadLength = 0 + self._maskKey = None + self._payloadDataBuffer = bytearray() # Once the whole wss connection is lost, there is no need to keep the buffered payload + try: + self._handShake(hostAddress, portNumber) + except wssNoKeyInEnvironmentError: # Handle SigV4 signing and websocket handshaking errors + raise ValueError("No Access Key/KeyID Error") + except wssHandShakeError: + raise ValueError("Websocket Handshake Error") + except ClientError as e: + raise ValueError(e.message) + # Now we have a socket with secured websocket... + self._bufferedReader = _BufferedReader(self._sslSocket) + self._bufferedWriter = _BufferedWriter(self._sslSocket) + + def _createSigV4Core(self): + return SigV4Core() + + def _generateMaskKey(self): + return bytearray(os.urandom(4)) + # os.urandom returns ascii str in 2.x, converted to bytearray + # os.urandom returns bytes in 3.x, converted to bytearray + + def _reset(self): # Reset the context for wss frame reception + # Control info + self._hasOpByte = False + self._hasPayloadLengthFirst = False + self._hasPayloadLengthExtended = False + self._hasMaskKey = False + self._hasPayload = False + # Frame Info + self._isFIN = False + self._RSVBits = None + self._opCode = None + self._needMaskKey = False + self._payloadLengthBytesLength = 1 + self._payloadLength = 0 + self._maskKey = None + # Never reset the payloadData since we might have fragmented MQTT data from the pervious frame + + def _generateWSSKey(self): + return base64.b64encode(os.urandom(128)) # Bytes + + def _verifyWSSResponse(self, response, clientKey): + # Check if it is a 101 response + rawResponse = response.strip().lower() + if b"101 switching protocols" not in rawResponse or b"upgrade: websocket" not in rawResponse or b"connection: upgrade" not in rawResponse: + return False + # Parse out the sec-websocket-accept + WSSAcceptKeyIndex = response.strip().index(b"sec-websocket-accept: ") + len(b"sec-websocket-accept: ") + rawSecWebSocketAccept = response.strip()[WSSAcceptKeyIndex:].split(b"\r\n")[0].strip() + # Verify the WSSAcceptKey + return self._verifyWSSAcceptKey(rawSecWebSocketAccept, clientKey) + + def _verifyWSSAcceptKey(self, srcAcceptKey, clientKey): + GUID = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + verifyServerAcceptKey = base64.b64encode((hashlib.sha1(clientKey + GUID)).digest()) # Bytes + return srcAcceptKey == verifyServerAcceptKey + + def _handShake(self, hostAddress, portNumber): + CRLF = "\r\n" + IOT_ENDPOINT_PATTERN = r"^[0-9a-zA-Z]+(\.ats|-ats)?\.iot\.(.*)\.amazonaws\..*" + matched = re.compile(IOT_ENDPOINT_PATTERN, re.IGNORECASE).match(hostAddress) + if not matched: + raise ClientError("Invalid endpoint pattern for wss: %s" % hostAddress) + region = matched.group(2) + signedURL = self._sigV4Handler.createWebsocketEndpoint(hostAddress, portNumber, region, "GET", "iotdata", "/mqtt") + # Now we got a signedURL + path = signedURL[signedURL.index("/mqtt"):] + # Assemble HTTP request headers + Method = "GET " + path + " HTTP/1.1" + CRLF + Host = "Host: " + hostAddress + CRLF + Connection = "Connection: " + "Upgrade" + CRLF + Upgrade = "Upgrade: " + "websocket" + CRLF + secWebSocketVersion = "Sec-WebSocket-Version: " + "13" + CRLF + rawSecWebSocketKey = self._generateWSSKey() # Bytes + secWebSocketKey = "sec-websocket-key: " + rawSecWebSocketKey.decode('utf-8') + CRLF # Should be randomly generated... + secWebSocketProtocol = "Sec-WebSocket-Protocol: " + "mqttv3.1" + CRLF + secWebSocketExtensions = "Sec-WebSocket-Extensions: " + "permessage-deflate; client_max_window_bits" + CRLF + # Send the HTTP request + # Ensure that we are sending bytes, not by any chance unicode string + handshakeBytes = Method + Host + Connection + Upgrade + secWebSocketVersion + secWebSocketProtocol + secWebSocketExtensions + secWebSocketKey + CRLF + handshakeBytes = handshakeBytes.encode('utf-8') + self._sslSocket.write(handshakeBytes) + # Read it back (Non-blocking socket) + timeStart = time.time() + wssHandshakeResponse = bytearray() + while len(wssHandshakeResponse) == 0: + try: + wssHandshakeResponse += self._sslSocket.read(1024) # Response is always less than 1024 bytes + except socket.error as err: + if err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE: + if time.time() - timeStart > self._getTimeoutSec(): + raise err # We make sure that reconnect gets retried in Paho upon a wss reconnect response timeout + else: + raise err + # Verify response + # Now both wssHandshakeResponse and rawSecWebSocketKey are byte strings + if not self._verifyWSSResponse(wssHandshakeResponse, rawSecWebSocketKey): + raise wssHandShakeError() + else: + pass + + def _getTimeoutSec(self): + return DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC + + # Used to create a single wss frame + # Assume that the maximum length of a MQTT packet never exceeds the maximum length + # for a wss frame. Therefore, the FIN bit for the encoded frame will always be 1. + # Frames are encoded as BINARY frames. + def _encodeFrame(self, rawPayload, opCode, masked=1): + ret = bytearray() + # Op byte + opByte = 0x80 | opCode # Always a FIN, no RSV bits + ret.append(opByte) + # Payload Length bytes + maskBit = masked + payloadLength = len(rawPayload) + if payloadLength <= 125: + ret.append((maskBit << 7) | payloadLength) + elif payloadLength <= 0xffff: # 16-bit unsigned int + ret.append((maskBit << 7) | 126) + ret.extend(struct.pack("!H", payloadLength)) + elif payloadLength <= 0x7fffffffffffffff: # 64-bit unsigned int (most significant bit must be 0) + ret.append((maskBit << 7) | 127) + ret.extend(struct.pack("!Q", payloadLength)) + else: # Overflow + raise ValueError("Exceeds the maximum number of bytes for a single websocket frame.") + if maskBit == 1: + # Mask key bytes + maskKey = self._generateMaskKey() + ret.extend(maskKey) + # Mask the payload + payloadBytes = bytearray(rawPayload) + if maskBit == 1: + for i in range(0, payloadLength): + payloadBytes[i] ^= maskKey[i % 4] + ret.extend(payloadBytes) + # Return the assembled wss frame + return ret + + # Used for the wss client to close a wss connection + # Create and send a masked wss closing frame + def _closeWssConnection(self): + # Frames sent from client to server must be masked + self._sslSocket.write(self._encodeFrame(b"", self._OP_CONNECTION_CLOSE, masked=1)) + + # Used for the wss client to respond to a wss PING from server + # Create and send a masked PONG frame + def _sendPONG(self): + # Frames sent from client to server must be masked + self._sslSocket.write(self._encodeFrame(b"", self._OP_PONG, masked=1)) + + # Override sslSocket read. Always read from the wss internal payload buffer, which + # contains the masked MQTT packet. This read will decode ONE wss frame every time + # and load in the payload for MQTT _packet_read. At any time, MQTT _packet_read + # should be able to read a complete MQTT packet from the payload (buffered per wss + # frame payload). If the MQTT packet is break into separate wss frames, different + # chunks will be buffered in separate frames and MQTT _packet_read will not be able + # to collect a complete MQTT packet to operate on until the necessary payload is + # fully buffered. + # If the requested number of bytes are not available, SSL_ERROR_WANT_READ will be + # raised to trigger another call of _packet_read when the data is available again. + def read(self, numberOfBytes): + # Check if we have enough data for paho + # _payloadDataBuffer will not be empty ony when the payload of a new wss frame + # has been unmasked. + if len(self._payloadDataBuffer) >= numberOfBytes: + ret = self._payloadDataBuffer[0:numberOfBytes] + self._payloadDataBuffer = self._payloadDataBuffer[numberOfBytes:] + # struct.unpack(fmt, string) # Py2.x + # struct.unpack(fmt, buffer) # Py3.x + # Here ret is always in bytes (buffer interface) + if sys.version_info[0] < 3: # Py2.x + ret = str(ret) + return ret + # Emmm, We don't. Try to buffer from the socket (It's a new wss frame). + if not self._hasOpByte: # Check if we need to buffer OpByte + opByte = self._bufferedReader.read(1) + self._isFIN = (opByte[0] & 0x80) == 0x80 + self._RSVBits = (opByte[0] & 0x70) + self._opCode = (opByte[0] & 0x0f) + self._hasOpByte = True # Finished buffering opByte + # Check if any of the RSV bits are set, if so, close the connection + # since client never sends negotiated extensions + if self._RSVBits != 0x0: + self._closeWssConnection() + self._connectStatus = self._WebsocketDisconnected + self._payloadDataBuffer = bytearray() + raise socket.error(ssl.SSL_ERROR_WANT_READ, "RSV bits set with NO negotiated extensions.") + if not self._hasPayloadLengthFirst: # Check if we need to buffer First Payload Length byte + payloadLengthFirst = self._bufferedReader.read(1) + self._hasPayloadLengthFirst = True # Finished buffering first byte of payload length + self._needMaskKey = (payloadLengthFirst[0] & 0x80) == 0x80 + payloadLengthFirstByteArray = bytearray() + payloadLengthFirstByteArray.extend(payloadLengthFirst) + self._payloadLength = (payloadLengthFirstByteArray[0] & 0x7f) + + if self._payloadLength == 126: + self._payloadLengthBytesLength = 2 + self._hasPayloadLengthExtended = False # Force to buffer the extended + elif self._payloadLength == 127: + self._payloadLengthBytesLength = 8 + self._hasPayloadLengthExtended = False # Force to buffer the extended + else: # _payloadLength <= 125: + self._hasPayloadLengthExtended = True # No need to buffer extended payload length + if not self._hasPayloadLengthExtended: # Check if we need to buffer Extended Payload Length bytes + payloadLengthExtended = self._bufferedReader.read(self._payloadLengthBytesLength) + self._hasPayloadLengthExtended = True + if sys.version_info[0] < 3: + payloadLengthExtended = str(payloadLengthExtended) + if self._payloadLengthBytesLength == 2: + self._payloadLength = struct.unpack("!H", payloadLengthExtended)[0] + else: # _payloadLengthBytesLength == 8 + self._payloadLength = struct.unpack("!Q", payloadLengthExtended)[0] + + if self._needMaskKey: # Response from server is masked, close the connection + self._closeWssConnection() + self._connectStatus = self._WebsocketDisconnected + self._payloadDataBuffer = bytearray() + raise socket.error(ssl.SSL_ERROR_WANT_READ, "Server response masked, closing connection and try again.") + + if not self._hasPayload: # Check if we need to buffer the payload + payloadForThisFrame = self._bufferedReader.read(self._payloadLength) + self._hasPayload = True + # Client side should never received a masked packet from the server side + # Unmask it as needed + #if self._needMaskKey: + # for i in range(0, self._payloadLength): + # payloadForThisFrame[i] ^= self._maskKey[i % 4] + # Append it to the internal payload buffer + self._payloadDataBuffer.extend(payloadForThisFrame) + # Now we have the complete wss frame, reset the context + # Check to see if it is a wss closing frame + if self._opCode == self._OP_CONNECTION_CLOSE: + self._connectStatus = self._WebsocketDisconnected + self._payloadDataBuffer = bytearray() # Ensure that once the wss closing frame comes, we have nothing to read and start all over again + # Check to see if it is a wss PING frame + if self._opCode == self._OP_PING: + self._sendPONG() # Nothing more to do here, if the transmission of the last wssMQTT packet is not finished, it will continue + self._reset() + # Check again if we have enough data for paho + if len(self._payloadDataBuffer) >= numberOfBytes: + ret = self._payloadDataBuffer[0:numberOfBytes] + self._payloadDataBuffer = self._payloadDataBuffer[numberOfBytes:] + # struct.unpack(fmt, string) # Py2.x + # struct.unpack(fmt, buffer) # Py3.x + # Here ret is always in bytes (buffer interface) + if sys.version_info[0] < 3: # Py2.x + ret = str(ret) + return ret + else: # Fragmented MQTT packets in separate wss frames + raise socket.error(ssl.SSL_ERROR_WANT_READ, "Not a complete MQTT packet payload within this wss frame.") + + def write(self, bytesToBeSent): + # When there is a disconnection, select will report a TypeError which triggers the reconnect. + # In reconnect, Paho will set the socket object (mocked by wss) to None, blocking other ops + # before a connection is re-established. + # This 'low-level' socket write op should always be able to write to plain socket. + # Error reporting is performed by Python socket itself. + # Wss closing frame handling is performed in the wss read. + return self._bufferedWriter.write(self._encodeFrame(bytesToBeSent, self._OP_BINARY, 1), len(bytesToBeSent)) + + def close(self): + if self._sslSocket is not None: + self._sslSocket.close() + self._sslSocket = None + + def getpeercert(self): + return self._sslSocket.getpeercert() + + def getSSLSocket(self): + if self._connectStatus != self._WebsocketDisconnected: + return self._sslSocket + else: + return None # Leave the sslSocket to Paho to close it. (_ssl.close() -> wssCore.close()) diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/clients.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/clients.py new file mode 100644 index 0000000..bb670f7 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/clients.py @@ -0,0 +1,244 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import ssl +import logging +from threading import Lock +from numbers import Number +import AWSIoTPythonSDK.core.protocol.paho.client as mqtt +from AWSIoTPythonSDK.core.protocol.paho.client import MQTT_ERR_SUCCESS +from AWSIoTPythonSDK.core.protocol.internal.events import FixedEventMids + + +class ClientStatus(object): + + IDLE = 0 + CONNECT = 1 + RESUBSCRIBE = 2 + DRAINING = 3 + STABLE = 4 + USER_DISCONNECT = 5 + ABNORMAL_DISCONNECT = 6 + + +class ClientStatusContainer(object): + + def __init__(self): + self._status = ClientStatus.IDLE + + def get_status(self): + return self._status + + def set_status(self, status): + if ClientStatus.USER_DISCONNECT == self._status: # If user requests to disconnect, no status updates other than user connect + if ClientStatus.CONNECT == status: + self._status = status + else: + self._status = status + + +class InternalAsyncMqttClient(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, client_id, clean_session, protocol, use_wss): + self._paho_client = self._create_paho_client(client_id, clean_session, None, protocol, use_wss) + self._use_wss = use_wss + self._event_callback_map_lock = Lock() + self._event_callback_map = dict() + + def _create_paho_client(self, client_id, clean_session, user_data, protocol, use_wss): + self._logger.debug("Initializing MQTT layer...") + return mqtt.Client(client_id, clean_session, user_data, protocol, use_wss) + + # TODO: Merge credentials providers configuration into one + def set_cert_credentials_provider(self, cert_credentials_provider): + # History issue from Yun SDK where AR9331 embedded Linux only have Python 2.7.3 + # pre-installed. In this version, TLSv1_2 is not even an option. + # SSLv23 is a work-around which selects the highest TLS version between the client + # and service. If user installs opensslv1.0.1+, this option will work fine for Mutual + # Auth. + # Note that we cannot force TLSv1.2 for Mutual Auth. in Python 2.7.3 and TLS support + # in Python only starts from Python2.7. + # See also: https://docs.python.org/2/library/ssl.html#ssl.PROTOCOL_SSLv23 + if self._use_wss: + ca_path = cert_credentials_provider.get_ca_path() + self._paho_client.tls_set(ca_certs=ca_path, cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_SSLv23) + else: + ca_path = cert_credentials_provider.get_ca_path() + cert_path = cert_credentials_provider.get_cert_path() + key_path = cert_credentials_provider.get_key_path() + self._paho_client.tls_set(ca_certs=ca_path,certfile=cert_path, keyfile=key_path, + cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_SSLv23) + + def set_iam_credentials_provider(self, iam_credentials_provider): + self._paho_client.configIAMCredentials(iam_credentials_provider.get_access_key_id(), + iam_credentials_provider.get_secret_access_key(), + iam_credentials_provider.get_session_token()) + + def set_endpoint_provider(self, endpoint_provider): + self._endpoint_provider = endpoint_provider + + def configure_last_will(self, topic, payload, qos, retain=False): + self._paho_client.will_set(topic, payload, qos, retain) + + def configure_alpn_protocols(self, alpn_protocols): + self._paho_client.config_alpn_protocols(alpn_protocols) + + def clear_last_will(self): + self._paho_client.will_clear() + + def set_username_password(self, username, password=None): + self._paho_client.username_pw_set(username, password) + + def set_socket_factory(self, socket_factory): + self._paho_client.socket_factory_set(socket_factory) + + def configure_reconnect_back_off(self, base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec): + self._paho_client.setBackoffTiming(base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec) + + def connect(self, keep_alive_sec, ack_callback=None): + host = self._endpoint_provider.get_host() + port = self._endpoint_provider.get_port() + + with self._event_callback_map_lock: + self._logger.debug("Filling in fixed event callbacks: CONNACK, DISCONNECT, MESSAGE") + self._event_callback_map[FixedEventMids.CONNACK_MID] = self._create_combined_on_connect_callback(ack_callback) + self._event_callback_map[FixedEventMids.DISCONNECT_MID] = self._create_combined_on_disconnect_callback(None) + self._event_callback_map[FixedEventMids.MESSAGE_MID] = self._create_converted_on_message_callback() + + rc = self._paho_client.connect(host, port, keep_alive_sec) + if MQTT_ERR_SUCCESS == rc: + self.start_background_network_io() + + return rc + + def start_background_network_io(self): + self._logger.debug("Starting network I/O thread...") + self._paho_client.loop_start() + + def stop_background_network_io(self): + self._logger.debug("Stopping network I/O thread...") + self._paho_client.loop_stop() + + def disconnect(self, ack_callback=None): + with self._event_callback_map_lock: + rc = self._paho_client.disconnect() + if MQTT_ERR_SUCCESS == rc: + self._logger.debug("Filling in custom disconnect event callback...") + combined_on_disconnect_callback = self._create_combined_on_disconnect_callback(ack_callback) + self._event_callback_map[FixedEventMids.DISCONNECT_MID] = combined_on_disconnect_callback + return rc + + def _create_combined_on_connect_callback(self, ack_callback): + def combined_on_connect_callback(mid, data): + self.on_online() + if ack_callback: + ack_callback(mid, data) + return combined_on_connect_callback + + def _create_combined_on_disconnect_callback(self, ack_callback): + def combined_on_disconnect_callback(mid, data): + self.on_offline() + if ack_callback: + ack_callback(mid, data) + return combined_on_disconnect_callback + + def _create_converted_on_message_callback(self): + def converted_on_message_callback(mid, data): + self.on_message(data) + return converted_on_message_callback + + # For client online notification + def on_online(self): + pass + + # For client offline notification + def on_offline(self): + pass + + # For client message reception notification + def on_message(self, message): + pass + + def publish(self, topic, payload, qos, retain=False, ack_callback=None): + with self._event_callback_map_lock: + rc, mid = self._paho_client.publish(topic, payload, qos, retain) + if MQTT_ERR_SUCCESS == rc and qos > 0 and ack_callback: + self._logger.debug("Filling in custom puback (QoS>0) event callback...") + self._event_callback_map[mid] = ack_callback + return rc, mid + + def subscribe(self, topic, qos, ack_callback=None): + with self._event_callback_map_lock: + rc, mid = self._paho_client.subscribe(topic, qos) + if MQTT_ERR_SUCCESS == rc and ack_callback: + self._logger.debug("Filling in custom suback event callback...") + self._event_callback_map[mid] = ack_callback + return rc, mid + + def unsubscribe(self, topic, ack_callback=None): + with self._event_callback_map_lock: + rc, mid = self._paho_client.unsubscribe(topic) + if MQTT_ERR_SUCCESS == rc and ack_callback: + self._logger.debug("Filling in custom unsuback event callback...") + self._event_callback_map[mid] = ack_callback + return rc, mid + + def register_internal_event_callbacks(self, on_connect, on_disconnect, on_publish, on_subscribe, on_unsubscribe, on_message): + self._logger.debug("Registering internal event callbacks to MQTT layer...") + self._paho_client.on_connect = on_connect + self._paho_client.on_disconnect = on_disconnect + self._paho_client.on_publish = on_publish + self._paho_client.on_subscribe = on_subscribe + self._paho_client.on_unsubscribe = on_unsubscribe + self._paho_client.on_message = on_message + + def unregister_internal_event_callbacks(self): + self._logger.debug("Unregistering internal event callbacks from MQTT layer...") + self._paho_client.on_connect = None + self._paho_client.on_disconnect = None + self._paho_client.on_publish = None + self._paho_client.on_subscribe = None + self._paho_client.on_unsubscribe = None + self._paho_client.on_message = None + + def invoke_event_callback(self, mid, data=None): + with self._event_callback_map_lock: + event_callback = self._event_callback_map.get(mid) + # For invoking the event callback, we do not need to acquire the lock + if event_callback: + self._logger.debug("Invoking custom event callback...") + if data is not None: + event_callback(mid=mid, data=data) + else: + event_callback(mid=mid) + if isinstance(mid, Number): # Do NOT remove callbacks for CONNACK/DISCONNECT/MESSAGE + self._logger.debug("This custom event callback is for pub/sub/unsub, removing it after invocation...") + with self._event_callback_map_lock: + del self._event_callback_map[mid] + + def remove_event_callback(self, mid): + with self._event_callback_map_lock: + if mid in self._event_callback_map: + self._logger.debug("Removing custom event callback...") + del self._event_callback_map[mid] + + def clean_up_event_callbacks(self): + with self._event_callback_map_lock: + self._event_callback_map.clear() + + def get_event_callback_map(self): + return self._event_callback_map diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/defaults.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/defaults.py new file mode 100644 index 0000000..66817d3 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/defaults.py @@ -0,0 +1,20 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC = 30 +DEFAULT_OPERATION_TIMEOUT_SEC = 5 +DEFAULT_DRAINING_INTERNAL_SEC = 0.5 +METRICS_PREFIX = "?SDK=Python&Version=" +ALPN_PROTCOLS = "x-amzn-mqtt-ca" \ No newline at end of file diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/events.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/events.py new file mode 100644 index 0000000..90f0b70 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/events.py @@ -0,0 +1,29 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +class EventTypes(object): + CONNACK = 0 + DISCONNECT = 1 + PUBACK = 2 + SUBACK = 3 + UNSUBACK = 4 + MESSAGE = 5 + + +class FixedEventMids(object): + CONNACK_MID = "CONNECTED" + DISCONNECT_MID = "DISCONNECTED" + MESSAGE_MID = "MESSAGE" + QUEUED_MID = "QUEUED" diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/queues.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/queues.py new file mode 100644 index 0000000..77046a8 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/queues.py @@ -0,0 +1,87 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import logging +from AWSIoTPythonSDK.core.util.enums import DropBehaviorTypes + + +class AppendResults(object): + APPEND_FAILURE_QUEUE_FULL = -1 + APPEND_FAILURE_QUEUE_DISABLED = -2 + APPEND_SUCCESS = 0 + + +class OfflineRequestQueue(list): + _logger = logging.getLogger(__name__) + + def __init__(self, max_size, drop_behavior=DropBehaviorTypes.DROP_NEWEST): + if not isinstance(max_size, int) or not isinstance(drop_behavior, int): + self._logger.error("init: MaximumSize/DropBehavior must be integer.") + raise TypeError("MaximumSize/DropBehavior must be integer.") + if drop_behavior != DropBehaviorTypes.DROP_OLDEST and drop_behavior != DropBehaviorTypes.DROP_NEWEST: + self._logger.error("init: Drop behavior not supported.") + raise ValueError("Drop behavior not supported.") + + list.__init__([]) + self._drop_behavior = drop_behavior + # When self._maximumSize > 0, queue is limited + # When self._maximumSize == 0, queue is disabled + # When self._maximumSize < 0. queue is infinite + self._max_size = max_size + + def _is_enabled(self): + return self._max_size != 0 + + def _need_drop_messages(self): + # Need to drop messages when: + # 1. Queue is limited and full + # 2. Queue is disabled + is_queue_full = len(self) >= self._max_size + is_queue_limited = self._max_size > 0 + is_queue_disabled = not self._is_enabled() + return (is_queue_full and is_queue_limited) or is_queue_disabled + + def set_behavior_drop_newest(self): + self._drop_behavior = DropBehaviorTypes.DROP_NEWEST + + def set_behavior_drop_oldest(self): + self._drop_behavior = DropBehaviorTypes.DROP_OLDEST + + # Override + # Append to a queue with a limited size. + # Return APPEND_SUCCESS if the append is successful + # Return APPEND_FAILURE_QUEUE_FULL if the append failed because the queue is full + # Return APPEND_FAILURE_QUEUE_DISABLED if the append failed because the queue is disabled + def append(self, data): + ret = AppendResults.APPEND_SUCCESS + if self._is_enabled(): + if self._need_drop_messages(): + # We should drop the newest + if DropBehaviorTypes.DROP_NEWEST == self._drop_behavior: + self._logger.warn("append: Full queue. Drop the newest: " + str(data)) + ret = AppendResults.APPEND_FAILURE_QUEUE_FULL + # We should drop the oldest + else: + current_oldest = super(OfflineRequestQueue, self).pop(0) + self._logger.warn("append: Full queue. Drop the oldest: " + str(current_oldest)) + super(OfflineRequestQueue, self).append(data) + ret = AppendResults.APPEND_FAILURE_QUEUE_FULL + else: + self._logger.debug("append: Add new element: " + str(data)) + super(OfflineRequestQueue, self).append(data) + else: + self._logger.debug("append: Queue is disabled. Drop the message: " + str(data)) + ret = AppendResults.APPEND_FAILURE_QUEUE_DISABLED + return ret diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/requests.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/requests.py new file mode 100644 index 0000000..bd2585d --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/requests.py @@ -0,0 +1,27 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +class RequestTypes(object): + CONNECT = 0 + DISCONNECT = 1 + PUBLISH = 2 + SUBSCRIBE = 3 + UNSUBSCRIBE = 4 + +class QueueableRequest(object): + + def __init__(self, type, data): + self.type = type + self.data = data # Can be a tuple diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/workers.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/workers.py new file mode 100644 index 0000000..e52db3f --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/internal/workers.py @@ -0,0 +1,296 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import time +import logging +from threading import Thread +from threading import Event +from AWSIoTPythonSDK.core.protocol.internal.events import EventTypes +from AWSIoTPythonSDK.core.protocol.internal.events import FixedEventMids +from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatus +from AWSIoTPythonSDK.core.protocol.internal.queues import OfflineRequestQueue +from AWSIoTPythonSDK.core.protocol.internal.requests import RequestTypes +from AWSIoTPythonSDK.core.protocol.paho.client import topic_matches_sub +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_DRAINING_INTERNAL_SEC + + +class EventProducer(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, cv, event_queue): + self._cv = cv + self._event_queue = event_queue + + def on_connect(self, client, user_data, flags, rc): + self._add_to_queue(FixedEventMids.CONNACK_MID, EventTypes.CONNACK, rc) + self._logger.debug("Produced [connack] event") + + def on_disconnect(self, client, user_data, rc): + self._add_to_queue(FixedEventMids.DISCONNECT_MID, EventTypes.DISCONNECT, rc) + self._logger.debug("Produced [disconnect] event") + + def on_publish(self, client, user_data, mid): + self._add_to_queue(mid, EventTypes.PUBACK, None) + self._logger.debug("Produced [puback] event") + + def on_subscribe(self, client, user_data, mid, granted_qos): + self._add_to_queue(mid, EventTypes.SUBACK, granted_qos) + self._logger.debug("Produced [suback] event") + + def on_unsubscribe(self, client, user_data, mid): + self._add_to_queue(mid, EventTypes.UNSUBACK, None) + self._logger.debug("Produced [unsuback] event") + + def on_message(self, client, user_data, message): + self._add_to_queue(FixedEventMids.MESSAGE_MID, EventTypes.MESSAGE, message) + self._logger.debug("Produced [message] event") + + def _add_to_queue(self, mid, event_type, data): + with self._cv: + self._event_queue.put((mid, event_type, data)) + self._cv.notify() + + +class EventConsumer(object): + + MAX_DISPATCH_INTERNAL_SEC = 0.01 + _logger = logging.getLogger(__name__) + + def __init__(self, cv, event_queue, internal_async_client, + subscription_manager, offline_requests_manager, client_status): + self._cv = cv + self._event_queue = event_queue + self._internal_async_client = internal_async_client + self._subscription_manager = subscription_manager + self._offline_requests_manager = offline_requests_manager + self._client_status = client_status + self._is_running = False + self._draining_interval_sec = DEFAULT_DRAINING_INTERNAL_SEC + self._dispatch_methods = { + EventTypes.CONNACK : self._dispatch_connack, + EventTypes.DISCONNECT : self._dispatch_disconnect, + EventTypes.PUBACK : self._dispatch_puback, + EventTypes.SUBACK : self._dispatch_suback, + EventTypes.UNSUBACK : self._dispatch_unsuback, + EventTypes.MESSAGE : self._dispatch_message + } + self._offline_request_handlers = { + RequestTypes.PUBLISH : self._handle_offline_publish, + RequestTypes.SUBSCRIBE : self._handle_offline_subscribe, + RequestTypes.UNSUBSCRIBE : self._handle_offline_unsubscribe + } + self._stopper = Event() + + def update_offline_requests_manager(self, offline_requests_manager): + self._offline_requests_manager = offline_requests_manager + + def update_draining_interval_sec(self, draining_interval_sec): + self._draining_interval_sec = draining_interval_sec + + def get_draining_interval_sec(self): + return self._draining_interval_sec + + def is_running(self): + return self._is_running + + def start(self): + self._stopper.clear() + self._is_running = True + dispatch_events = Thread(target=self._dispatch) + dispatch_events.daemon = True + dispatch_events.start() + self._logger.debug("Event consuming thread started") + + def stop(self): + if self._is_running: + self._is_running = False + self._clean_up() + self._logger.debug("Event consuming thread stopped") + + def _clean_up(self): + self._logger.debug("Cleaning up before stopping event consuming") + with self._event_queue.mutex: + self._event_queue.queue.clear() + self._logger.debug("Event queue cleared") + self._internal_async_client.stop_background_network_io() + self._logger.debug("Network thread stopped") + self._internal_async_client.clean_up_event_callbacks() + self._logger.debug("Event callbacks cleared") + + def wait_until_it_stops(self, timeout_sec): + self._logger.debug("Waiting for event consumer to completely stop") + return self._stopper.wait(timeout=timeout_sec) + + def is_fully_stopped(self): + return self._stopper.is_set() + + def _dispatch(self): + while self._is_running: + with self._cv: + if self._event_queue.empty(): + self._cv.wait(self.MAX_DISPATCH_INTERNAL_SEC) + else: + while not self._event_queue.empty(): + self._dispatch_one() + self._stopper.set() + self._logger.debug("Exiting dispatching loop...") + + def _dispatch_one(self): + mid, event_type, data = self._event_queue.get() + if mid: + self._dispatch_methods[event_type](mid, data) + self._internal_async_client.invoke_event_callback(mid, data=data) + # We need to make sure disconnect event gets dispatched and then we stop the consumer + if self._need_to_stop_dispatching(mid): + self.stop() + + def _need_to_stop_dispatching(self, mid): + status = self._client_status.get_status() + return (ClientStatus.USER_DISCONNECT == status or ClientStatus.CONNECT == status) \ + and mid == FixedEventMids.DISCONNECT_MID + + def _dispatch_connack(self, mid, rc): + status = self._client_status.get_status() + self._logger.debug("Dispatching [connack] event") + if self._need_recover(): + if ClientStatus.STABLE != status: # To avoid multiple connack dispatching + self._logger.debug("Has recovery job") + clean_up_debt = Thread(target=self._clean_up_debt) + clean_up_debt.start() + else: + self._logger.debug("No need for recovery") + self._client_status.set_status(ClientStatus.STABLE) + + def _need_recover(self): + return self._subscription_manager.list_records() or self._offline_requests_manager.has_more() + + def _clean_up_debt(self): + self._handle_resubscribe() + self._handle_draining() + self._client_status.set_status(ClientStatus.STABLE) + + def _handle_resubscribe(self): + subscriptions = self._subscription_manager.list_records() + if subscriptions and not self._has_user_disconnect_request(): + self._logger.debug("Start resubscribing") + self._client_status.set_status(ClientStatus.RESUBSCRIBE) + for topic, (qos, message_callback, ack_callback) in subscriptions: + if self._has_user_disconnect_request(): + self._logger.debug("User disconnect detected") + break + self._internal_async_client.subscribe(topic, qos, ack_callback) + + def _handle_draining(self): + if self._offline_requests_manager.has_more() and not self._has_user_disconnect_request(): + self._logger.debug("Start draining") + self._client_status.set_status(ClientStatus.DRAINING) + while self._offline_requests_manager.has_more(): + if self._has_user_disconnect_request(): + self._logger.debug("User disconnect detected") + break + offline_request = self._offline_requests_manager.get_next() + if offline_request: + self._offline_request_handlers[offline_request.type](offline_request) + time.sleep(self._draining_interval_sec) + + def _has_user_disconnect_request(self): + return ClientStatus.USER_DISCONNECT == self._client_status.get_status() + + def _dispatch_disconnect(self, mid, rc): + self._logger.debug("Dispatching [disconnect] event") + status = self._client_status.get_status() + if ClientStatus.USER_DISCONNECT == status or ClientStatus.CONNECT == status: + pass + else: + self._client_status.set_status(ClientStatus.ABNORMAL_DISCONNECT) + + # For puback, suback and unsuback, ack callback invocation is handled in dispatch_one + # Do nothing in the event dispatching itself + def _dispatch_puback(self, mid, rc): + self._logger.debug("Dispatching [puback] event") + + def _dispatch_suback(self, mid, rc): + self._logger.debug("Dispatching [suback] event") + + def _dispatch_unsuback(self, mid, rc): + self._logger.debug("Dispatching [unsuback] event") + + def _dispatch_message(self, mid, message): + self._logger.debug("Dispatching [message] event") + subscriptions = self._subscription_manager.list_records() + if subscriptions: + for topic, (qos, message_callback, _) in subscriptions: + if topic_matches_sub(topic, message.topic) and message_callback: + message_callback(None, None, message) # message_callback(client, userdata, message) + + def _handle_offline_publish(self, request): + topic, payload, qos, retain = request.data + self._internal_async_client.publish(topic, payload, qos, retain) + self._logger.debug("Processed offline publish request") + + def _handle_offline_subscribe(self, request): + topic, qos, message_callback, ack_callback = request.data + self._subscription_manager.add_record(topic, qos, message_callback, ack_callback) + self._internal_async_client.subscribe(topic, qos, ack_callback) + self._logger.debug("Processed offline subscribe request") + + def _handle_offline_unsubscribe(self, request): + topic, ack_callback = request.data + self._subscription_manager.remove_record(topic) + self._internal_async_client.unsubscribe(topic, ack_callback) + self._logger.debug("Processed offline unsubscribe request") + + +class SubscriptionManager(object): + + _logger = logging.getLogger(__name__) + + def __init__(self): + self._subscription_map = dict() + + def add_record(self, topic, qos, message_callback, ack_callback): + self._logger.debug("Adding a new subscription record: %s qos: %d", topic, qos) + self._subscription_map[topic] = qos, message_callback, ack_callback # message_callback and/or ack_callback could be None + + def remove_record(self, topic): + self._logger.debug("Removing subscription record: %s", topic) + if self._subscription_map.get(topic): # Ignore topics that are never subscribed to + del self._subscription_map[topic] + else: + self._logger.warn("Removing attempt for non-exist subscription record: %s", topic) + + def list_records(self): + return list(self._subscription_map.items()) + + +class OfflineRequestsManager(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, max_size, drop_behavior): + self._queue = OfflineRequestQueue(max_size, drop_behavior) + + def has_more(self): + return len(self._queue) > 0 + + def add_one(self, request): + return self._queue.append(request) + + def get_next(self): + if self.has_more(): + return self._queue.pop(0) + else: + return None diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/mqtt_core.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/mqtt_core.py new file mode 100644 index 0000000..e2f98fc --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/mqtt_core.py @@ -0,0 +1,373 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import AWSIoTPythonSDK +from AWSIoTPythonSDK.core.protocol.internal.clients import InternalAsyncMqttClient +from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatusContainer +from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatus +from AWSIoTPythonSDK.core.protocol.internal.workers import EventProducer +from AWSIoTPythonSDK.core.protocol.internal.workers import EventConsumer +from AWSIoTPythonSDK.core.protocol.internal.workers import SubscriptionManager +from AWSIoTPythonSDK.core.protocol.internal.workers import OfflineRequestsManager +from AWSIoTPythonSDK.core.protocol.internal.requests import RequestTypes +from AWSIoTPythonSDK.core.protocol.internal.requests import QueueableRequest +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC +from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_OPERATION_TIMEOUT_SEC +from AWSIoTPythonSDK.core.protocol.internal.defaults import METRICS_PREFIX +from AWSIoTPythonSDK.core.protocol.internal.defaults import ALPN_PROTCOLS +from AWSIoTPythonSDK.core.protocol.internal.events import FixedEventMids +from AWSIoTPythonSDK.core.protocol.paho.client import MQTT_ERR_SUCCESS +from AWSIoTPythonSDK.exception.AWSIoTExceptions import connectError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import connectTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import disconnectError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import disconnectTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishQueueFullException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishQueueDisabledException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeQueueFullException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeQueueDisabledException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeQueueFullException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeQueueDisabledException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeTimeoutException +from AWSIoTPythonSDK.core.protocol.internal.queues import AppendResults +from AWSIoTPythonSDK.core.util.enums import DropBehaviorTypes +from AWSIoTPythonSDK.core.protocol.paho.client import MQTTv31 +from threading import Condition +from threading import Event +import logging +import sys +if sys.version_info[0] < 3: + from Queue import Queue +else: + from queue import Queue + + +class MqttCore(object): + + _logger = logging.getLogger(__name__) + + def __init__(self, client_id, clean_session, protocol, use_wss): + self._use_wss = use_wss + self._username = "" + self._password = None + self._enable_metrics_collection = True + self._event_queue = Queue() + self._event_cv = Condition() + self._event_producer = EventProducer(self._event_cv, self._event_queue) + self._client_status = ClientStatusContainer() + self._internal_async_client = InternalAsyncMqttClient(client_id, clean_session, protocol, use_wss) + self._subscription_manager = SubscriptionManager() + self._offline_requests_manager = OfflineRequestsManager(-1, DropBehaviorTypes.DROP_NEWEST) # Infinite queue + self._event_consumer = EventConsumer(self._event_cv, + self._event_queue, + self._internal_async_client, + self._subscription_manager, + self._offline_requests_manager, + self._client_status) + self._connect_disconnect_timeout_sec = DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC + self._operation_timeout_sec = DEFAULT_OPERATION_TIMEOUT_SEC + self._init_offline_request_exceptions() + self._init_workers() + self._logger.info("MqttCore initialized") + self._logger.info("Client id: %s" % client_id) + self._logger.info("Protocol version: %s" % ("MQTTv3.1" if protocol == MQTTv31 else "MQTTv3.1.1")) + self._logger.info("Authentication type: %s" % ("SigV4 WebSocket" if use_wss else "TLSv1.2 certificate based Mutual Auth.")) + + def _init_offline_request_exceptions(self): + self._offline_request_queue_disabled_exceptions = { + RequestTypes.PUBLISH : publishQueueDisabledException(), + RequestTypes.SUBSCRIBE : subscribeQueueDisabledException(), + RequestTypes.UNSUBSCRIBE : unsubscribeQueueDisabledException() + } + self._offline_request_queue_full_exceptions = { + RequestTypes.PUBLISH : publishQueueFullException(), + RequestTypes.SUBSCRIBE : subscribeQueueFullException(), + RequestTypes.UNSUBSCRIBE : unsubscribeQueueFullException() + } + + def _init_workers(self): + self._internal_async_client.register_internal_event_callbacks(self._event_producer.on_connect, + self._event_producer.on_disconnect, + self._event_producer.on_publish, + self._event_producer.on_subscribe, + self._event_producer.on_unsubscribe, + self._event_producer.on_message) + + def _start_workers(self): + self._event_consumer.start() + + def use_wss(self): + return self._use_wss + + # Used for general message event reception + def on_message(self, message): + pass + + # Used for general online event notification + def on_online(self): + pass + + # Used for general offline event notification + def on_offline(self): + pass + + def configure_cert_credentials(self, cert_credentials_provider): + self._logger.info("Configuring certificates...") + self._internal_async_client.set_cert_credentials_provider(cert_credentials_provider) + + def configure_iam_credentials(self, iam_credentials_provider): + self._logger.info("Configuring custom IAM credentials...") + self._internal_async_client.set_iam_credentials_provider(iam_credentials_provider) + + def configure_endpoint(self, endpoint_provider): + self._logger.info("Configuring endpoint...") + self._internal_async_client.set_endpoint_provider(endpoint_provider) + + def configure_connect_disconnect_timeout_sec(self, connect_disconnect_timeout_sec): + self._logger.info("Configuring connect/disconnect time out: %f sec" % connect_disconnect_timeout_sec) + self._connect_disconnect_timeout_sec = connect_disconnect_timeout_sec + + def configure_operation_timeout_sec(self, operation_timeout_sec): + self._logger.info("Configuring MQTT operation time out: %f sec" % operation_timeout_sec) + self._operation_timeout_sec = operation_timeout_sec + + def configure_reconnect_back_off(self, base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec): + self._logger.info("Configuring reconnect back off timing...") + self._logger.info("Base quiet time: %f sec" % base_reconnect_quiet_sec) + self._logger.info("Max quiet time: %f sec" % max_reconnect_quiet_sec) + self._logger.info("Stable connection time: %f sec" % stable_connection_sec) + self._internal_async_client.configure_reconnect_back_off(base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec) + + def configure_alpn_protocols(self): + self._logger.info("Configuring alpn protocols...") + self._internal_async_client.configure_alpn_protocols([ALPN_PROTCOLS]) + + def configure_last_will(self, topic, payload, qos, retain=False): + self._logger.info("Configuring last will...") + self._internal_async_client.configure_last_will(topic, payload, qos, retain) + + def clear_last_will(self): + self._logger.info("Clearing last will...") + self._internal_async_client.clear_last_will() + + def configure_username_password(self, username, password=None): + self._logger.info("Configuring username and password...") + self._username = username + self._password = password + + def configure_socket_factory(self, socket_factory): + self._logger.info("Configuring socket factory...") + self._internal_async_client.set_socket_factory(socket_factory) + + def enable_metrics_collection(self): + self._enable_metrics_collection = True + + def disable_metrics_collection(self): + self._enable_metrics_collection = False + + def configure_offline_requests_queue(self, max_size, drop_behavior): + self._logger.info("Configuring offline requests queueing: max queue size: %d", max_size) + self._offline_requests_manager = OfflineRequestsManager(max_size, drop_behavior) + self._event_consumer.update_offline_requests_manager(self._offline_requests_manager) + + def configure_draining_interval_sec(self, draining_interval_sec): + self._logger.info("Configuring offline requests queue draining interval: %f sec", draining_interval_sec) + self._event_consumer.update_draining_interval_sec(draining_interval_sec) + + def connect(self, keep_alive_sec): + self._logger.info("Performing sync connect...") + event = Event() + self.connect_async(keep_alive_sec, self._create_blocking_ack_callback(event)) + if not event.wait(self._connect_disconnect_timeout_sec): + self._logger.error("Connect timed out") + raise connectTimeoutException() + return True + + def connect_async(self, keep_alive_sec, ack_callback=None): + self._logger.info("Performing async connect...") + self._logger.info("Keep-alive: %f sec" % keep_alive_sec) + self._start_workers() + self._load_callbacks() + self._load_username_password() + + try: + self._client_status.set_status(ClientStatus.CONNECT) + rc = self._internal_async_client.connect(keep_alive_sec, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Connect error: %d", rc) + raise connectError(rc) + except Exception as e: + # Provided any error in connect, we should clean up the threads that have been created + self._event_consumer.stop() + if not self._event_consumer.wait_until_it_stops(self._connect_disconnect_timeout_sec): + self._logger.error("Time out in waiting for event consumer to stop") + else: + self._logger.debug("Event consumer stopped") + self._client_status.set_status(ClientStatus.IDLE) + raise e + + return FixedEventMids.CONNACK_MID + + def _load_callbacks(self): + self._logger.debug("Passing in general notification callbacks to internal client...") + self._internal_async_client.on_online = self.on_online + self._internal_async_client.on_offline = self.on_offline + self._internal_async_client.on_message = self.on_message + + def _load_username_password(self): + username_candidate = self._username + if self._enable_metrics_collection: + username_candidate += METRICS_PREFIX + username_candidate += AWSIoTPythonSDK.__version__ + self._internal_async_client.set_username_password(username_candidate, self._password) + + def disconnect(self): + self._logger.info("Performing sync disconnect...") + event = Event() + self.disconnect_async(self._create_blocking_ack_callback(event)) + if not event.wait(self._connect_disconnect_timeout_sec): + self._logger.error("Disconnect timed out") + raise disconnectTimeoutException() + if not self._event_consumer.wait_until_it_stops(self._connect_disconnect_timeout_sec): + self._logger.error("Disconnect timed out in waiting for event consumer") + raise disconnectTimeoutException() + return True + + def disconnect_async(self, ack_callback=None): + self._logger.info("Performing async disconnect...") + self._client_status.set_status(ClientStatus.USER_DISCONNECT) + rc = self._internal_async_client.disconnect(ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Disconnect error: %d", rc) + raise disconnectError(rc) + return FixedEventMids.DISCONNECT_MID + + def publish(self, topic, payload, qos, retain=False): + self._logger.info("Performing sync publish...") + ret = False + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.PUBLISH, (topic, payload, qos, retain)) + else: + if qos > 0: + event = Event() + rc, mid = self._publish_async(topic, payload, qos, retain, self._create_blocking_ack_callback(event)) + if not event.wait(self._operation_timeout_sec): + self._internal_async_client.remove_event_callback(mid) + self._logger.error("Publish timed out") + raise publishTimeoutException() + else: + self._publish_async(topic, payload, qos, retain) + ret = True + return ret + + def publish_async(self, topic, payload, qos, retain=False, ack_callback=None): + self._logger.info("Performing async publish...") + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.PUBLISH, (topic, payload, qos, retain)) + return FixedEventMids.QUEUED_MID + else: + rc, mid = self._publish_async(topic, payload, qos, retain, ack_callback) + return mid + + def _publish_async(self, topic, payload, qos, retain=False, ack_callback=None): + rc, mid = self._internal_async_client.publish(topic, payload, qos, retain, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Publish error: %d", rc) + raise publishError(rc) + return rc, mid + + def subscribe(self, topic, qos, message_callback=None): + self._logger.info("Performing sync subscribe...") + ret = False + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.SUBSCRIBE, (topic, qos, message_callback, None)) + else: + event = Event() + rc, mid = self._subscribe_async(topic, qos, self._create_blocking_ack_callback(event), message_callback) + if not event.wait(self._operation_timeout_sec): + self._internal_async_client.remove_event_callback(mid) + self._logger.error("Subscribe timed out") + raise subscribeTimeoutException() + ret = True + return ret + + def subscribe_async(self, topic, qos, ack_callback=None, message_callback=None): + self._logger.info("Performing async subscribe...") + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.SUBSCRIBE, (topic, qos, message_callback, ack_callback)) + return FixedEventMids.QUEUED_MID + else: + rc, mid = self._subscribe_async(topic, qos, ack_callback, message_callback) + return mid + + def _subscribe_async(self, topic, qos, ack_callback=None, message_callback=None): + self._subscription_manager.add_record(topic, qos, message_callback, ack_callback) + rc, mid = self._internal_async_client.subscribe(topic, qos, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Subscribe error: %d", rc) + raise subscribeError(rc) + return rc, mid + + def unsubscribe(self, topic): + self._logger.info("Performing sync unsubscribe...") + ret = False + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.UNSUBSCRIBE, (topic, None)) + else: + event = Event() + rc, mid = self._unsubscribe_async(topic, self._create_blocking_ack_callback(event)) + if not event.wait(self._operation_timeout_sec): + self._internal_async_client.remove_event_callback(mid) + self._logger.error("Unsubscribe timed out") + raise unsubscribeTimeoutException() + ret = True + return ret + + def unsubscribe_async(self, topic, ack_callback=None): + self._logger.info("Performing async unsubscribe...") + if ClientStatus.STABLE != self._client_status.get_status(): + self._handle_offline_request(RequestTypes.UNSUBSCRIBE, (topic, ack_callback)) + return FixedEventMids.QUEUED_MID + else: + rc, mid = self._unsubscribe_async(topic, ack_callback) + return mid + + def _unsubscribe_async(self, topic, ack_callback=None): + self._subscription_manager.remove_record(topic) + rc, mid = self._internal_async_client.unsubscribe(topic, ack_callback) + if MQTT_ERR_SUCCESS != rc: + self._logger.error("Unsubscribe error: %d", rc) + raise unsubscribeError(rc) + return rc, mid + + def _create_blocking_ack_callback(self, event): + def ack_callback(mid, data=None): + event.set() + return ack_callback + + def _handle_offline_request(self, type, data): + self._logger.info("Offline request detected!") + offline_request = QueueableRequest(type, data) + append_result = self._offline_requests_manager.add_one(offline_request) + if AppendResults.APPEND_FAILURE_QUEUE_DISABLED == append_result: + self._logger.error("Offline request queue has been disabled") + raise self._offline_request_queue_disabled_exceptions[type] + if AppendResults.APPEND_FAILURE_QUEUE_FULL == append_result: + self._logger.error("Offline request queue is full") + raise self._offline_request_queue_full_exceptions[type] diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/paho/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/paho/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/paho/client.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/paho/client.py new file mode 100644 index 0000000..503d1c6 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/protocol/paho/client.py @@ -0,0 +1,2445 @@ +# Copyright (c) 2012-2014 Roger Light +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# and Eclipse Distribution License v1.0 which accompany this distribution. +# +# The Eclipse Public License is available at +# http://www.eclipse.org/legal/epl-v10.html +# and the Eclipse Distribution License is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# Contributors: +# Roger Light - initial API and implementation + +""" +This is an MQTT v3.1 client module. MQTT is a lightweight pub/sub messaging +protocol that is easy to implement and suitable for low powered devices. +""" +import errno +import platform +import random +import select +import socket +HAVE_SSL = True +try: + import ssl + cert_reqs = ssl.CERT_REQUIRED + tls_version = ssl.PROTOCOL_TLSv1 +except: + HAVE_SSL = False + cert_reqs = None + tls_version = None +import struct +import sys +import threading +import time +HAVE_DNS = True +try: + import dns.resolver +except ImportError: + HAVE_DNS = False + +if platform.system() == 'Windows': + EAGAIN = errno.WSAEWOULDBLOCK +else: + EAGAIN = errno.EAGAIN + +from AWSIoTPythonSDK.core.protocol.connection.cores import ProgressiveBackOffCore +from AWSIoTPythonSDK.core.protocol.connection.cores import SecuredWebSocketCore +from AWSIoTPythonSDK.core.protocol.connection.alpn import SSLContextBuilder + +VERSION_MAJOR=1 +VERSION_MINOR=0 +VERSION_REVISION=0 +VERSION_NUMBER=(VERSION_MAJOR*1000000+VERSION_MINOR*1000+VERSION_REVISION) + +MQTTv31 = 3 +MQTTv311 = 4 + +if sys.version_info[0] < 3: + PROTOCOL_NAMEv31 = "MQIsdp" + PROTOCOL_NAMEv311 = "MQTT" +else: + PROTOCOL_NAMEv31 = b"MQIsdp" + PROTOCOL_NAMEv311 = b"MQTT" + +PROTOCOL_VERSION = 3 + +# Message types +CONNECT = 0x10 +CONNACK = 0x20 +PUBLISH = 0x30 +PUBACK = 0x40 +PUBREC = 0x50 +PUBREL = 0x60 +PUBCOMP = 0x70 +SUBSCRIBE = 0x80 +SUBACK = 0x90 +UNSUBSCRIBE = 0xA0 +UNSUBACK = 0xB0 +PINGREQ = 0xC0 +PINGRESP = 0xD0 +DISCONNECT = 0xE0 + +# Log levels +MQTT_LOG_INFO = 0x01 +MQTT_LOG_NOTICE = 0x02 +MQTT_LOG_WARNING = 0x04 +MQTT_LOG_ERR = 0x08 +MQTT_LOG_DEBUG = 0x10 + +# CONNACK codes +CONNACK_ACCEPTED = 0 +CONNACK_REFUSED_PROTOCOL_VERSION = 1 +CONNACK_REFUSED_IDENTIFIER_REJECTED = 2 +CONNACK_REFUSED_SERVER_UNAVAILABLE = 3 +CONNACK_REFUSED_BAD_USERNAME_PASSWORD = 4 +CONNACK_REFUSED_NOT_AUTHORIZED = 5 + +# Connection state +mqtt_cs_new = 0 +mqtt_cs_connected = 1 +mqtt_cs_disconnecting = 2 +mqtt_cs_connect_async = 3 + +# Message state +mqtt_ms_invalid = 0 +mqtt_ms_publish= 1 +mqtt_ms_wait_for_puback = 2 +mqtt_ms_wait_for_pubrec = 3 +mqtt_ms_resend_pubrel = 4 +mqtt_ms_wait_for_pubrel = 5 +mqtt_ms_resend_pubcomp = 6 +mqtt_ms_wait_for_pubcomp = 7 +mqtt_ms_send_pubrec = 8 +mqtt_ms_queued = 9 + +# Error values +MQTT_ERR_AGAIN = -1 +MQTT_ERR_SUCCESS = 0 +MQTT_ERR_NOMEM = 1 +MQTT_ERR_PROTOCOL = 2 +MQTT_ERR_INVAL = 3 +MQTT_ERR_NO_CONN = 4 +MQTT_ERR_CONN_REFUSED = 5 +MQTT_ERR_NOT_FOUND = 6 +MQTT_ERR_CONN_LOST = 7 +MQTT_ERR_TLS = 8 +MQTT_ERR_PAYLOAD_SIZE = 9 +MQTT_ERR_NOT_SUPPORTED = 10 +MQTT_ERR_AUTH = 11 +MQTT_ERR_ACL_DENIED = 12 +MQTT_ERR_UNKNOWN = 13 +MQTT_ERR_ERRNO = 14 + +# MessageQueueing DropBehavior +MSG_QUEUEING_DROP_OLDEST = 0 +MSG_QUEUEING_DROP_NEWEST = 1 + +if sys.version_info[0] < 3: + sockpair_data = "0" +else: + sockpair_data = b"0" + +def error_string(mqtt_errno): + """Return the error string associated with an mqtt error number.""" + if mqtt_errno == MQTT_ERR_SUCCESS: + return "No error." + elif mqtt_errno == MQTT_ERR_NOMEM: + return "Out of memory." + elif mqtt_errno == MQTT_ERR_PROTOCOL: + return "A network protocol error occurred when communicating with the broker." + elif mqtt_errno == MQTT_ERR_INVAL: + return "Invalid function arguments provided." + elif mqtt_errno == MQTT_ERR_NO_CONN: + return "The client is not currently connected." + elif mqtt_errno == MQTT_ERR_CONN_REFUSED: + return "The connection was refused." + elif mqtt_errno == MQTT_ERR_NOT_FOUND: + return "Message not found (internal error)." + elif mqtt_errno == MQTT_ERR_CONN_LOST: + return "The connection was lost." + elif mqtt_errno == MQTT_ERR_TLS: + return "A TLS error occurred." + elif mqtt_errno == MQTT_ERR_PAYLOAD_SIZE: + return "Payload too large." + elif mqtt_errno == MQTT_ERR_NOT_SUPPORTED: + return "This feature is not supported." + elif mqtt_errno == MQTT_ERR_AUTH: + return "Authorisation failed." + elif mqtt_errno == MQTT_ERR_ACL_DENIED: + return "Access denied by ACL." + elif mqtt_errno == MQTT_ERR_UNKNOWN: + return "Unknown error." + elif mqtt_errno == MQTT_ERR_ERRNO: + return "Error defined by errno." + else: + return "Unknown error." + + +def connack_string(connack_code): + """Return the string associated with a CONNACK result.""" + if connack_code == 0: + return "Connection Accepted." + elif connack_code == 1: + return "Connection Refused: unacceptable protocol version." + elif connack_code == 2: + return "Connection Refused: identifier rejected." + elif connack_code == 3: + return "Connection Refused: broker unavailable." + elif connack_code == 4: + return "Connection Refused: bad user name or password." + elif connack_code == 5: + return "Connection Refused: not authorised." + else: + return "Connection Refused: unknown reason." + + +def topic_matches_sub(sub, topic): + """Check whether a topic matches a subscription. + + For example: + + foo/bar would match the subscription foo/# or +/bar + non/matching would not match the subscription non/+/+ + """ + result = True + multilevel_wildcard = False + + slen = len(sub) + tlen = len(topic) + + if slen > 0 and tlen > 0: + if (sub[0] == '$' and topic[0] != '$') or (topic[0] == '$' and sub[0] != '$'): + return False + + spos = 0 + tpos = 0 + + while spos < slen and tpos < tlen: + if sub[spos] == topic[tpos]: + if tpos == tlen-1: + # Check for e.g. foo matching foo/# + if spos == slen-3 and sub[spos+1] == '/' and sub[spos+2] == '#': + result = True + multilevel_wildcard = True + break + + spos += 1 + tpos += 1 + + if tpos == tlen and spos == slen-1 and sub[spos] == '+': + spos += 1 + result = True + break + else: + if sub[spos] == '+': + spos += 1 + while tpos < tlen and topic[tpos] != '/': + tpos += 1 + if tpos == tlen and spos == slen: + result = True + break + + elif sub[spos] == '#': + multilevel_wildcard = True + if spos+1 != slen: + result = False + break + else: + result = True + break + + else: + result = False + break + + if not multilevel_wildcard and (tpos < tlen or spos < slen): + result = False + + return result + + +def _socketpair_compat(): + """TCP/IP socketpair including Windows support""" + listensock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_IP) + listensock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + listensock.bind(("127.0.0.1", 0)) + listensock.listen(1) + + iface, port = listensock.getsockname() + sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_IP) + sock1.setblocking(0) + try: + sock1.connect(("127.0.0.1", port)) + except socket.error as err: + if err.errno != errno.EINPROGRESS and err.errno != errno.EWOULDBLOCK and err.errno != EAGAIN: + raise + sock2, address = listensock.accept() + sock2.setblocking(0) + listensock.close() + return (sock1, sock2) + + +class MQTTMessage: + """ This is a class that describes an incoming message. It is passed to the + on_message callback as the message parameter. + + Members: + + topic : String. topic that the message was published on. + payload : String/bytes the message payload. + qos : Integer. The message Quality of Service 0, 1 or 2. + retain : Boolean. If true, the message is a retained message and not fresh. + mid : Integer. The message id. + """ + def __init__(self): + self.timestamp = 0 + self.state = mqtt_ms_invalid + self.dup = False + self.mid = 0 + self.topic = "" + self.payload = None + self.qos = 0 + self.retain = False + + +class Client(object): + """MQTT version 3.1/3.1.1 client class. + + This is the main class for use communicating with an MQTT broker. + + General usage flow: + + * Use connect()/connect_async() to connect to a broker + * Call loop() frequently to maintain network traffic flow with the broker + * Or use loop_start() to set a thread running to call loop() for you. + * Or use loop_forever() to handle calling loop() for you in a blocking + * function. + * Use subscribe() to subscribe to a topic and receive messages + * Use publish() to send messages + * Use disconnect() to disconnect from the broker + + Data returned from the broker is made available with the use of callback + functions as described below. + + Callbacks + ========= + + A number of callback functions are available to receive data back from the + broker. To use a callback, define a function and then assign it to the + client: + + def on_connect(client, userdata, flags, rc): + print("Connection returned " + str(rc)) + + client.on_connect = on_connect + + All of the callbacks as described below have a "client" and an "userdata" + argument. "client" is the Client instance that is calling the callback. + "userdata" is user data of any type and can be set when creating a new client + instance or with user_data_set(userdata). + + The callbacks: + + on_connect(client, userdata, flags, rc): called when the broker responds to our connection + request. + flags is a dict that contains response flags from the broker: + flags['session present'] - this flag is useful for clients that are + using clean session set to 0 only. If a client with clean + session=0, that reconnects to a broker that it has previously + connected to, this flag indicates whether the broker still has the + session information for the client. If 1, the session still exists. + The value of rc determines success or not: + 0: Connection successful + 1: Connection refused - incorrect protocol version + 2: Connection refused - invalid client identifier + 3: Connection refused - server unavailable + 4: Connection refused - bad username or password + 5: Connection refused - not authorised + 6-255: Currently unused. + + on_disconnect(client, userdata, rc): called when the client disconnects from the broker. + The rc parameter indicates the disconnection state. If MQTT_ERR_SUCCESS + (0), the callback was called in response to a disconnect() call. If any + other value the disconnection was unexpected, such as might be caused by + a network error. + + on_message(client, userdata, message): called when a message has been received on a + topic that the client subscribes to. The message variable is a + MQTTMessage that describes all of the message parameters. + + on_publish(client, userdata, mid): called when a message that was to be sent using the + publish() call has completed transmission to the broker. For messages + with QoS levels 1 and 2, this means that the appropriate handshakes have + completed. For QoS 0, this simply means that the message has left the + client. The mid variable matches the mid variable returned from the + corresponding publish() call, to allow outgoing messages to be tracked. + This callback is important because even if the publish() call returns + success, it does not always mean that the message has been sent. + + on_subscribe(client, userdata, mid, granted_qos): called when the broker responds to a + subscribe request. The mid variable matches the mid variable returned + from the corresponding subscribe() call. The granted_qos variable is a + list of integers that give the QoS level the broker has granted for each + of the different subscription requests. + + on_unsubscribe(client, userdata, mid): called when the broker responds to an unsubscribe + request. The mid variable matches the mid variable returned from the + corresponding unsubscribe() call. + + on_log(client, userdata, level, buf): called when the client has log information. Define + to allow debugging. The level variable gives the severity of the message + and will be one of MQTT_LOG_INFO, MQTT_LOG_NOTICE, MQTT_LOG_WARNING, + MQTT_LOG_ERR, and MQTT_LOG_DEBUG. The message itself is in buf. + + """ + def __init__(self, client_id="", clean_session=True, userdata=None, protocol=MQTTv31, useSecuredWebsocket=False): + """client_id is the unique client id string used when connecting to the + broker. If client_id is zero length or None, then one will be randomly + generated. In this case, clean_session must be True. If this is not the + case a ValueError will be raised. + + clean_session is a boolean that determines the client type. If True, + the broker will remove all information about this client when it + disconnects. If False, the client is a persistent client and + subscription information and queued messages will be retained when the + client disconnects. + Note that a client will never discard its own outgoing messages on + disconnect. Calling connect() or reconnect() will cause the messages to + be resent. Use reinitialise() to reset a client to its original state. + + userdata is user defined data of any type that is passed as the "userdata" + parameter to callbacks. It may be updated at a later point with the + user_data_set() function. + + The protocol argument allows explicit setting of the MQTT version to + use for this client. Can be paho.mqtt.client.MQTTv311 (v3.1.1) or + paho.mqtt.client.MQTTv31 (v3.1), with the default being v3.1. If the + broker reports that the client connected with an invalid protocol + version, the client will automatically attempt to reconnect using v3.1 + instead. + + useSecuredWebsocket is a boolean that determines whether the client uses + MQTT over Websocket with sigV4 signing (True) or MQTT with plain TCP + socket. If True, the client will try to find AWS_ACCESS_KEY_ID and + AWS_SECRET_ACCESS_KEY in the system environment variables and start the + sigV4 signing and Websocket handshake. Under this configuration, all + outbound MQTT packets will be wrapped around with Websocket framework. All + inbound MQTT packets will be automatically wss-decoded. + """ + if not clean_session and (client_id == "" or client_id is None): + raise ValueError('A client id must be provided if clean session is False.') + + self._protocol = protocol + self._userdata = userdata + self._sock = None + self._sockpairR, self._sockpairW = _socketpair_compat() + self._keepalive = 60 + self._message_retry = 20 + self._last_retry_check = 0 + self._clean_session = clean_session + if client_id == "" or client_id is None: + self._client_id = "paho/" + "".join(random.choice("0123456789ADCDEF") for x in range(23-5)) + else: + self._client_id = client_id + + self._username = "" + self._password = "" + self._in_packet = { + "command": 0, + "have_remaining": 0, + "remaining_count": [], + "remaining_mult": 1, + "remaining_length": 0, + "packet": b"", + "to_process": 0, + "pos": 0} + self._out_packet = [] + self._current_out_packet = None + self._last_msg_in = time.time() + self._last_msg_out = time.time() + self._ping_t = 0 + self._last_mid = 0 + self._state = mqtt_cs_new + self._max_inflight_messages = 20 + self._out_messages = [] + self._in_messages = [] + self._inflight_messages = 0 + self._will = False + self._will_topic = "" + self._will_payload = None + self._will_qos = 0 + self._will_retain = False + self.on_disconnect = None + self.on_connect = None + self.on_publish = None + self.on_message = None + self.on_message_filtered = [] + self.on_subscribe = None + self.on_unsubscribe = None + self.on_log = None + self._host = "" + self._port = 1883 + self._bind_address = "" + self._socket_factory = None + self._in_callback = False + self._strict_protocol = False + self._callback_mutex = threading.Lock() + self._state_mutex = threading.Lock() + self._out_packet_mutex = threading.Lock() + self._current_out_packet_mutex = threading.Lock() + self._msgtime_mutex = threading.Lock() + self._out_message_mutex = threading.Lock() + self._in_message_mutex = threading.Lock() + self._thread = None + self._thread_terminate = False + self._ssl = None + self._tls_certfile = None + self._tls_keyfile = None + self._tls_ca_certs = None + self._tls_cert_reqs = None + self._tls_ciphers = None + self._tls_version = tls_version + self._tls_insecure = False + self._useSecuredWebsocket = useSecuredWebsocket # Do we enable secured websocket + self._backoffCore = ProgressiveBackOffCore() # Init the backoffCore using default configuration + self._AWSAccessKeyIDCustomConfig = "" + self._AWSSecretAccessKeyCustomConfig = "" + self._AWSSessionTokenCustomConfig = "" + self._alpn_protocols = None + + def __del__(self): + pass + + + def setBackoffTiming(self, srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSecond, srcMinimumConnectTimeSecond): + """ + Make custom settings for backoff timing for reconnect logic + srcBaseReconnectTimeSecond - The base reconnection time in seconds + srcMaximumReconnectTimeSecond - The maximum reconnection time in seconds + srcMinimumConnectTimeSecond - The minimum time in seconds that a connection must be maintained in order to be considered stable + * Raise ValueError if input params are malformed + """ + self._backoffCore.configTime(srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSecond, srcMinimumConnectTimeSecond) + + def configIAMCredentials(self, srcAWSAccessKeyID, srcAWSSecretAccessKey, srcAWSSessionToken): + """ + Make custom settings for IAM credentials for websocket connection + srcAWSAccessKeyID - AWS IAM access key + srcAWSSecretAccessKey - AWS IAM secret key + srcAWSSessionToken - AWS Session Token + """ + self._AWSAccessKeyIDCustomConfig = srcAWSAccessKeyID + self._AWSSecretAccessKeyCustomConfig = srcAWSSecretAccessKey + self._AWSSessionTokenCustomConfig = srcAWSSessionToken + + def config_alpn_protocols(self, alpn_protocols): + """ + Make custom settings for ALPN protocols + :param alpn_protocols: Array of strings that specifies the alpn protocols to be used + :return: None + """ + self._alpn_protocols = alpn_protocols + + def reinitialise(self, client_id="", clean_session=True, userdata=None): + if self._ssl: + self._ssl.close() + self._ssl = None + self._sock = None + elif self._sock: + self._sock.close() + self._sock = None + if self._sockpairR: + self._sockpairR.close() + self._sockpairR = None + if self._sockpairW: + self._sockpairW.close() + self._sockpairW = None + + self.__init__(client_id, clean_session, userdata) + + def tls_set(self, ca_certs, certfile=None, keyfile=None, cert_reqs=cert_reqs, tls_version=tls_version, ciphers=None): + """Configure network encryption and authentication options. Enables SSL/TLS support. + + ca_certs : a string path to the Certificate Authority certificate files + that are to be treated as trusted by this client. If this is the only + option given then the client will operate in a similar manner to a web + browser. That is to say it will require the broker to have a + certificate signed by the Certificate Authorities in ca_certs and will + communicate using TLS v1, but will not attempt any form of + authentication. This provides basic network encryption but may not be + sufficient depending on how the broker is configured. + + certfile and keyfile are strings pointing to the PEM encoded client + certificate and private keys respectively. If these arguments are not + None then they will be used as client information for TLS based + authentication. Support for this feature is broker dependent. Note + that if either of these files in encrypted and needs a password to + decrypt it, Python will ask for the password at the command line. It is + not currently possible to define a callback to provide the password. + + cert_reqs allows the certificate requirements that the client imposes + on the broker to be changed. By default this is ssl.CERT_REQUIRED, + which means that the broker must provide a certificate. See the ssl + pydoc for more information on this parameter. + + tls_version allows the version of the SSL/TLS protocol used to be + specified. By default TLS v1 is used. Previous versions (all versions + beginning with SSL) are possible but not recommended due to possible + security problems. + + ciphers is a string specifying which encryption ciphers are allowable + for this connection, or None to use the defaults. See the ssl pydoc for + more information. + + Must be called before connect() or connect_async().""" + if HAVE_SSL is False: + raise ValueError('This platform has no SSL/TLS.') + + if sys.version < '2.7': + raise ValueError('Python 2.7 is the minimum supported version for TLS.') + + if ca_certs is None: + raise ValueError('ca_certs must not be None.') + + try: + f = open(ca_certs, "r") + except IOError as err: + raise IOError(ca_certs+": "+err.strerror) + else: + f.close() + if certfile is not None: + try: + f = open(certfile, "r") + except IOError as err: + raise IOError(certfile+": "+err.strerror) + else: + f.close() + if keyfile is not None: + try: + f = open(keyfile, "r") + except IOError as err: + raise IOError(keyfile+": "+err.strerror) + else: + f.close() + + self._tls_ca_certs = ca_certs + self._tls_certfile = certfile + self._tls_keyfile = keyfile + self._tls_cert_reqs = cert_reqs + self._tls_version = tls_version + self._tls_ciphers = ciphers + + def tls_insecure_set(self, value): + """Configure verification of the server hostname in the server certificate. + + If value is set to true, it is impossible to guarantee that the host + you are connecting to is not impersonating your server. This can be + useful in initial server testing, but makes it possible for a malicious + third party to impersonate your server through DNS spoofing, for + example. + + Do not use this function in a real system. Setting value to true means + there is no point using encryption. + + Must be called before connect().""" + if HAVE_SSL is False: + raise ValueError('This platform has no SSL/TLS.') + + self._tls_insecure = value + + def connect(self, host, port=1883, keepalive=60, bind_address=""): + """Connect to a remote broker. + + host is the hostname or IP address of the remote broker. + port is the network port of the server host to connect to. Defaults to + 1883. Note that the default port for MQTT over SSL/TLS is 8883 so if you + are using tls_set() the port may need providing. + keepalive: Maximum period in seconds between communications with the + broker. If no other messages are being exchanged, this controls the + rate at which the client will send ping messages to the broker. + """ + self.connect_async(host, port, keepalive, bind_address) + return self.reconnect() + + def connect_srv(self, domain=None, keepalive=60, bind_address=""): + """Connect to a remote broker. + + domain is the DNS domain to search for SRV records; if None, + try to determine local domain name. + keepalive and bind_address are as for connect() + """ + + if HAVE_DNS is False: + raise ValueError('No DNS resolver library found.') + + if domain is None: + domain = socket.getfqdn() + domain = domain[domain.find('.') + 1:] + + try: + rr = '_mqtt._tcp.%s' % domain + if self._ssl is not None: + # IANA specifies secure-mqtt (not mqtts) for port 8883 + rr = '_secure-mqtt._tcp.%s' % domain + answers = [] + for answer in dns.resolver.query(rr, dns.rdatatype.SRV): + addr = answer.target.to_text()[:-1] + answers.append((addr, answer.port, answer.priority, answer.weight)) + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.resolver.NoNameservers): + raise ValueError("No answer/NXDOMAIN for SRV in %s" % (domain)) + + # FIXME: doesn't account for weight + for answer in answers: + host, port, prio, weight = answer + + try: + return self.connect(host, port, keepalive, bind_address) + except: + pass + + raise ValueError("No SRV hosts responded") + + def connect_async(self, host, port=1883, keepalive=60, bind_address=""): + """Connect to a remote broker asynchronously. This is a non-blocking + connect call that can be used with loop_start() to provide very quick + start. + + host is the hostname or IP address of the remote broker. + port is the network port of the server host to connect to. Defaults to + 1883. Note that the default port for MQTT over SSL/TLS is 8883 so if you + are using tls_set() the port may need providing. + keepalive: Maximum period in seconds between communications with the + broker. If no other messages are being exchanged, this controls the + rate at which the client will send ping messages to the broker. + """ + if host is None or len(host) == 0: + raise ValueError('Invalid host.') + if port <= 0: + raise ValueError('Invalid port number.') + if keepalive < 0: + raise ValueError('Keepalive must be >=0.') + if bind_address != "" and bind_address is not None: + if (sys.version_info[0] == 2 and sys.version_info[1] < 7) or (sys.version_info[0] == 3 and sys.version_info[1] < 2): + raise ValueError('bind_address requires Python 2.7 or 3.2.') + + self._host = host + self._port = port + self._keepalive = keepalive + self._bind_address = bind_address + + self._state_mutex.acquire() + self._state = mqtt_cs_connect_async + self._state_mutex.release() + + def reconnect(self): + """Reconnect the client after a disconnect. Can only be called after + connect()/connect_async().""" + if len(self._host) == 0: + raise ValueError('Invalid host.') + if self._port <= 0: + raise ValueError('Invalid port number.') + + self._in_packet = { + "command": 0, + "have_remaining": 0, + "remaining_count": [], + "remaining_mult": 1, + "remaining_length": 0, + "packet": b"", + "to_process": 0, + "pos": 0} + + self._out_packet_mutex.acquire() + self._out_packet = [] + self._out_packet_mutex.release() + + self._current_out_packet_mutex.acquire() + self._current_out_packet = None + self._current_out_packet_mutex.release() + + self._msgtime_mutex.acquire() + self._last_msg_in = time.time() + self._last_msg_out = time.time() + self._msgtime_mutex.release() + + self._ping_t = 0 + self._state_mutex.acquire() + self._state = mqtt_cs_new + self._state_mutex.release() + if self._ssl: + self._ssl.close() + self._ssl = None + self._sock = None + elif self._sock: + self._sock.close() + self._sock = None + + # Put messages in progress in a valid state. + self._messages_reconnect_reset() + + try: + if self._socket_factory: + sock = self._socket_factory() + elif (sys.version_info[0] == 2 and sys.version_info[1] < 7) or (sys.version_info[0] == 3 and sys.version_info[1] < 2): + sock = socket.create_connection((self._host, self._port)) + else: + sock = socket.create_connection((self._host, self._port), source_address=(self._bind_address, 0)) + except socket.error as err: + if err.errno != errno.EINPROGRESS and err.errno != errno.EWOULDBLOCK and err.errno != EAGAIN: + raise + + verify_hostname = self._tls_insecure is False # Decide whether we need to verify hostname + + if self._tls_ca_certs is not None: + if self._useSecuredWebsocket: + # Never assign to ._ssl before wss handshake is finished + # Non-None value for ._ssl will allow ops before wss-MQTT connection is established + rawSSL = ssl.wrap_socket(sock, ca_certs=self._tls_ca_certs, cert_reqs=ssl.CERT_REQUIRED) # Add server certificate verification + rawSSL.setblocking(0) # Non-blocking socket + self._ssl = SecuredWebSocketCore(rawSSL, self._host, self._port, self._AWSAccessKeyIDCustomConfig, self._AWSSecretAccessKeyCustomConfig, self._AWSSessionTokenCustomConfig) # Override the _ssl socket + # self._ssl.enableDebug() + elif self._alpn_protocols is not None: + # SSLContext is required to enable ALPN support + # Assuming Python 2.7.10+/3.5+ till the end of this elif branch + ssl_context = SSLContextBuilder()\ + .with_ca_certs(self._tls_ca_certs)\ + .with_cert_key_pair(self._tls_certfile, self._tls_keyfile)\ + .with_cert_reqs(self._tls_cert_reqs)\ + .with_check_hostname(True)\ + .with_ciphers(self._tls_ciphers)\ + .with_alpn_protocols(self._alpn_protocols)\ + .build() + self._ssl = ssl_context.wrap_socket(sock, server_hostname=self._host, do_handshake_on_connect=False) + verify_hostname = False # Since check_hostname in SSLContext is already set to True, no need to verify it again + self._ssl.do_handshake() + else: + self._ssl = ssl.wrap_socket( + sock, + certfile=self._tls_certfile, + keyfile=self._tls_keyfile, + ca_certs=self._tls_ca_certs, + cert_reqs=self._tls_cert_reqs, + ssl_version=self._tls_version, + ciphers=self._tls_ciphers) + + if verify_hostname: + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 5): # No IP host match before 3.5.x + self._tls_match_hostname() + else: + ssl.match_hostname(self._ssl.getpeercert(), self._host) + + self._sock = sock + + if self._ssl and not self._useSecuredWebsocket: + self._ssl.setblocking(0) # For X.509 cert mutual auth. + elif not self._ssl: + self._sock.setblocking(0) # For plain socket + else: + pass # For MQTT over WebSocket + + return self._send_connect(self._keepalive, self._clean_session) + + def loop(self, timeout=1.0, max_packets=1): + """Process network events. + + This function must be called regularly to ensure communication with the + broker is carried out. It calls select() on the network socket to wait + for network events. If incoming data is present it will then be + processed. Outgoing commands, from e.g. publish(), are normally sent + immediately that their function is called, but this is not always + possible. loop() will also attempt to send any remaining outgoing + messages, which also includes commands that are part of the flow for + messages with QoS>0. + + timeout: The time in seconds to wait for incoming/outgoing network + traffic before timing out and returning. + max_packets: Not currently used. + + Returns MQTT_ERR_SUCCESS on success. + Returns >0 on error. + + A ValueError will be raised if timeout < 0""" + if timeout < 0.0: + raise ValueError('Invalid timeout.') + + self._current_out_packet_mutex.acquire() + self._out_packet_mutex.acquire() + if self._current_out_packet is None and len(self._out_packet) > 0: + self._current_out_packet = self._out_packet.pop(0) + + if self._current_out_packet: + wlist = [self.socket()] + else: + wlist = [] + self._out_packet_mutex.release() + self._current_out_packet_mutex.release() + + # sockpairR is used to break out of select() before the timeout, on a + # call to publish() etc. + rlist = [self.socket(), self._sockpairR] + try: + socklist = select.select(rlist, wlist, [], timeout) + except TypeError as e: + # Socket isn't correct type, in likelihood connection is lost + return MQTT_ERR_CONN_LOST + except ValueError: + # Can occur if we just reconnected but rlist/wlist contain a -1 for + # some reason. + return MQTT_ERR_CONN_LOST + except: + return MQTT_ERR_UNKNOWN + + if self.socket() in socklist[0]: + rc = self.loop_read(max_packets) + if rc or (self._ssl is None and self._sock is None): + return rc + + if self._sockpairR in socklist[0]: + # Stimulate output write even though we didn't ask for it, because + # at that point the publish or other command wasn't present. + socklist[1].insert(0, self.socket()) + # Clear sockpairR - only ever a single byte written. + try: + self._sockpairR.recv(1) + except socket.error as err: + if err.errno != EAGAIN: + raise + + if self.socket() in socklist[1]: + rc = self.loop_write(max_packets) + if rc or (self._ssl is None and self._sock is None): + return rc + + return self.loop_misc() + + def publish(self, topic, payload=None, qos=0, retain=False): + """Publish a message on a topic. + + This causes a message to be sent to the broker and subsequently from + the broker to any clients subscribing to matching topics. + + topic: The topic that the message should be published on. + payload: The actual message to send. If not given, or set to None a + zero length message will be used. Passing an int or float will result + in the payload being converted to a string representing that number. If + you wish to send a true int/float, use struct.pack() to create the + payload you require. + qos: The quality of service level to use. + retain: If set to true, the message will be set as the "last known + good"/retained message for the topic. + + Returns a tuple (result, mid), where result is MQTT_ERR_SUCCESS to + indicate success or MQTT_ERR_NO_CONN if the client is not currently + connected. mid is the message ID for the publish request. The mid + value can be used to track the publish request by checking against the + mid argument in the on_publish() callback if it is defined. + + A ValueError will be raised if topic is None, has zero length or is + invalid (contains a wildcard), if qos is not one of 0, 1 or 2, or if + the length of the payload is greater than 268435455 bytes.""" + if topic is None or len(topic) == 0: + raise ValueError('Invalid topic.') + if qos<0 or qos>2: + raise ValueError('Invalid QoS level.') + if isinstance(payload, str) or isinstance(payload, bytearray): + local_payload = payload + elif sys.version_info[0] < 3 and isinstance(payload, unicode): + local_payload = payload + elif isinstance(payload, int) or isinstance(payload, float): + local_payload = str(payload) + elif payload is None: + local_payload = None + else: + raise TypeError('payload must be a string, bytearray, int, float or None.') + + if local_payload is not None and len(local_payload) > 268435455: + raise ValueError('Payload too large.') + + if self._topic_wildcard_len_check(topic) != MQTT_ERR_SUCCESS: + raise ValueError('Publish topic cannot contain wildcards.') + + local_mid = self._mid_generate() + + if qos == 0: + rc = self._send_publish(local_mid, topic, local_payload, qos, retain, False) + return (rc, local_mid) + else: + message = MQTTMessage() + message.timestamp = time.time() + + message.mid = local_mid + message.topic = topic + if local_payload is None or len(local_payload) == 0: + message.payload = None + else: + message.payload = local_payload + + message.qos = qos + message.retain = retain + message.dup = False + + self._out_message_mutex.acquire() + self._out_messages.append(message) + if self._max_inflight_messages == 0 or self._inflight_messages < self._max_inflight_messages: + self._inflight_messages = self._inflight_messages+1 + if qos == 1: + message.state = mqtt_ms_wait_for_puback + elif qos == 2: + message.state = mqtt_ms_wait_for_pubrec + self._out_message_mutex.release() + + rc = self._send_publish(message.mid, message.topic, message.payload, message.qos, message.retain, message.dup) + + # remove from inflight messages so it will be send after a connection is made + if rc is MQTT_ERR_NO_CONN: + with self._out_message_mutex: + self._inflight_messages -= 1 + message.state = mqtt_ms_publish + + return (rc, local_mid) + else: + message.state = mqtt_ms_queued; + self._out_message_mutex.release() + return (MQTT_ERR_SUCCESS, local_mid) + + def username_pw_set(self, username, password=None): + """Set a username and optionally a password for broker authentication. + + Must be called before connect() to have any effect. + Requires a broker that supports MQTT v3.1. + + username: The username to authenticate with. Need have no relationship to the client id. + password: The password to authenticate with. Optional, set to None if not required. + """ + self._username = username.encode('utf-8') + self._password = password + + def socket_factory_set(self, socket_factory): + """Set a socket factory to custom configure a different socket type for + mqtt connection. + Must be called before connect() to have any effect. + socket_factory: create_connection function which creates a socket to user's specification + """ + self._socket_factory = socket_factory + + def disconnect(self): + """Disconnect a connected client from the broker.""" + self._state_mutex.acquire() + self._state = mqtt_cs_disconnecting + self._state_mutex.release() + + self._backoffCore.stopStableConnectionTimer() + + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + return self._send_disconnect() + + def subscribe(self, topic, qos=0): + """Subscribe the client to one or more topics. + + This function may be called in three different ways: + + Simple string and integer + ------------------------- + e.g. subscribe("my/topic", 2) + + topic: A string specifying the subscription topic to subscribe to. + qos: The desired quality of service level for the subscription. + Defaults to 0. + + String and integer tuple + ------------------------ + e.g. subscribe(("my/topic", 1)) + + topic: A tuple of (topic, qos). Both topic and qos must be present in + the tuple. + qos: Not used. + + List of string and integer tuples + ------------------------ + e.g. subscribe([("my/topic", 0), ("another/topic", 2)]) + + This allows multiple topic subscriptions in a single SUBSCRIPTION + command, which is more efficient than using multiple calls to + subscribe(). + + topic: A list of tuple of format (topic, qos). Both topic and qos must + be present in all of the tuples. + qos: Not used. + + The function returns a tuple (result, mid), where result is + MQTT_ERR_SUCCESS to indicate success or (MQTT_ERR_NO_CONN, None) if the + client is not currently connected. mid is the message ID for the + subscribe request. The mid value can be used to track the subscribe + request by checking against the mid argument in the on_subscribe() + callback if it is defined. + + Raises a ValueError if qos is not 0, 1 or 2, or if topic is None or has + zero string length, or if topic is not a string, tuple or list. + """ + topic_qos_list = None + if isinstance(topic, str): + if qos<0 or qos>2: + raise ValueError('Invalid QoS level.') + if topic is None or len(topic) == 0: + raise ValueError('Invalid topic.') + topic_qos_list = [(topic.encode('utf-8'), qos)] + elif isinstance(topic, tuple): + if topic[1]<0 or topic[1]>2: + raise ValueError('Invalid QoS level.') + if topic[0] is None or len(topic[0]) == 0 or not isinstance(topic[0], str): + raise ValueError('Invalid topic.') + topic_qos_list = [(topic[0].encode('utf-8'), topic[1])] + elif isinstance(topic, list): + topic_qos_list = [] + for t in topic: + if t[1]<0 or t[1]>2: + raise ValueError('Invalid QoS level.') + if t[0] is None or len(t[0]) == 0 or not isinstance(t[0], str): + raise ValueError('Invalid topic.') + topic_qos_list.append((t[0].encode('utf-8'), t[1])) + + if topic_qos_list is None: + raise ValueError("No topic specified, or incorrect topic type.") + + if self._sock is None and self._ssl is None: + return (MQTT_ERR_NO_CONN, None) + + return self._send_subscribe(False, topic_qos_list) + + def unsubscribe(self, topic): + """Unsubscribe the client from one or more topics. + + topic: A single string, or list of strings that are the subscription + topics to unsubscribe from. + + Returns a tuple (result, mid), where result is MQTT_ERR_SUCCESS + to indicate success or (MQTT_ERR_NO_CONN, None) if the client is not + currently connected. + mid is the message ID for the unsubscribe request. The mid value can be + used to track the unsubscribe request by checking against the mid + argument in the on_unsubscribe() callback if it is defined. + + Raises a ValueError if topic is None or has zero string length, or is + not a string or list. + """ + topic_list = None + if topic is None: + raise ValueError('Invalid topic.') + if isinstance(topic, str): + if len(topic) == 0: + raise ValueError('Invalid topic.') + topic_list = [topic.encode('utf-8')] + elif isinstance(topic, list): + topic_list = [] + for t in topic: + if len(t) == 0 or not isinstance(t, str): + raise ValueError('Invalid topic.') + topic_list.append(t.encode('utf-8')) + + if topic_list is None: + raise ValueError("No topic specified, or incorrect topic type.") + + if self._sock is None and self._ssl is None: + return (MQTT_ERR_NO_CONN, None) + + return self._send_unsubscribe(False, topic_list) + + def loop_read(self, max_packets=1): + """Process read network events. Use in place of calling loop() if you + wish to handle your client reads as part of your own application. + + Use socket() to obtain the client socket to call select() or equivalent + on. + + Do not use if you are using the threaded interface loop_start().""" + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + max_packets = len(self._out_messages) + len(self._in_messages) + if max_packets < 1: + max_packets = 1 + + for i in range(0, max_packets): + rc = self._packet_read() + if rc > 0: + return self._loop_rc_handle(rc) + elif rc == MQTT_ERR_AGAIN: + return MQTT_ERR_SUCCESS + return MQTT_ERR_SUCCESS + + def loop_write(self, max_packets=1): + """Process read network events. Use in place of calling loop() if you + wish to handle your client reads as part of your own application. + + Use socket() to obtain the client socket to call select() or equivalent + on. + + Use want_write() to determine if there is data waiting to be written. + + Do not use if you are using the threaded interface loop_start().""" + + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + max_packets = len(self._out_packet) + 1 + if max_packets < 1: + max_packets = 1 + + for i in range(0, max_packets): + rc = self._packet_write() + if rc > 0: + return self._loop_rc_handle(rc) + elif rc == MQTT_ERR_AGAIN: + return MQTT_ERR_SUCCESS + return MQTT_ERR_SUCCESS + + def want_write(self): + """Call to determine if there is network data waiting to be written. + Useful if you are calling select() yourself rather than using loop(). + """ + if self._current_out_packet or len(self._out_packet) > 0: + return True + else: + return False + + def loop_misc(self): + """Process miscellaneous network events. Use in place of calling loop() if you + wish to call select() or equivalent on. + + Do not use if you are using the threaded interface loop_start().""" + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + now = time.time() + self._check_keepalive() + if self._last_retry_check+1 < now: + # Only check once a second at most + self._message_retry_check() + self._last_retry_check = now + + if self._ping_t > 0 and now - self._ping_t >= self._keepalive: + # client->ping_t != 0 means we are waiting for a pingresp. + # This hasn't happened in the keepalive time so we should disconnect. + if self._ssl: + self._ssl.close() + self._ssl = None + elif self._sock: + self._sock.close() + self._sock = None + + self._callback_mutex.acquire() + if self._state == mqtt_cs_disconnecting: + rc = MQTT_ERR_SUCCESS + else: + rc = 1 + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, rc) + self._in_callback = False + self._callback_mutex.release() + return MQTT_ERR_CONN_LOST + + return MQTT_ERR_SUCCESS + + def max_inflight_messages_set(self, inflight): + """Set the maximum number of messages with QoS>0 that can be part way + through their network flow at once. Defaults to 20.""" + if inflight < 0: + raise ValueError('Invalid inflight.') + self._max_inflight_messages = inflight + + def message_retry_set(self, retry): + """Set the timeout in seconds before a message with QoS>0 is retried. + 20 seconds by default.""" + if retry < 0: + raise ValueError('Invalid retry.') + + self._message_retry = retry + + def user_data_set(self, userdata): + """Set the user data variable passed to callbacks. May be any data type.""" + self._userdata = userdata + + def will_set(self, topic, payload=None, qos=0, retain=False): + """Set a Will to be sent by the broker in case the client disconnects unexpectedly. + + This must be called before connect() to have any effect. + + topic: The topic that the will message should be published on. + payload: The message to send as a will. If not given, or set to None a + zero length message will be used as the will. Passing an int or float + will result in the payload being converted to a string representing + that number. If you wish to send a true int/float, use struct.pack() to + create the payload you require. + qos: The quality of service level to use for the will. + retain: If set to true, the will message will be set as the "last known + good"/retained message for the topic. + + Raises a ValueError if qos is not 0, 1 or 2, or if topic is None or has + zero string length. + """ + if topic is None or len(topic) == 0: + raise ValueError('Invalid topic.') + if qos<0 or qos>2: + raise ValueError('Invalid QoS level.') + if isinstance(payload, str): + self._will_payload = payload.encode('utf-8') + elif isinstance(payload, bytearray): + self._will_payload = payload + elif isinstance(payload, int) or isinstance(payload, float): + self._will_payload = str(payload) + elif payload is None: + self._will_payload = None + else: + raise TypeError('payload must be a string, bytearray, int, float or None.') + + self._will = True + self._will_topic = topic.encode('utf-8') + self._will_qos = qos + self._will_retain = retain + + def will_clear(self): + """ Removes a will that was previously configured with will_set(). + + Must be called before connect() to have any effect.""" + self._will = False + self._will_topic = "" + self._will_payload = None + self._will_qos = 0 + self._will_retain = False + + def socket(self): + """Return the socket or ssl object for this client.""" + if self._ssl: + if self._useSecuredWebsocket: + return self._ssl.getSSLSocket() + else: + return self._ssl + else: + return self._sock + + def loop_forever(self, timeout=1.0, max_packets=1, retry_first_connection=False): + """This function call loop() for you in an infinite blocking loop. It + is useful for the case where you only want to run the MQTT client loop + in your program. + + loop_forever() will handle reconnecting for you. If you call + disconnect() in a callback it will return. + + + timeout: The time in seconds to wait for incoming/outgoing network + traffic before timing out and returning. + max_packets: Not currently used. + retry_first_connection: Should the first connection attempt be retried on failure. + + Raises socket.error on first connection failures unless retry_first_connection=True + """ + + run = True + + while run: + if self._state == mqtt_cs_connect_async: + try: + self.reconnect() + except socket.error: + if not retry_first_connection: + raise + self._easy_log(MQTT_LOG_DEBUG, "Connection failed, retrying") + self._backoffCore.backOff() + # time.sleep(1) + else: + break + + while run: + rc = MQTT_ERR_SUCCESS + while rc == MQTT_ERR_SUCCESS: + rc = self.loop(timeout, max_packets) + # We don't need to worry about locking here, because we've + # either called loop_forever() when in single threaded mode, or + # in multi threaded mode when loop_stop() has been called and + # so no other threads can access _current_out_packet, + # _out_packet or _messages. + if (self._thread_terminate is True + and self._current_out_packet is None + and len(self._out_packet) == 0 + and len(self._out_messages) == 0): + + rc = 1 + run = False + + self._state_mutex.acquire() + if self._state == mqtt_cs_disconnecting or run is False or self._thread_terminate is True: + run = False + self._state_mutex.release() + else: + self._state_mutex.release() + self._backoffCore.backOff() + # time.sleep(1) + + self._state_mutex.acquire() + if self._state == mqtt_cs_disconnecting or run is False or self._thread_terminate is True: + run = False + self._state_mutex.release() + else: + self._state_mutex.release() + try: + self.reconnect() + except socket.error as err: + pass + + return rc + + def loop_start(self): + """This is part of the threaded client interface. Call this once to + start a new thread to process network traffic. This provides an + alternative to repeatedly calling loop() yourself. + """ + if self._thread is not None: + return MQTT_ERR_INVAL + + self._thread_terminate = False + self._thread = threading.Thread(target=self._thread_main) + self._thread.daemon = True + self._thread.start() + + def loop_stop(self, force=False): + """This is part of the threaded client interface. Call this once to + stop the network thread previously created with loop_start(). This call + will block until the network thread finishes. + + The force parameter is currently ignored. + """ + if self._thread is None: + return MQTT_ERR_INVAL + + self._thread_terminate = True + self._thread.join() + self._thread = None + + def message_callback_add(self, sub, callback): + """Register a message callback for a specific topic. + Messages that match 'sub' will be passed to 'callback'. Any + non-matching messages will be passed to the default on_message + callback. + + Call multiple times with different 'sub' to define multiple topic + specific callbacks. + + Topic specific callbacks may be removed with + message_callback_remove().""" + if callback is None or sub is None: + raise ValueError("sub and callback must both be defined.") + + self._callback_mutex.acquire() + for i in range(0, len(self.on_message_filtered)): + if self.on_message_filtered[i][0] == sub: + self.on_message_filtered[i] = (sub, callback) + self._callback_mutex.release() + return + + self.on_message_filtered.append((sub, callback)) + self._callback_mutex.release() + + def message_callback_remove(self, sub): + """Remove a message callback previously registered with + message_callback_add().""" + if sub is None: + raise ValueError("sub must defined.") + + self._callback_mutex.acquire() + for i in range(0, len(self.on_message_filtered)): + if self.on_message_filtered[i][0] == sub: + self.on_message_filtered.pop(i) + self._callback_mutex.release() + return + self._callback_mutex.release() + + # ============================================================ + # Private functions + # ============================================================ + + def _loop_rc_handle(self, rc): + if rc: + if self._ssl: + self._ssl.close() + self._ssl = None + elif self._sock: + self._sock.close() + self._sock = None + + self._state_mutex.acquire() + if self._state == mqtt_cs_disconnecting: + rc = MQTT_ERR_SUCCESS + self._state_mutex.release() + self._callback_mutex.acquire() + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, rc) + self._in_callback = False + + self._callback_mutex.release() + return rc + + def _packet_read(self): + # This gets called if pselect() indicates that there is network data + # available - ie. at least one byte. What we do depends on what data we + # already have. + # If we've not got a command, attempt to read one and save it. This should + # always work because it's only a single byte. + # Then try to read the remaining length. This may fail because it is may + # be more than one byte - will need to save data pending next read if it + # does fail. + # Then try to read the remaining payload, where 'payload' here means the + # combined variable header and actual payload. This is the most likely to + # fail due to longer length, so save current data and current position. + # After all data is read, send to _mqtt_handle_packet() to deal with. + # Finally, free the memory and reset everything to starting conditions. + if self._in_packet['command'] == 0: + try: + if self._ssl: + command = self._ssl.read(1) + else: + command = self._sock.recv(1) + except socket.error as err: + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + else: + if len(command) == 0: + return 1 + command = struct.unpack("!B", command) + self._in_packet['command'] = command[0] + + if self._in_packet['have_remaining'] == 0: + # Read remaining + # Algorithm for decoding taken from pseudo code at + # http://publib.boulder.ibm.com/infocenter/wmbhelp/v6r0m0/topic/com.ibm.etools.mft.doc/ac10870_.htm + while True: + try: + if self._ssl: + byte = self._ssl.read(1) + else: + byte = self._sock.recv(1) + except socket.error as err: + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + else: + byte = struct.unpack("!B", byte) + byte = byte[0] + self._in_packet['remaining_count'].append(byte) + # Max 4 bytes length for remaining length as defined by protocol. + # Anything more likely means a broken/malicious client. + if len(self._in_packet['remaining_count']) > 4: + return MQTT_ERR_PROTOCOL + + self._in_packet['remaining_length'] = self._in_packet['remaining_length'] + (byte & 127)*self._in_packet['remaining_mult'] + self._in_packet['remaining_mult'] = self._in_packet['remaining_mult'] * 128 + + if (byte & 128) == 0: + break + + self._in_packet['have_remaining'] = 1 + self._in_packet['to_process'] = self._in_packet['remaining_length'] + + while self._in_packet['to_process'] > 0: + try: + if self._ssl: + data = self._ssl.read(self._in_packet['to_process']) + else: + data = self._sock.recv(self._in_packet['to_process']) + except socket.error as err: + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + else: + self._in_packet['to_process'] = self._in_packet['to_process'] - len(data) + self._in_packet['packet'] = self._in_packet['packet'] + data + + # All data for this packet is read. + self._in_packet['pos'] = 0 + rc = self._packet_handle() + + # Free data and reset values + self._in_packet = dict( + command=0, + have_remaining=0, + remaining_count=[], + remaining_mult=1, + remaining_length=0, + packet=b"", + to_process=0, + pos=0) + + self._msgtime_mutex.acquire() + self._last_msg_in = time.time() + self._msgtime_mutex.release() + return rc + + def _packet_write(self): + self._current_out_packet_mutex.acquire() + while self._current_out_packet: + packet = self._current_out_packet + + try: + if self._ssl: + write_length = self._ssl.write(packet['packet'][packet['pos']:]) + else: + write_length = self._sock.send(packet['packet'][packet['pos']:]) + except AttributeError: + self._current_out_packet_mutex.release() + return MQTT_ERR_SUCCESS + except socket.error as err: + self._current_out_packet_mutex.release() + if self._ssl and (err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE): + return MQTT_ERR_AGAIN + if err.errno == EAGAIN: + return MQTT_ERR_AGAIN + print(err) + return 1 + + if write_length > 0: + packet['to_process'] = packet['to_process'] - write_length + packet['pos'] = packet['pos'] + write_length + + if packet['to_process'] == 0: + if (packet['command'] & 0xF0) == PUBLISH and packet['qos'] == 0: + self._callback_mutex.acquire() + if self.on_publish: + self._in_callback = True + self.on_publish(self, self._userdata, packet['mid']) + self._in_callback = False + + self._callback_mutex.release() + + if (packet['command'] & 0xF0) == DISCONNECT: + self._current_out_packet_mutex.release() + + self._msgtime_mutex.acquire() + self._last_msg_out = time.time() + self._msgtime_mutex.release() + + self._callback_mutex.acquire() + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, 0) + self._in_callback = False + self._callback_mutex.release() + + if self._ssl: + self._ssl.close() + self._ssl = None + if self._sock: + self._sock.close() + self._sock = None + return MQTT_ERR_SUCCESS + + self._out_packet_mutex.acquire() + if len(self._out_packet) > 0: + self._current_out_packet = self._out_packet.pop(0) + else: + self._current_out_packet = None + self._out_packet_mutex.release() + else: + pass # FIXME + + self._current_out_packet_mutex.release() + + self._msgtime_mutex.acquire() + self._last_msg_out = time.time() + self._msgtime_mutex.release() + return MQTT_ERR_SUCCESS + + def _easy_log(self, level, buf): + if self.on_log: + self.on_log(self, self._userdata, level, buf) + + def _check_keepalive(self): + now = time.time() + self._msgtime_mutex.acquire() + last_msg_out = self._last_msg_out + last_msg_in = self._last_msg_in + self._msgtime_mutex.release() + if (self._sock is not None or self._ssl is not None) and (now - last_msg_out >= self._keepalive or now - last_msg_in >= self._keepalive): + if self._state == mqtt_cs_connected and self._ping_t == 0: + self._send_pingreq() + self._msgtime_mutex.acquire() + self._last_msg_out = now + self._last_msg_in = now + self._msgtime_mutex.release() + else: + if self._ssl: + self._ssl.close() + self._ssl = None + elif self._sock: + self._sock.close() + self._sock = None + + if self._state == mqtt_cs_disconnecting: + rc = MQTT_ERR_SUCCESS + else: + rc = 1 + self._callback_mutex.acquire() + if self.on_disconnect: + self._in_callback = True + self.on_disconnect(self, self._userdata, rc) + self._in_callback = False + self._callback_mutex.release() + + def _mid_generate(self): + self._last_mid = self._last_mid + 1 + if self._last_mid == 65536: + self._last_mid = 1 + return self._last_mid + + def _topic_wildcard_len_check(self, topic): + # Search for + or # in a topic. Return MQTT_ERR_INVAL if found. + # Also returns MQTT_ERR_INVAL if the topic string is too long. + # Returns MQTT_ERR_SUCCESS if everything is fine. + if '+' in topic or '#' in topic or len(topic) == 0 or len(topic) > 65535: + return MQTT_ERR_INVAL + else: + return MQTT_ERR_SUCCESS + + def _send_pingreq(self): + self._easy_log(MQTT_LOG_DEBUG, "Sending PINGREQ") + rc = self._send_simple_command(PINGREQ) + if rc == MQTT_ERR_SUCCESS: + self._ping_t = time.time() + return rc + + def _send_pingresp(self): + self._easy_log(MQTT_LOG_DEBUG, "Sending PINGRESP") + return self._send_simple_command(PINGRESP) + + def _send_puback(self, mid): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBACK (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBACK, mid, False) + + def _send_pubcomp(self, mid): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBCOMP (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBCOMP, mid, False) + + def _pack_remaining_length(self, packet, remaining_length): + remaining_bytes = [] + while True: + byte = remaining_length % 128 + remaining_length = remaining_length // 128 + # If there are more digits to encode, set the top bit of this digit + if remaining_length > 0: + byte = byte | 0x80 + + remaining_bytes.append(byte) + packet.extend(struct.pack("!B", byte)) + if remaining_length == 0: + # FIXME - this doesn't deal with incorrectly large payloads + return packet + + def _pack_str16(self, packet, data): + if sys.version_info[0] < 3: + if isinstance(data, bytearray): + packet.extend(struct.pack("!H", len(data))) + packet.extend(data) + elif isinstance(data, str): + udata = data.encode('utf-8') + pack_format = "!H" + str(len(udata)) + "s" + packet.extend(struct.pack(pack_format, len(udata), udata)) + elif isinstance(data, unicode): + udata = data.encode('utf-8') + pack_format = "!H" + str(len(udata)) + "s" + packet.extend(struct.pack(pack_format, len(udata), udata)) + else: + raise TypeError + else: + if isinstance(data, bytearray) or isinstance(data, bytes): + packet.extend(struct.pack("!H", len(data))) + packet.extend(data) + elif isinstance(data, str): + udata = data.encode('utf-8') + pack_format = "!H" + str(len(udata)) + "s" + packet.extend(struct.pack(pack_format, len(udata), udata)) + else: + raise TypeError + + def _send_publish(self, mid, topic, payload=None, qos=0, retain=False, dup=False): + if self._sock is None and self._ssl is None: + return MQTT_ERR_NO_CONN + + utopic = topic.encode('utf-8') + command = PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain + packet = bytearray() + packet.extend(struct.pack("!B", command)) + if payload is None: + remaining_length = 2+len(utopic) + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBLISH (d"+str(dup)+", q"+str(qos)+", r"+str(int(retain))+", m"+str(mid)+", '"+topic+"' (NULL payload)") + else: + if isinstance(payload, str): + upayload = payload.encode('utf-8') + payloadlen = len(upayload) + elif isinstance(payload, bytearray): + payloadlen = len(payload) + elif isinstance(payload, unicode): + upayload = payload.encode('utf-8') + payloadlen = len(upayload) + + remaining_length = 2+len(utopic) + payloadlen + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBLISH (d"+str(dup)+", q"+str(qos)+", r"+str(int(retain))+", m"+str(mid)+", '"+topic+"', ... ("+str(payloadlen)+" bytes)") + + if qos > 0: + # For message id + remaining_length = remaining_length + 2 + + self._pack_remaining_length(packet, remaining_length) + self._pack_str16(packet, topic) + + if qos > 0: + # For message id + packet.extend(struct.pack("!H", mid)) + + if payload is not None: + if isinstance(payload, str): + pack_format = str(payloadlen) + "s" + packet.extend(struct.pack(pack_format, upayload)) + elif isinstance(payload, bytearray): + packet.extend(payload) + elif isinstance(payload, unicode): + pack_format = str(payloadlen) + "s" + packet.extend(struct.pack(pack_format, upayload)) + else: + raise TypeError('payload must be a string, unicode or a bytearray.') + + return self._packet_queue(PUBLISH, packet, mid, qos) + + def _send_pubrec(self, mid): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBREC (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBREC, mid, False) + + def _send_pubrel(self, mid, dup=False): + self._easy_log(MQTT_LOG_DEBUG, "Sending PUBREL (Mid: "+str(mid)+")") + return self._send_command_with_mid(PUBREL|2, mid, dup) + + def _send_command_with_mid(self, command, mid, dup): + # For PUBACK, PUBCOMP, PUBREC, and PUBREL + if dup: + command = command | 8 + + remaining_length = 2 + packet = struct.pack('!BBH', command, remaining_length, mid) + return self._packet_queue(command, packet, mid, 1) + + def _send_simple_command(self, command): + # For DISCONNECT, PINGREQ and PINGRESP + remaining_length = 0 + packet = struct.pack('!BB', command, remaining_length) + return self._packet_queue(command, packet, 0, 0) + + def _send_connect(self, keepalive, clean_session): + if self._protocol == MQTTv31: + protocol = PROTOCOL_NAMEv31 + proto_ver = 3 + else: + protocol = PROTOCOL_NAMEv311 + proto_ver = 4 + remaining_length = 2+len(protocol) + 1+1+2 + 2+len(self._client_id) + connect_flags = 0 + if clean_session: + connect_flags = connect_flags | 0x02 + + if self._will: + if self._will_payload is not None: + remaining_length = remaining_length + 2+len(self._will_topic) + 2+len(self._will_payload) + else: + remaining_length = remaining_length + 2+len(self._will_topic) + 2 + + connect_flags = connect_flags | 0x04 | ((self._will_qos&0x03) << 3) | ((self._will_retain&0x01) << 5) + + if self._username: + remaining_length = remaining_length + 2+len(self._username) + connect_flags = connect_flags | 0x80 + if self._password: + connect_flags = connect_flags | 0x40 + remaining_length = remaining_length + 2+len(self._password) + + command = CONNECT + packet = bytearray() + packet.extend(struct.pack("!B", command)) + + self._pack_remaining_length(packet, remaining_length) + packet.extend(struct.pack("!H"+str(len(protocol))+"sBBH", len(protocol), protocol, proto_ver, connect_flags, keepalive)) + + self._pack_str16(packet, self._client_id) + + if self._will: + self._pack_str16(packet, self._will_topic) + if self._will_payload is None or len(self._will_payload) == 0: + packet.extend(struct.pack("!H", 0)) + else: + self._pack_str16(packet, self._will_payload) + + if self._username: + self._pack_str16(packet, self._username) + + if self._password: + self._pack_str16(packet, self._password) + + self._keepalive = keepalive + return self._packet_queue(command, packet, 0, 0) + + def _send_disconnect(self): + return self._send_simple_command(DISCONNECT) + + def _send_subscribe(self, dup, topics): + remaining_length = 2 + for t in topics: + remaining_length = remaining_length + 2+len(t[0])+1 + + command = SUBSCRIBE | (dup<<3) | (1<<1) + packet = bytearray() + packet.extend(struct.pack("!B", command)) + self._pack_remaining_length(packet, remaining_length) + local_mid = self._mid_generate() + packet.extend(struct.pack("!H", local_mid)) + for t in topics: + self._pack_str16(packet, t[0]) + packet.extend(struct.pack("B", t[1])) + return (self._packet_queue(command, packet, local_mid, 1), local_mid) + + def _send_unsubscribe(self, dup, topics): + remaining_length = 2 + for t in topics: + remaining_length = remaining_length + 2+len(t) + + command = UNSUBSCRIBE | (dup<<3) | (1<<1) + packet = bytearray() + packet.extend(struct.pack("!B", command)) + self._pack_remaining_length(packet, remaining_length) + local_mid = self._mid_generate() + packet.extend(struct.pack("!H", local_mid)) + for t in topics: + self._pack_str16(packet, t) + return (self._packet_queue(command, packet, local_mid, 1), local_mid) + + def _message_retry_check_actual(self, messages, mutex): + mutex.acquire() + now = time.time() + for m in messages: + if m.timestamp + self._message_retry < now: + if m.state == mqtt_ms_wait_for_puback or m.state == mqtt_ms_wait_for_pubrec: + m.timestamp = now + m.dup = True + self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + elif m.state == mqtt_ms_wait_for_pubrel: + m.timestamp = now + m.dup = True + self._send_pubrec(m.mid) + elif m.state == mqtt_ms_wait_for_pubcomp: + m.timestamp = now + m.dup = True + self._send_pubrel(m.mid, True) + mutex.release() + + def _message_retry_check(self): + self._message_retry_check_actual(self._out_messages, self._out_message_mutex) + self._message_retry_check_actual(self._in_messages, self._in_message_mutex) + + def _messages_reconnect_reset_out(self): + self._out_message_mutex.acquire() + self._inflight_messages = 0 + for m in self._out_messages: + m.timestamp = 0 + if self._max_inflight_messages == 0 or self._inflight_messages < self._max_inflight_messages: + if m.qos == 0: + m.state = mqtt_ms_publish + elif m.qos == 1: + #self._inflight_messages = self._inflight_messages + 1 + if m.state == mqtt_ms_wait_for_puback: + m.dup = True + m.state = mqtt_ms_publish + elif m.qos == 2: + #self._inflight_messages = self._inflight_messages + 1 + if m.state == mqtt_ms_wait_for_pubcomp: + m.state = mqtt_ms_resend_pubrel + m.dup = True + else: + if m.state == mqtt_ms_wait_for_pubrec: + m.dup = True + m.state = mqtt_ms_publish + else: + m.state = mqtt_ms_queued + self._out_message_mutex.release() + + def _messages_reconnect_reset_in(self): + self._in_message_mutex.acquire() + for m in self._in_messages: + m.timestamp = 0 + if m.qos != 2: + self._in_messages.pop(self._in_messages.index(m)) + else: + # Preserve current state + pass + self._in_message_mutex.release() + + def _messages_reconnect_reset(self): + self._messages_reconnect_reset_out() + self._messages_reconnect_reset_in() + + def _packet_queue(self, command, packet, mid, qos): + mpkt = dict( + command = command, + mid = mid, + qos = qos, + pos = 0, + to_process = len(packet), + packet = packet) + + self._out_packet_mutex.acquire() + self._out_packet.append(mpkt) + if self._current_out_packet_mutex.acquire(False): + if self._current_out_packet is None and len(self._out_packet) > 0: + self._current_out_packet = self._out_packet.pop(0) + self._current_out_packet_mutex.release() + self._out_packet_mutex.release() + + # Write a single byte to sockpairW (connected to sockpairR) to break + # out of select() if in threaded mode. + try: + self._sockpairW.send(sockpair_data) + except socket.error as err: + if err.errno != EAGAIN: + raise + + if not self._in_callback and self._thread is None: + return self.loop_write() + else: + return MQTT_ERR_SUCCESS + + def _packet_handle(self): + cmd = self._in_packet['command']&0xF0 + if cmd == PINGREQ: + return self._handle_pingreq() + elif cmd == PINGRESP: + return self._handle_pingresp() + elif cmd == PUBACK: + return self._handle_pubackcomp("PUBACK") + elif cmd == PUBCOMP: + return self._handle_pubackcomp("PUBCOMP") + elif cmd == PUBLISH: + return self._handle_publish() + elif cmd == PUBREC: + return self._handle_pubrec() + elif cmd == PUBREL: + return self._handle_pubrel() + elif cmd == CONNACK: + return self._handle_connack() + elif cmd == SUBACK: + return self._handle_suback() + elif cmd == UNSUBACK: + return self._handle_unsuback() + else: + # If we don't recognise the command, return an error straight away. + self._easy_log(MQTT_LOG_ERR, "Error: Unrecognised command "+str(cmd)) + return MQTT_ERR_PROTOCOL + + def _handle_pingreq(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 0: + return MQTT_ERR_PROTOCOL + + self._easy_log(MQTT_LOG_DEBUG, "Received PINGREQ") + return self._send_pingresp() + + def _handle_pingresp(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 0: + return MQTT_ERR_PROTOCOL + + # No longer waiting for a PINGRESP. + self._ping_t = 0 + self._easy_log(MQTT_LOG_DEBUG, "Received PINGRESP") + return MQTT_ERR_SUCCESS + + def _handle_connack(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + if len(self._in_packet['packet']) != 2: + return MQTT_ERR_PROTOCOL + + (flags, result) = struct.unpack("!BB", self._in_packet['packet']) + if result == CONNACK_REFUSED_PROTOCOL_VERSION and self._protocol == MQTTv311: + self._easy_log(MQTT_LOG_DEBUG, "Received CONNACK ("+str(flags)+", "+str(result)+"), attempting downgrade to MQTT v3.1.") + # Downgrade to MQTT v3.1 + self._protocol = MQTTv31 + return self.reconnect() + + if result == 0: + self._state = mqtt_cs_connected + + self._easy_log(MQTT_LOG_DEBUG, "Received CONNACK ("+str(flags)+", "+str(result)+")") + self._callback_mutex.acquire() + if self.on_connect: + self._in_callback = True + + if sys.version_info[0] < 3: + argcount = self.on_connect.func_code.co_argcount + else: + argcount = self.on_connect.__code__.co_argcount + + if argcount == 3: + self.on_connect(self, self._userdata, result) + else: + flags_dict = dict() + flags_dict['session present'] = flags & 0x01 + self.on_connect(self, self._userdata, flags_dict, result) + self._in_callback = False + self._callback_mutex.release() + + # Start counting for stable connection + self._backoffCore.startStableConnectionTimer() + + if result == 0: + rc = 0 + self._out_message_mutex.acquire() + for m in self._out_messages: + m.timestamp = time.time() + if m.state == mqtt_ms_queued: + self.loop_write() # Process outgoing messages that have just been queued up + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + + if m.qos == 0: + self._in_callback = True # Don't call loop_write after _send_publish() + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + elif m.qos == 1: + if m.state == mqtt_ms_publish: + self._inflight_messages = self._inflight_messages + 1 + m.state = mqtt_ms_wait_for_puback + self._in_callback = True # Don't call loop_write after _send_publish() + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + elif m.qos == 2: + if m.state == mqtt_ms_publish: + self._inflight_messages = self._inflight_messages + 1 + m.state = mqtt_ms_wait_for_pubrec + self._in_callback = True # Don't call loop_write after _send_publish() + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + elif m.state == mqtt_ms_resend_pubrel: + self._inflight_messages = self._inflight_messages + 1 + m.state = mqtt_ms_wait_for_pubcomp + self._in_callback = True # Don't call loop_write after _send_pubrel() + rc = self._send_pubrel(m.mid, m.dup) + self._in_callback = False + if rc != 0: + self._out_message_mutex.release() + return rc + self.loop_write() # Process outgoing messages that have just been queued up + self._out_message_mutex.release() + return rc + elif result > 0 and result < 6: + return MQTT_ERR_CONN_REFUSED + else: + return MQTT_ERR_PROTOCOL + + def _handle_suback(self): + self._easy_log(MQTT_LOG_DEBUG, "Received SUBACK") + pack_format = "!H" + str(len(self._in_packet['packet'])-2) + 's' + (mid, packet) = struct.unpack(pack_format, self._in_packet['packet']) + pack_format = "!" + "B"*len(packet) + granted_qos = struct.unpack(pack_format, packet) + + self._callback_mutex.acquire() + if self.on_subscribe: + self._in_callback = True + self.on_subscribe(self, self._userdata, mid, granted_qos) + self._in_callback = False + self._callback_mutex.release() + + return MQTT_ERR_SUCCESS + + def _handle_publish(self): + rc = 0 + + header = self._in_packet['command'] + message = MQTTMessage() + message.dup = (header & 0x08)>>3 + message.qos = (header & 0x06)>>1 + message.retain = (header & 0x01) + + pack_format = "!H" + str(len(self._in_packet['packet'])-2) + 's' + (slen, packet) = struct.unpack(pack_format, self._in_packet['packet']) + pack_format = '!' + str(slen) + 's' + str(len(packet)-slen) + 's' + (message.topic, packet) = struct.unpack(pack_format, packet) + + if len(message.topic) == 0: + return MQTT_ERR_PROTOCOL + + if sys.version_info[0] >= 3: + message.topic = message.topic.decode('utf-8') + + if message.qos > 0: + pack_format = "!H" + str(len(packet)-2) + 's' + (message.mid, packet) = struct.unpack(pack_format, packet) + + message.payload = packet + + self._easy_log( + MQTT_LOG_DEBUG, + "Received PUBLISH (d"+str(message.dup)+ + ", q"+str(message.qos)+", r"+str(message.retain)+ + ", m"+str(message.mid)+", '"+message.topic+ + "', ... ("+str(len(message.payload))+" bytes)") + + message.timestamp = time.time() + if message.qos == 0: + self._handle_on_message(message) + return MQTT_ERR_SUCCESS + elif message.qos == 1: + rc = self._send_puback(message.mid) + self._handle_on_message(message) + return rc + elif message.qos == 2: + rc = self._send_pubrec(message.mid) + message.state = mqtt_ms_wait_for_pubrel + self._in_message_mutex.acquire() + self._in_messages.append(message) + self._in_message_mutex.release() + return rc + else: + return MQTT_ERR_PROTOCOL + + def _handle_pubrel(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + if len(self._in_packet['packet']) != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received PUBREL (Mid: "+str(mid)+")") + + self._in_message_mutex.acquire() + for i in range(len(self._in_messages)): + if self._in_messages[i].mid == mid: + + # Only pass the message on if we have removed it from the queue - this + # prevents multiple callbacks for the same message. + self._handle_on_message(self._in_messages[i]) + self._in_messages.pop(i) + self._inflight_messages = self._inflight_messages - 1 + if self._max_inflight_messages > 0: + self._out_message_mutex.acquire() + rc = self._update_inflight() + self._out_message_mutex.release() + if rc != MQTT_ERR_SUCCESS: + self._in_message_mutex.release() + return rc + + self._in_message_mutex.release() + return self._send_pubcomp(mid) + + self._in_message_mutex.release() + return MQTT_ERR_SUCCESS + + def _update_inflight(self): + # Dont lock message_mutex here + for m in self._out_messages: + if self._inflight_messages < self._max_inflight_messages: + if m.qos > 0 and m.state == mqtt_ms_queued: + self._inflight_messages = self._inflight_messages + 1 + if m.qos == 1: + m.state = mqtt_ms_wait_for_puback + elif m.qos == 2: + m.state = mqtt_ms_wait_for_pubrec + rc = self._send_publish(m.mid, m.topic, m.payload, m.qos, m.retain, m.dup) + if rc != 0: + return rc + else: + return MQTT_ERR_SUCCESS + return MQTT_ERR_SUCCESS + + def _handle_pubrec(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received PUBREC (Mid: "+str(mid)+")") + + self._out_message_mutex.acquire() + for m in self._out_messages: + if m.mid == mid: + m.state = mqtt_ms_wait_for_pubcomp + m.timestamp = time.time() + self._out_message_mutex.release() + return self._send_pubrel(mid, False) + + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + + def _handle_unsuback(self): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received UNSUBACK (Mid: "+str(mid)+")") + self._callback_mutex.acquire() + if self.on_unsubscribe: + self._in_callback = True + self.on_unsubscribe(self, self._userdata, mid) + self._in_callback = False + self._callback_mutex.release() + return MQTT_ERR_SUCCESS + + def _handle_pubackcomp(self, cmd): + if self._strict_protocol: + if self._in_packet['remaining_length'] != 2: + return MQTT_ERR_PROTOCOL + + mid = struct.unpack("!H", self._in_packet['packet']) + mid = mid[0] + self._easy_log(MQTT_LOG_DEBUG, "Received "+cmd+" (Mid: "+str(mid)+")") + + self._out_message_mutex.acquire() + for i in range(len(self._out_messages)): + try: + if self._out_messages[i].mid == mid: + # Only inform the client the message has been sent once. + self._callback_mutex.acquire() + if self.on_publish: + self._out_message_mutex.release() + self._in_callback = True + self.on_publish(self, self._userdata, mid) + self._in_callback = False + self._out_message_mutex.acquire() + + self._callback_mutex.release() + self._out_messages.pop(i) + self._inflight_messages = self._inflight_messages - 1 + if self._max_inflight_messages > 0: + rc = self._update_inflight() + if rc != MQTT_ERR_SUCCESS: + self._out_message_mutex.release() + return rc + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + except IndexError: + # Have removed item so i>count. + # Not really an error. + pass + + self._out_message_mutex.release() + return MQTT_ERR_SUCCESS + + def _handle_on_message(self, message): + self._callback_mutex.acquire() + matched = False + for t in self.on_message_filtered: + if topic_matches_sub(t[0], message.topic): + self._in_callback = True + t[1](self, self._userdata, message) + self._in_callback = False + matched = True + + if matched == False and self.on_message: + self._in_callback = True + self.on_message(self, self._userdata, message) + self._in_callback = False + + self._callback_mutex.release() + + def _thread_main(self): + self._state_mutex.acquire() + if self._state == mqtt_cs_connect_async: + self._state_mutex.release() + self.reconnect() + else: + self._state_mutex.release() + + self.loop_forever() + + def _host_matches_cert(self, host, cert_host): + if cert_host[0:2] == "*.": + if cert_host.count("*") != 1: + return False + + host_match = host.split(".", 1)[1] + cert_match = cert_host.split(".", 1)[1] + if host_match == cert_match: + return True + else: + return False + else: + if host == cert_host: + return True + else: + return False + + def _tls_match_hostname(self): + try: + cert = self._ssl.getpeercert() + except AttributeError: + # the getpeercert can throw Attribute error: object has no attribute 'peer_certificate' + # Don't let that crash the whole client. See also: http://bugs.python.org/issue13721 + raise ssl.SSLError('Not connected') + + san = cert.get('subjectAltName') + if san: + have_san_dns = False + for (key, value) in san: + if key == 'DNS': + have_san_dns = True + if self._host_matches_cert(self._host.lower(), value.lower()) == True: + return + if key == 'IP Address': + have_san_dns = True + if value.lower().strip() == self._host.lower().strip(): + return + + if have_san_dns: + # Only check subject if subjectAltName dns not found. + raise ssl.SSLError('Certificate subject does not match remote hostname.') + subject = cert.get('subject') + if subject: + for ((key, value),) in subject: + if key == 'commonName': + if self._host_matches_cert(self._host.lower(), value.lower()) == True: + return + + raise ssl.SSLError('Certificate subject does not match remote hostname.') + + +# Compatibility class for easy porting from mosquitto.py. +class Mosquitto(Client): + def __init__(self, client_id="", clean_session=True, userdata=None): + super(Mosquitto, self).__init__(client_id, clean_session, userdata) diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/deviceShadow.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/deviceShadow.py new file mode 100644 index 0000000..f58240a --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/deviceShadow.py @@ -0,0 +1,430 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import json +import logging +import uuid +from threading import Timer, Lock, Thread + + +class _shadowRequestToken: + + URN_PREFIX_LENGTH = 9 + + def getNextToken(self): + return uuid.uuid4().urn[self.URN_PREFIX_LENGTH:] # We only need the uuid digits, not the urn prefix + + +class _basicJSONParser: + + def setString(self, srcString): + self._rawString = srcString + self._dictionObject = None + + def regenerateString(self): + return json.dumps(self._dictionaryObject) + + def getAttributeValue(self, srcAttributeKey): + return self._dictionaryObject.get(srcAttributeKey) + + def setAttributeValue(self, srcAttributeKey, srcAttributeValue): + self._dictionaryObject[srcAttributeKey] = srcAttributeValue + + def validateJSON(self): + try: + self._dictionaryObject = json.loads(self._rawString) + except ValueError: + return False + return True + + +class deviceShadow: + _logger = logging.getLogger(__name__) + + def __init__(self, srcShadowName, srcIsPersistentSubscribe, srcShadowManager): + """ + + The class that denotes a local/client-side device shadow instance. + + Users can perform shadow operations on this instance to retrieve and modify the + corresponding shadow JSON document in AWS IoT Cloud. The following shadow operations + are available: + + - Get + + - Update + + - Delete + + - Listen on delta + + - Cancel listening on delta + + This is returned from :code:`AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTShadowClient.createShadowWithName` function call. + No need to call directly from user scripts. + + """ + if srcShadowName is None or srcIsPersistentSubscribe is None or srcShadowManager is None: + raise TypeError("None type inputs detected.") + self._shadowName = srcShadowName + # Tool handler + self._shadowManagerHandler = srcShadowManager + self._basicJSONParserHandler = _basicJSONParser() + self._tokenHandler = _shadowRequestToken() + # Properties + self._isPersistentSubscribe = srcIsPersistentSubscribe + self._lastVersionInSync = -1 # -1 means not initialized + self._isGetSubscribed = False + self._isUpdateSubscribed = False + self._isDeleteSubscribed = False + self._shadowSubscribeCallbackTable = dict() + self._shadowSubscribeCallbackTable["get"] = None + self._shadowSubscribeCallbackTable["delete"] = None + self._shadowSubscribeCallbackTable["update"] = None + self._shadowSubscribeCallbackTable["delta"] = None + self._shadowSubscribeStatusTable = dict() + self._shadowSubscribeStatusTable["get"] = 0 + self._shadowSubscribeStatusTable["delete"] = 0 + self._shadowSubscribeStatusTable["update"] = 0 + self._tokenPool = dict() + self._dataStructureLock = Lock() + + def _doNonPersistentUnsubscribe(self, currentAction): + self._shadowManagerHandler.basicShadowUnsubscribe(self._shadowName, currentAction) + self._logger.info("Unsubscribed to " + currentAction + " accepted/rejected topics for deviceShadow: " + self._shadowName) + + def generalCallback(self, client, userdata, message): + # In Py3.x, message.payload comes in as a bytes(string) + # json.loads needs a string input + with self._dataStructureLock: + currentTopic = message.topic + currentAction = self._parseTopicAction(currentTopic) # get/delete/update/delta + currentType = self._parseTopicType(currentTopic) # accepted/rejected/delta + payloadUTF8String = message.payload.decode('utf-8') + # get/delete/update: Need to deal with token, timer and unsubscribe + if currentAction in ["get", "delete", "update"]: + # Check for token + self._basicJSONParserHandler.setString(payloadUTF8String) + if self._basicJSONParserHandler.validateJSON(): # Filter out invalid JSON + currentToken = self._basicJSONParserHandler.getAttributeValue(u"clientToken") + if currentToken is not None: + self._logger.debug("shadow message clientToken: " + currentToken) + if currentToken is not None and currentToken in self._tokenPool.keys(): # Filter out JSON without the desired token + # Sync local version when it is an accepted response + self._logger.debug("Token is in the pool. Type: " + currentType) + if currentType == "accepted": + incomingVersion = self._basicJSONParserHandler.getAttributeValue(u"version") + # If it is get/update accepted response, we need to sync the local version + if incomingVersion is not None and incomingVersion > self._lastVersionInSync and currentAction != "delete": + self._lastVersionInSync = incomingVersion + # If it is a delete accepted, we need to reset the version + else: + self._lastVersionInSync = -1 # The version will always be synced for the next incoming delta/GU-accepted response + # Cancel the timer and clear the token + self._tokenPool[currentToken].cancel() + del self._tokenPool[currentToken] + # Need to unsubscribe? + self._shadowSubscribeStatusTable[currentAction] -= 1 + if not self._isPersistentSubscribe and self._shadowSubscribeStatusTable.get(currentAction) <= 0: + self._shadowSubscribeStatusTable[currentAction] = 0 + processNonPersistentUnsubscribe = Thread(target=self._doNonPersistentUnsubscribe, args=[currentAction]) + processNonPersistentUnsubscribe.start() + # Custom callback + if self._shadowSubscribeCallbackTable.get(currentAction) is not None: + processCustomCallback = Thread(target=self._shadowSubscribeCallbackTable[currentAction], args=[payloadUTF8String, currentType, currentToken]) + processCustomCallback.start() + # delta: Watch for version + else: + currentType += "/" + self._parseTopicShadowName(currentTopic) + # Sync local version + self._basicJSONParserHandler.setString(payloadUTF8String) + if self._basicJSONParserHandler.validateJSON(): # Filter out JSON without version + incomingVersion = self._basicJSONParserHandler.getAttributeValue(u"version") + if incomingVersion is not None and incomingVersion > self._lastVersionInSync: + self._lastVersionInSync = incomingVersion + # Custom callback + if self._shadowSubscribeCallbackTable.get(currentAction) is not None: + processCustomCallback = Thread(target=self._shadowSubscribeCallbackTable[currentAction], args=[payloadUTF8String, currentType, None]) + processCustomCallback.start() + + def _parseTopicAction(self, srcTopic): + ret = None + fragments = srcTopic.split('/') + if fragments[5] == "delta": + ret = "delta" + else: + ret = fragments[4] + return ret + + def _parseTopicType(self, srcTopic): + fragments = srcTopic.split('/') + return fragments[5] + + def _parseTopicShadowName(self, srcTopic): + fragments = srcTopic.split('/') + return fragments[2] + + def _timerHandler(self, srcActionName, srcToken): + with self._dataStructureLock: + # Don't crash if we try to remove an unknown token + if srcToken not in self._tokenPool: + self._logger.warn('Tried to remove non-existent token from pool: %s' % str(srcToken)) + return + # Remove the token + del self._tokenPool[srcToken] + # Need to unsubscribe? + self._shadowSubscribeStatusTable[srcActionName] -= 1 + if not self._isPersistentSubscribe and self._shadowSubscribeStatusTable.get(srcActionName) <= 0: + self._shadowSubscribeStatusTable[srcActionName] = 0 + self._shadowManagerHandler.basicShadowUnsubscribe(self._shadowName, srcActionName) + # Notify time-out issue + if self._shadowSubscribeCallbackTable.get(srcActionName) is not None: + self._logger.info("Shadow request with token: " + str(srcToken) + " has timed out.") + self._shadowSubscribeCallbackTable[srcActionName]("REQUEST TIME OUT", "timeout", srcToken) + + def shadowGet(self, srcCallback, srcTimeout): + """ + **Description** + + Retrieve the device shadow JSON document from AWS IoT by publishing an empty JSON document to the + corresponding shadow topics. Shadow response topics will be subscribed to receive responses from + AWS IoT regarding the result of the get operation. Retrieved shadow JSON document will be available + in the registered callback. If no response is received within the provided timeout, a timeout + notification will be passed into the registered callback. + + **Syntax** + + .. code:: python + + # Retrieve the shadow JSON document from AWS IoT, with a timeout set to 5 seconds + BotShadow.shadowGet(customCallback, 5) + + **Parameters** + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + *srcTimeout* - Timeout to determine whether the request is invalid. When a request gets timeout, + a timeout notification will be generated and put into the registered callback to notify users. + + **Returns** + + The token used for tracing in this shadow request. + + """ + with self._dataStructureLock: + # Update callback data structure + self._shadowSubscribeCallbackTable["get"] = srcCallback + # Update number of pending feedback + self._shadowSubscribeStatusTable["get"] += 1 + # clientToken + currentToken = self._tokenHandler.getNextToken() + self._tokenPool[currentToken] = Timer(srcTimeout, self._timerHandler, ["get", currentToken]) + self._basicJSONParserHandler.setString("{}") + self._basicJSONParserHandler.validateJSON() + self._basicJSONParserHandler.setAttributeValue("clientToken", currentToken) + currentPayload = self._basicJSONParserHandler.regenerateString() + # Two subscriptions + if not self._isPersistentSubscribe or not self._isGetSubscribed: + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "get", self.generalCallback) + self._isGetSubscribed = True + self._logger.info("Subscribed to get accepted/rejected topics for deviceShadow: " + self._shadowName) + # One publish + self._shadowManagerHandler.basicShadowPublish(self._shadowName, "get", currentPayload) + # Start the timer + self._tokenPool[currentToken].start() + return currentToken + + def shadowDelete(self, srcCallback, srcTimeout): + """ + **Description** + + Delete the device shadow from AWS IoT by publishing an empty JSON document to the corresponding + shadow topics. Shadow response topics will be subscribed to receive responses from AWS IoT + regarding the result of the get operation. Responses will be available in the registered callback. + If no response is received within the provided timeout, a timeout notification will be passed into + the registered callback. + + **Syntax** + + .. code:: python + + # Delete the device shadow from AWS IoT, with a timeout set to 5 seconds + BotShadow.shadowDelete(customCallback, 5) + + **Parameters** + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + *srcTimeout* - Timeout to determine whether the request is invalid. When a request gets timeout, + a timeout notification will be generated and put into the registered callback to notify users. + + **Returns** + + The token used for tracing in this shadow request. + + """ + with self._dataStructureLock: + # Update callback data structure + self._shadowSubscribeCallbackTable["delete"] = srcCallback + # Update number of pending feedback + self._shadowSubscribeStatusTable["delete"] += 1 + # clientToken + currentToken = self._tokenHandler.getNextToken() + self._tokenPool[currentToken] = Timer(srcTimeout, self._timerHandler, ["delete", currentToken]) + self._basicJSONParserHandler.setString("{}") + self._basicJSONParserHandler.validateJSON() + self._basicJSONParserHandler.setAttributeValue("clientToken", currentToken) + currentPayload = self._basicJSONParserHandler.regenerateString() + # Two subscriptions + if not self._isPersistentSubscribe or not self._isDeleteSubscribed: + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "delete", self.generalCallback) + self._isDeleteSubscribed = True + self._logger.info("Subscribed to delete accepted/rejected topics for deviceShadow: " + self._shadowName) + # One publish + self._shadowManagerHandler.basicShadowPublish(self._shadowName, "delete", currentPayload) + # Start the timer + self._tokenPool[currentToken].start() + return currentToken + + def shadowUpdate(self, srcJSONPayload, srcCallback, srcTimeout): + """ + **Description** + + Update the device shadow JSON document string from AWS IoT by publishing the provided JSON + document to the corresponding shadow topics. Shadow response topics will be subscribed to + receive responses from AWS IoT regarding the result of the get operation. Response will be + available in the registered callback. If no response is received within the provided timeout, + a timeout notification will be passed into the registered callback. + + **Syntax** + + .. code:: python + + # Update the shadow JSON document from AWS IoT, with a timeout set to 5 seconds + BotShadow.shadowUpdate(newShadowJSONDocumentString, customCallback, 5) + + **Parameters** + + *srcJSONPayload* - JSON document string used to update shadow JSON document in AWS IoT. + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + *srcTimeout* - Timeout to determine whether the request is invalid. When a request gets timeout, + a timeout notification will be generated and put into the registered callback to notify users. + + **Returns** + + The token used for tracing in this shadow request. + + """ + # Validate JSON + self._basicJSONParserHandler.setString(srcJSONPayload) + if self._basicJSONParserHandler.validateJSON(): + with self._dataStructureLock: + # clientToken + currentToken = self._tokenHandler.getNextToken() + self._tokenPool[currentToken] = Timer(srcTimeout, self._timerHandler, ["update", currentToken]) + self._basicJSONParserHandler.setAttributeValue("clientToken", currentToken) + JSONPayloadWithToken = self._basicJSONParserHandler.regenerateString() + # Update callback data structure + self._shadowSubscribeCallbackTable["update"] = srcCallback + # Update number of pending feedback + self._shadowSubscribeStatusTable["update"] += 1 + # Two subscriptions + if not self._isPersistentSubscribe or not self._isUpdateSubscribed: + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "update", self.generalCallback) + self._isUpdateSubscribed = True + self._logger.info("Subscribed to update accepted/rejected topics for deviceShadow: " + self._shadowName) + # One publish + self._shadowManagerHandler.basicShadowPublish(self._shadowName, "update", JSONPayloadWithToken) + # Start the timer + self._tokenPool[currentToken].start() + else: + raise ValueError("Invalid JSON file.") + return currentToken + + def shadowRegisterDeltaCallback(self, srcCallback): + """ + **Description** + + Listen on delta topics for this device shadow by subscribing to delta topics. Whenever there + is a difference between the desired and reported state, the registered callback will be called + and the delta payload will be available in the callback. + + **Syntax** + + .. code:: python + + # Listen on delta topics for BotShadow + BotShadow.shadowRegisterDeltaCallback(customCallback) + + **Parameters** + + *srcCallback* - Function to be called when the response for this shadow request comes back. Should + be in form :code:`customCallback(payload, responseStatus, token)`, where :code:`payload` is the + JSON document returned, :code:`responseStatus` indicates whether the request has been accepted, + rejected or is a delta message, :code:`token` is the token used for tracing in this request. + + **Returns** + + None + + """ + with self._dataStructureLock: + # Update callback data structure + self._shadowSubscribeCallbackTable["delta"] = srcCallback + # One subscription + self._shadowManagerHandler.basicShadowSubscribe(self._shadowName, "delta", self.generalCallback) + self._logger.info("Subscribed to delta topic for deviceShadow: " + self._shadowName) + + def shadowUnregisterDeltaCallback(self): + """ + **Description** + + Cancel listening on delta topics for this device shadow by unsubscribing to delta topics. There will + be no delta messages received after this API call even though there is a difference between the + desired and reported state. + + **Syntax** + + .. code:: python + + # Cancel listening on delta topics for BotShadow + BotShadow.shadowUnregisterDeltaCallback() + + **Parameters** + + None + + **Returns** + + None + + """ + with self._dataStructureLock: + # Update callback data structure + del self._shadowSubscribeCallbackTable["delta"] + # One unsubscription + self._shadowManagerHandler.basicShadowUnsubscribe(self._shadowName, "delta") + self._logger.info("Unsubscribed to delta topics for deviceShadow: " + self._shadowName) diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/shadowManager.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/shadowManager.py new file mode 100644 index 0000000..3dafa74 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/shadow/shadowManager.py @@ -0,0 +1,83 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import logging +import time +from threading import Lock + +class _shadowAction: + _actionType = ["get", "update", "delete", "delta"] + + def __init__(self, srcShadowName, srcActionName): + if srcActionName is None or srcActionName not in self._actionType: + raise TypeError("Unsupported shadow action.") + self._shadowName = srcShadowName + self._actionName = srcActionName + self.isDelta = srcActionName == "delta" + if self.isDelta: + self._topicDelta = "$aws/things/" + str(self._shadowName) + "/shadow/update/delta" + else: + self._topicGeneral = "$aws/things/" + str(self._shadowName) + "/shadow/" + str(self._actionName) + self._topicAccept = "$aws/things/" + str(self._shadowName) + "/shadow/" + str(self._actionName) + "/accepted" + self._topicReject = "$aws/things/" + str(self._shadowName) + "/shadow/" + str(self._actionName) + "/rejected" + + def getTopicGeneral(self): + return self._topicGeneral + + def getTopicAccept(self): + return self._topicAccept + + def getTopicReject(self): + return self._topicReject + + def getTopicDelta(self): + return self._topicDelta + + +class shadowManager: + + _logger = logging.getLogger(__name__) + + def __init__(self, srcMQTTCore): + # Load in mqttCore + if srcMQTTCore is None: + raise TypeError("None type inputs detected.") + self._mqttCoreHandler = srcMQTTCore + self._shadowSubUnsubOperationLock = Lock() + + def basicShadowPublish(self, srcShadowName, srcShadowAction, srcPayload): + currentShadowAction = _shadowAction(srcShadowName, srcShadowAction) + self._mqttCoreHandler.publish(currentShadowAction.getTopicGeneral(), srcPayload, 0, False) + + def basicShadowSubscribe(self, srcShadowName, srcShadowAction, srcCallback): + with self._shadowSubUnsubOperationLock: + currentShadowAction = _shadowAction(srcShadowName, srcShadowAction) + if currentShadowAction.isDelta: + self._mqttCoreHandler.subscribe(currentShadowAction.getTopicDelta(), 0, srcCallback) + else: + self._mqttCoreHandler.subscribe(currentShadowAction.getTopicAccept(), 0, srcCallback) + self._mqttCoreHandler.subscribe(currentShadowAction.getTopicReject(), 0, srcCallback) + time.sleep(2) + + def basicShadowUnsubscribe(self, srcShadowName, srcShadowAction): + with self._shadowSubUnsubOperationLock: + currentShadowAction = _shadowAction(srcShadowName, srcShadowAction) + if currentShadowAction.isDelta: + self._mqttCoreHandler.unsubscribe(currentShadowAction.getTopicDelta()) + else: + self._logger.debug(currentShadowAction.getTopicAccept()) + self._mqttCoreHandler.unsubscribe(currentShadowAction.getTopicAccept()) + self._logger.debug(currentShadowAction.getTopicReject()) + self._mqttCoreHandler.unsubscribe(currentShadowAction.getTopicReject()) diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/enums.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/enums.py new file mode 100644 index 0000000..3aa3d2f --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/enums.py @@ -0,0 +1,19 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class DropBehaviorTypes(object): + DROP_OLDEST = 0 + DROP_NEWEST = 1 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/providers.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/providers.py new file mode 100644 index 0000000..d90789a --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/core/util/providers.py @@ -0,0 +1,92 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class CredentialsProvider(object): + + def __init__(self): + self._ca_path = "" + + def set_ca_path(self, ca_path): + self._ca_path = ca_path + + def get_ca_path(self): + return self._ca_path + + +class CertificateCredentialsProvider(CredentialsProvider): + + def __init__(self): + CredentialsProvider.__init__(self) + self._cert_path = "" + self._key_path = "" + + def set_cert_path(self,cert_path): + self._cert_path = cert_path + + def set_key_path(self, key_path): + self._key_path = key_path + + def get_cert_path(self): + return self._cert_path + + def get_key_path(self): + return self._key_path + + +class IAMCredentialsProvider(CredentialsProvider): + + def __init__(self): + CredentialsProvider.__init__(self) + self._aws_access_key_id = "" + self._aws_secret_access_key = "" + self._aws_session_token = "" + + def set_access_key_id(self, access_key_id): + self._aws_access_key_id = access_key_id + + def set_secret_access_key(self, secret_access_key): + self._aws_secret_access_key = secret_access_key + + def set_session_token(self, session_token): + self._aws_session_token = session_token + + def get_access_key_id(self): + return self._aws_access_key_id + + def get_secret_access_key(self): + return self._aws_secret_access_key + + def get_session_token(self): + return self._aws_session_token + + +class EndpointProvider(object): + + def __init__(self): + self._host = "" + self._port = -1 + + def set_host(self, host): + self._host = host + + def set_port(self, port): + self._port = port + + def get_host(self): + return self._host + + def get_port(self): + return self._port diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/AWSIoTExceptions.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/AWSIoTExceptions.py new file mode 100644 index 0000000..0de5401 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/AWSIoTExceptions.py @@ -0,0 +1,153 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + +import AWSIoTPythonSDK.exception.operationTimeoutException as operationTimeoutException +import AWSIoTPythonSDK.exception.operationError as operationError + + +# Serial Exception +class acceptTimeoutException(Exception): + def __init__(self, msg="Accept Timeout"): + self.message = msg + + +# MQTT Operation Timeout Exception +class connectTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Connect Timeout"): + self.message = msg + + +class disconnectTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Disconnect Timeout"): + self.message = msg + + +class publishTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Publish Timeout"): + self.message = msg + + +class subscribeTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Subscribe Timeout"): + self.message = msg + + +class unsubscribeTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, msg="Unsubscribe Timeout"): + self.message = msg + + +# MQTT Operation Error +class connectError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Connect Error: " + str(errorCode) + + +class disconnectError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Disconnect Error: " + str(errorCode) + + +class publishError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Publish Error: " + str(errorCode) + + +class publishQueueFullException(operationError.operationError): + def __init__(self): + self.message = "Internal Publish Queue Full" + + +class publishQueueDisabledException(operationError.operationError): + def __init__(self): + self.message = "Offline publish request dropped because queueing is disabled" + + +class subscribeError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Subscribe Error: " + str(errorCode) + + +class subscribeQueueFullException(operationError.operationError): + def __init__(self): + self.message = "Internal Subscribe Queue Full" + + +class subscribeQueueDisabledException(operationError.operationError): + def __init__(self): + self.message = "Offline subscribe request dropped because queueing is disabled" + + +class unsubscribeError(operationError.operationError): + def __init__(self, errorCode): + self.message = "Unsubscribe Error: " + str(errorCode) + + +class unsubscribeQueueFullException(operationError.operationError): + def __init__(self): + self.message = "Internal Unsubscribe Queue Full" + + +class unsubscribeQueueDisabledException(operationError.operationError): + def __init__(self): + self.message = "Offline unsubscribe request dropped because queueing is disabled" + + +# Websocket Error +class wssNoKeyInEnvironmentError(operationError.operationError): + def __init__(self): + self.message = "No AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY detected in $ENV." + + +class wssHandShakeError(operationError.operationError): + def __init__(self): + self.message = "Error in WSS handshake." + + +# Greengrass Discovery Error +class DiscoveryDataNotFoundException(operationError.operationError): + def __init__(self): + self.message = "No discovery data found" + + +class DiscoveryTimeoutException(operationTimeoutException.operationTimeoutException): + def __init__(self, message="Discovery request timed out"): + self.message = message + + +class DiscoveryInvalidRequestException(operationError.operationError): + def __init__(self): + self.message = "Invalid discovery request" + + +class DiscoveryUnauthorizedException(operationError.operationError): + def __init__(self): + self.message = "Discovery request not authorized" + + +class DiscoveryThrottlingException(operationError.operationError): + def __init__(self): + self.message = "Too many discovery requests" + + +class DiscoveryFailure(operationError.operationError): + def __init__(self, message): + self.message = message + + +# Client Error +class ClientError(Exception): + def __init__(self, message): + self.message = message diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/__init__.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationError.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationError.py new file mode 100644 index 0000000..1c86dfc --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationError.py @@ -0,0 +1,19 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class operationError(Exception): + def __init__(self, msg="Operation Error"): + self.message = msg diff --git a/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationTimeoutException.py b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationTimeoutException.py new file mode 100644 index 0000000..737154e --- /dev/null +++ b/Device/aws-iot-device-sdk-python/build/lib.linux-x86_64-2.7/AWSIoTPythonSDK/exception/operationTimeoutException.py @@ -0,0 +1,19 @@ +# /* +# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"). +# * You may not use this file except in compliance with the License. +# * A copy of the License is located at +# * +# * http://aws.amazon.com/apache2.0 +# * +# * or in the "license" file accompanying this file. This file is distributed +# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# * express or implied. See the License for the specific language governing +# * permissions and limitations under the License. +# */ + + +class operationTimeoutException(Exception): + def __init__(self, msg="Operation Timeout"): + self.message = msg diff --git a/Device/aws-iot-device-sdk-python/setup.cfg b/Device/aws-iot-device-sdk-python/setup.cfg new file mode 100644 index 0000000..5aef279 --- /dev/null +++ b/Device/aws-iot-device-sdk-python/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.rst diff --git a/Device/aws-iot-device-sdk-python/setup.py b/Device/aws-iot-device-sdk-python/setup.py new file mode 100644 index 0000000..3846bae --- /dev/null +++ b/Device/aws-iot-device-sdk-python/setup.py @@ -0,0 +1,34 @@ +import sys +sys.path.insert(0, 'AWSIoTPythonSDK') +import AWSIoTPythonSDK +currentVersion = AWSIoTPythonSDK.__version__ + +from distutils.core import setup +setup( + name = 'AWSIoTPythonSDK', + packages=['AWSIoTPythonSDK', 'AWSIoTPythonSDK.core', + 'AWSIoTPythonSDK.core.util', 'AWSIoTPythonSDK.core.shadow', 'AWSIoTPythonSDK.core.protocol', + 'AWSIoTPythonSDK.core.jobs', + 'AWSIoTPythonSDK.core.protocol.paho', 'AWSIoTPythonSDK.core.protocol.internal', + 'AWSIoTPythonSDK.core.protocol.connection', 'AWSIoTPythonSDK.core.greengrass', + 'AWSIoTPythonSDK.core.greengrass.discovery', 'AWSIoTPythonSDK.exception'], + version = currentVersion, + description = 'SDK for connecting to AWS IoT using Python.', + author = 'Amazon Web Service', + author_email = '', + url = 'https://github.com/aws/aws-iot-device-sdk-python.git', + download_url = 'https://s3.amazonaws.com/aws-iot-device-sdk-python/aws-iot-device-sdk-python-latest.zip', + keywords = ['aws', 'iot', 'mqtt'], + classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Natural Language :: English", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5" + ] +) diff --git a/Device/data_points.py b/Device/data_points.py new file mode 100644 index 0000000..90d223c --- /dev/null +++ b/Device/data_points.py @@ -0,0 +1,153 @@ +from datetime import datetime +import time +import minimalmodbus +from pycomm.ab_comm.clx import Driver as clx +from pycomm.cip.cip_base import CommError, DataError + +class DataPoint(object): + def __init__(self,changeThreshold=0,guaranteed=3600, name="datapoint",alertThreshold=[],alertCondition=[],alertResponse=[],alertContact=[], alertName=[],alertBuffer=[],alertReminder=[]): + self.value = None + self.lastvalue = None + self.lastsend = 0 + self.changeThreshold = changeThreshold + self.guaranteed = guaranteed + self.name = name + self.alertThreshold = alertThreshold + self.alertCondition = alertCondition + self.alertResponse = alertResponse + self.alertContact = alertContact + self.alertName = alertName + self.alertBuffer = alertBuffer + self.alertReminder = alertReminder + self.alerted = [False] * len(self.alertCondition) + self.reminderTimer = [0] * len(self.alertCondition) + self.alertTimer = [0] * len(self.alertCondition) + + + def checkSend(self,value): + if value != self.lastvalue or (time.time() - self.lastsend > self.guaranteed): + self.lastsend = time.time() + self.lastvalue = value + return True + else: + return False + + def checkAlert(self,value): + conditions = { + "gt": "value > threshold", + "lt": "value < threshold", + "eq": "value == threshold", + "gte": "value >= threshold", + "lte": "value <= threshold", + "not": "value != threshold", + + } + + oppositeConditions = { + "gt": "lt", + "lt": "gt", + "gte": "lte", + "lte": "gte", + "eq": "not", + "not": "eq" + } + + for x in range(len(self.alerted)): + #check value for alert threshold send back first alarmed value + evalVars = { + "value": value, + "threshold": self.alertThreshold[x][0] + } + func = conditions.get(self.alertCondition[x]) + if func == None: + print("Not an available function: {}".format(self.alertCondition[x])) + else: + result = eval(func,evalVars) + if result and not self.alerted[x]:#threshold crossed but not already alerted + if self.alertTimer[x] != 0 and time.time() - self.alertTimer[x] > self.alertBuffer[x]:#timer started and crossed threshold + self.alerted[x] = True + self.alertTimer[x] = 0 + self.reminderTimer[x] = time.time() + return {"alert": self.alertName[x] + " alarm", "contact": self.alertContact[x], "response": self.alertResponse[x]} + elif self.alertTimer[x] == 0:#timer not started yet + self.alertTimer[x] = time.time() + elif result and self.alerted[x]:#threshold crossed and already on alert + if self.alertReminder[x] and time.time() - self.reminderTimer[x] > self.alertReminder[x]: #reminder threshold crossed + self.reminderTimer[x] = time.time() + return {"alert": self.alertName[x] + " reminder", "contact": self.alertContact[x], "response": self.alertResponse[x]} + elif not result and self.alerted[x]:#threshold not crossed but previously alerted + evalVars["threshold"] = self.alertThreshold[x][1] + func = conditions.get(oppositeConditions.get(self.alertCondition[x])) + if eval(func,evalVars):#untrigger threshold crossed + if self.alertTimer[x] != 0 and time.time() - self.alertTimer[x] > self.alertBuffer[x]:#timer started and crossed threshold + self.alerted[x] = False + self.alertTimer[x] = 0 + #Send cleared alarm message + return {"alert": self.alertName[x] + " alarmed cleared", "contact": self.alertContact[x], "response": self.alertResponse[x]} + elif self.alertTimer[x] == 0:#timer not started + self.alertTimer[x] = time.time() + return None + +class modbusDataPoint(DataPoint): + def __init__(self,changeThreshold,guaranteed,name,register=1,baud=19200,stopBits=1,parity=None, device='/dev/ttyS0'): + DataPoint.__init__(self,changeThreshold,guaranteed,name) + self.register = register + self.baud = baud + self.stopBits = stopBits + self.parity = parity + self.device = device + def read(self): + pass + + def write(self): + pass + +class plcDataPoint(DataPoint): + def __init__(self,changeThreshold,guaranteed,name,plcIP='192.168.1.10',plcType='Micro800',tag=None,alertThreshold=[],alertCondition=[],alertResponse=[],alertContact=[], alertName=[],alertBuffer=[],alertReminder=[]): + DataPoint.__init__(self,changeThreshold,guaranteed,name,alertThreshold,alertCondition,alertResponse,alertContact,alertName,alertBuffer,alertReminder) + self.plcIP = plcIP + self.plcType = plcType + self.tag = tag + + def read(self): + direct_connect = self.plcType == "Micro800" + c = clx() + try: + if c.open(self.plcIP,direct_connect): + try: + val = c.read_tag(self.tag) + c.close() + alertMessage = self.checkAlert(val[0]) + return val[0], alertMessage + except DataError as derr: + print("Error: {}".format(derr)) + c.close() + except CommError as cerr: + print("Error: {}".format(cerr)) + + return False, None + + def write(self): + pass + +class currentDataPoint(DataPoint): + def __init__(self,changeThreshold,guaranteed,name, euMin=0, euMax=100, rawMin=4, rawMax=20): + DataPoint.__init__(self,changeThreshold,guaranteed,name) + self.euMin = euMin + self.euMax = euMax + self.rawMin = rawMin + self.rawMax = rawMax + + def read(self): + pass + +class voltageDataPoint(DataPoint): + def __init__(self,changeThreshold,guaranteed,name, euMin=0, euMax=100, rawMin=0, rawMax=10): + DataPoint.__init__(self,changeThreshold,guaranteed,name) + self.euMin = euMin + self.euMax = euMax + self.rawMin = rawMin + self.rawMax = rawMax + + def read(self): + pass diff --git a/Device/data_points.pyc b/Device/data_points.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a1ce46c19ed0deb7d82681d636d49c939cd1c61 GIT binary patch literal 5556 zcmdT|+j1L45bf2?mhTv162e6RLWv4kcB+7oN`>5r6R4Qf%2a|LP_1_-_S({}*c~}m zVLv%MD=E-p&6rJN4J!=YRI4|Ch(} z8cO;nssR5TX^FH&8X^wcIcYi4aP&9GIceln&PyvV?SeFlS-*m`O46Q?#)Pydr7;O@ zQA}ALVQ5L7h#ZOh)R>ZBLd=wECx_Z;3CaWQ)KEJk!Sp~oGt|yXFgwuB4YhMLv|gRZ zCc=O5S9KuSN$$zB#)fUPo~cSu-AckelT>r;Qbu(%ZnwWpk~q=UEzf$#TleEIvO|v* zFyaPE`VlGvM`gZ24ael=NnSlvplOY~xba;hoH0hH)d;;6cAYF$^WPGBa>x!2>!SX!~?wYo+(+454G zwdfJyRW>ejnE_Zr*>dj^tg|^w`?owJLPI>sx zr?Uq|o&FURnP+!Ic5{+m5bMZ}!=Qz8cXD!?kG$-PBsFfk4u{s&e##*=)x_w}qyQkQR3l)o2eYz50W98Ikm6N}=Q|PHH^E(#>v4R3FDNH>o(j2;mrx z0YIQBLvxWJ4l*q+T+fxzN0zOrZQw_!AAa<9yz}u`&vpU1-9aN)}9>XCs-e^-F)k`B( z(<_6bE@v17B*n~MXo-r7yK!zpk0&u+@IFjR$wcD#1Jn6@&CO>}KSmgta}fIW_bKpA zXxz70DI+R7oMrP}R3o2{iy}_J3Wl{(T*)~-QO;Xl51p3(B115Klp#KYaEu{}qzB&g z;09dzpagJ3MiR;m+`9(o>em;SSHHZpyt=%)qFB5a`bm6gWyL3YS%w7h1sX3+5YL1+ zCwhhs*u<{x-nU!@(nhaiY@UmFTS{Kp_46F&Kj17CRy^C$fsG02=V3%TiAtOd=?W9N zcj&i2(BS0^tUJ8B4;|j!MEODR% zV#fKNsXzGTsTAP9-6=_a6Xy_QjpN<{7Z*5Y?apWjdOnOq9z^FbqO2o+#|S3J*$7=_ z?M~##LtLSCy;#>>5EaW_FmA$Vd_a~ zj^VfB)VO-abkUYA= zRVu$>8C!lgNlav4BvIm2N%Rv4=7rZKvL;?4k!)qDmA)}?Zbd~1ev`1kig$`nCSVzY z|0)_UO`5~3>KXRrlFzZH>E6S8AD4pU?Q6=Ec#o-MZ;IZ2mFD~}lYY)0mRZ$Ut)Ln! zh6wpNMR zeCUi(`V(*NAg{?toq4~@yUQgqT^coZlF%gXO7 3.5 then current is good else current disconnected + #if voltagedata != to empty then setup polls for voltage + #if raw voltage value > 0 then voltage is good else voltage disconnected + datapoints = [] + if not config["PLCData"] == "empty": + for key in config['PLCData'].keys(): + changeThreshold = config['PLCData'][key]["changeThreshold"] + guaranteed = config['PLCData'][key]["guaranteed"] + plcIP = config['PLCData'][key]["plcIP"] + plcType = config['PLCData'][key]["plcType"] + tag = config['PLCData'][key]["tag"] + name = config['PLCData'][key]["name"] + if "alert" in config['PLCData'][key].keys(): + threshold = config['PLCData'][key]["alert"]["threshold"] + condition = config['PLCData'][key]["alert"]["condition"] + response = config['PLCData'][key]["alert"]["response"] + contact = config['PLCData'][key]["alert"]["contact"] + alertName = config['PLCData'][key]["alert"]["name"] + buffer = config['PLCData'][key]["alert"]["buffer"] + reminder = config['PLCData'][key]["alert"]["reminder"] + datapoint = plcDataPoint(changeThreshold,guaranteed,str(name),plcIP=str(plcIP),plcType=str(plcType),tag=str(tag),alertThreshold=threshold,alertCondition=condition,alertResponse=response,alertContact=contact, alertName=alertName,alertBuffer=buffer,alertReminder=reminder) + else: + datapoint = plcDataPoint(changeThreshold,guaranteed,str(name),plcIP=str(plcIP),plcType=str(plcType),tag=str(tag)) + datapoints.append(datapoint) + + if not config["modbusData"] == "empty": + pass + if not config["currentData"] == "empty": + pass + if not config["voltageData"] == "empty": + pass + + + #A function for polling data and checking alert status per datapoint. + #Latency should remain low on polls but manage thresholds for how often to send data + #Loop through list of data points to read value, check send thresholds, and check alert thresholds + def dataCollection(): + while True: + message = {} + for datapoint in datapoints: + val,alertMessage = datapoint.read() + if alertMessage != None: + alertMessage["location"] = locationID + alertMessage["timestamp"] = datetime.now().isoformat() + filelogger.info("Publishing: {}\tTo Topic: {}".format(alertMessage,alm_topic)) + myAWSIoTMQTTClient.publish(alm_topic,json.dumps(alertMessage),1) + if datapoint.checkSend(val): + message[datapoint.name] = val + if message: + message["timestamp"] = datetime.now().isoformat() + filelogger.info("Publishing: {}\tTo Topic: {}".format(message,dt_topic)) + myAWSIoTMQTTClient.publish(dt_topic, json.dumps(message),1) + time.sleep(5) + + + + # list of all threads, so that they can be killed afterwards + all_threads = [] + + data_thread = threading.Thread(target=dataCollection, args=(), name="Thread-data") + data_thread.start() + all_threads.append(data_thread) + + + + for thread in all_threads: + thread.join() + + #myAWSIoTMQTTClient.disconnect() + diff --git a/Device/driver.pyc b/Device/driver.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fe586e3d01069f53718f42610aa25009a422534 GIT binary patch literal 4144 zcmcgvUsD^`6+f#50RjQW{I>zw39)c%6t|tG&A6FR6epyF&_x+Cnn{^u_W~>SkG%Ja zpjvuzr?x*sANmP8dFflfgg-{#)A#gu&I%#iK3ixn=bn4+*>lgI-?_4XEEazJ=E0vl z>V0zf|0y2*Hw-?$7KKFhK5bFm5`K=t97Q>*=g8{G*;Kb>&8BdOqG75J_t)}N&&%2n zg(DP=Qhl_)Hb(U^SsSLXK+!nW$0?ei`UFKqsuwAmr1~VJ^Yj;(GQ~C>lt*A+@Do0J zWecPkWqVztOc1Gza~m8dF|G;X)2BhGzHnndRB5(2jm53QgPo-I)gNoM?J!WWDG#xt z2@K89tGdSBPlDK(DKMhMKW^!39&h(rX^LGpnHNcD+*8$Odc%;shlkbLc=W$98lnc= zXweIcy2Iq>sF9;iHqDcUEA@;cbI*JRf6Ktb{ie$c$5i-$C6`>WmJ&qbEBmvOFo0KRGy= zlD84FSX~D}nWm*K^n#U2R5pdoqAZd9%O&z#+iTq`HVP~vc^vWVL zLygQ445$V1WGz^+>ZyAIKnI-Bh$?@(9JumcqpsA^&~ye-7{2-Bs$WQe#EJ*jW+VR>ijKP1uS} zAIhdjvT2PvYj15@lTDZK%nCv>P2Cc8O4NWZfZ80~rkil&?a!9e^Os0?)g8 z4F7iaO4T&DP^o4J{5&zG?Ib=4PCqUco_7rcu-k0%A%ymlsOiRS(RUK4&^HB0goy_L zPU4-aOnr3`c&gTJD#Iu8RBD2g03vFqswctm4bIp9%8T7F>N7wXHqA@oSb0YI`W9xJ zl}zvBZRp!PS8cugHg_xbx3^@usUnmwPCA338u;-8Q|hVvxYRq>{_Zv-xST~rP1BYp z;GMbgsj8i&N}naY^PRTb)Qyc&z6hgn?Cgs>K*=$I_Jocg;Syi5SFYQM1Zbd>$b6uQ zc#xL9!QtkPrvHiI@*j-z=?@4pbus-dms$0@$JDjBji9$63%k-%xUm56EJ{)RpizAg zu<6OOdBXP)jP&mW^Uz4J37r8WgNsE^7^+63JE08_LmYsU>zE;LOdzj74Z(4)eOrJM zWr`lkjbTV+pV^ev0w>y@M32ir8#ij|JK*iNj>ABoAs5;Ig<4XoCC$L&i3BR(jb%;_ zabhiPDIrqj`dKoZDewG1#lFMp96a1YiQ?pYSr2q_lBAJqWLprQBqopL9*^_5nVBH# z4V}bUQM6#7u-IN<=}@U=nRQEyd*vxF@sTf0xi9eYg&StK366GuNoThdb7c5{QV=J& zn4p?Zk+__XQTu-`CE$`i!%&H0Q}HU_XcS~+FYuDmSJ)b>N;OTI$H`@>{Dq3sc4;4W zZ&a@7(pJkPI6bPcR8wwLdWz&#X$5a8?R;IURHY^>zLffAvyG;i*}R>EA&Lz9zGWNc zF_1N8<*lMMVNF@HpysV5Yt8a_g+E+Z2Y57RtIq()oV_vzdTV&MM`8eTarraXXG*{l zw8N!`)4{musmf9Wl-7)#TB~rZfU(QnLBw|Uo_;NQVA^h$CY({O@Aq!A0;2~8W=2;W&OhDO zawu*5q-C6Sez!nB!zIuTDBeodXR)89?Ccmk5p+FHa@%*}u<=8D$5U9kFp_99k`LwP{Z zv~}CMYuQ*US|#jVF66;mux1ASo>;TFX~^`Rk;R3vd_K3zd$Mt;Xq6?JlGG1jhcpo9 zBTy2$UNvv_l0!=kJD>70M=ZnZ{kAzv;)CiRHu>k|Zg4Es=6uOg3?vdCskN*Y9Ekxp oHix6*xEQkFfXJwK8x1apC%BfhLiGvfrreGu#L4XF?746M7v4*jLjV8( literal 0 HcmV?d00001 diff --git a/Device/logs/device1.log b/Device/logs/device1.log new file mode 100644 index 0000000..250aea1 --- /dev/null +++ b/Device/logs/device1.log @@ -0,0 +1,93 @@ +2020-01-20 14:24:51,205 INFO run(26) IN Driver +2020-01-20 14:24:51,206 INFO run(27) Got Config: +{u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': u'empty', u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-20 14:26:34,220 INFO run(26) IN Driver +2020-01-20 14:26:34,222 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': u'empty', u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-20 15:08:28,235 INFO run(26) IN Driver +2020-01-20 15:08:28,236 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': u'empty', u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-20 15:09:18,894 INFO run(26) IN Driver +2020-01-20 15:09:18,895 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-20 15:10:19,977 INFO run(26) IN Driver +2020-01-20 15:10:19,979 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:16:52,980 INFO run(26) IN Driver +2020-01-21 13:16:52,981 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:18:28,723 INFO run(26) IN Driver +2020-01-21 13:18:28,724 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:21:45,694 INFO run(26) IN Driver +2020-01-21 13:21:45,695 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:23:56,621 INFO run(26) IN Driver +2020-01-21 13:23:56,622 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:24:25,281 INFO run(26) IN Driver +2020-01-21 13:24:25,283 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:40:43,424 INFO run(26) IN Driver +2020-01-21 13:40:43,427 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:41:20,835 INFO run(26) IN Driver +2020-01-21 13:41:20,836 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:50:21,215 INFO run(26) IN Driver +2020-01-21 13:50:21,217 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'henrypump', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': 0, u'currentData': u'empty'} +2020-01-21 13:50:21,739 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:21.739073', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:50:26,876 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:26.876741', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:50:32,065 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:32.065283', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:50:37,202 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:37.201957', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:50:42,385 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:42.385094', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:50:47,523 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:47.523263', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:50:52,667 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:52.667452', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:50:57,811 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:50:57.811198', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:51:02,953 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:51:02.953156', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/henrypump/inventory/0 +2020-01-21 13:54:00,990 INFO run(26) IN Driver +2020-01-21 13:54:00,992 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'QEP', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'North', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': u'POE 1', u'currentData': u'empty'} +2020-01-21 13:54:01,514 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:54:01.514449', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:54:06,701 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:54:06.701727', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:54:11,840 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:54:11.840273', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:54:16,969 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:54:16.969216', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:54:22,110 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:54:22.109787', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:54:27,253 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:54:27.253244', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:54:32,392 INFO dataCollection(97) Publishing: {'pond 1 height': 12.0, 'timestamp': '2020-01-21T13:54:32.392205', 'pond 2 height': -17.29999542236328} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:57:56,108 INFO run(26) IN Driver +2020-01-21 13:57:56,109 INFO run(27) Got Config: +{u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'appname': u'hpiot', u'company': u'QEP', u'modbusData': u'empty', u'PLCData': {u'tag1': {u'name': u'current', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'volumeflow', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'North', u'deviceType': u'inventory', u'voltageData': u'empty', u'locationID': u'POE 1', u'currentData': u'empty'} +2020-01-21 13:57:56,742 INFO dataCollection(97) Publishing: {'current': 12.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:57:56.742390'} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:58:01,878 INFO dataCollection(97) Publishing: {'current': 12.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:58:01.878045'} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:58:07,014 INFO dataCollection(97) Publishing: {'current': 15.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:58:07.013781'} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:58:12,198 INFO dataCollection(97) Publishing: {'current': 15.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:58:12.198353'} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:58:17,338 INFO dataCollection(97) Publishing: {'current': 27.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:58:17.338821'} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:58:22,468 INFO dataCollection(97) Publishing: {'current': 27.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:58:22.468762'} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:58:27,608 INFO dataCollection(97) Publishing: {'current': 27.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:58:27.608766'} +To Topic: dt/hpiot/QEP/North/POE 1 +2020-01-21 13:58:32,749 INFO dataCollection(97) Publishing: {'current': 27.0, 'volumeflow': -17.29999542236328, 'timestamp': '2020-01-21T13:58:32.749239'} +To Topic: dt/hpiot/QEP/North/POE 1 diff --git a/Device/logs/test.log b/Device/logs/test.log new file mode 100644 index 0000000..fe32651 --- /dev/null +++ b/Device/logs/test.log @@ -0,0 +1,15 @@ +2020-01-21 13:30:40,848 INFO run(26) IN Driver +2020-01-21 13:30:40,849 INFO run(27) Got Config: +{u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'currentData': u'empty', u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'deviceType': u'inventory', u'locationID': 0, u'appname': u'hpiot', u'voltageData': u'empty', u'company': u'henrypump', u'modbusData': u'empty'} +2020-01-21 13:35:19,199 INFO run(26) IN Driver +2020-01-21 13:35:19,201 INFO run(27) Got Config: +{u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'deviceType': u'inventory', u'modbusData': u'empty', u'appname': u'hpiot', u'locationID': 0, u'company': u'henrypump', u'currentData': u'empty', u'voltageData': u'empty'} +2020-01-21 13:38:31,119 INFO run(26) IN Driver +2020-01-21 13:38:31,119 INFO run(26) IN Driver +2020-01-21 13:38:31,126 INFO run(27) Got Config: +{u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'deviceType': u'inventory', u'modbusData': u'empty', u'appname': u'hpiot', u'locationID': 0, u'company': u'henrypump', u'currentData': u'empty', u'voltageData': u'empty'} +2020-01-21 13:38:31,126 INFO run(27) Got Config: +{u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'deviceType': u'inventory', u'modbusData': u'empty', u'appname': u'hpiot', u'locationID': 0, u'company': u'henrypump', u'currentData': u'empty', u'voltageData': u'empty'} +2020-01-21 13:39:34,604 INFO run(26) IN Driver +2020-01-21 13:39:34,605 INFO run(27) Got Config: +{u'PLCData': {u'tag1': {u'name': u'pond 1 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond1Height', u'changeThreshold': 1}, u'tag2': {u'name': u'pond 2 height', u'plcType': u'Micro800', u'guaranteed': 3600, u'plcIP': u'192.168.1.12', u'tag': u'pond2Height', u'changeThreshold': 1}}, u'field': u'inventory', u'currentData': u'empty', u'certificateID': u'bfb15ea80f83b61a4ae3e5d43ed9519cb66380a8cfd2d784aaf9ace87bc275e4', u'deviceType': u'inventory', u'appname': u'hpiot', u'locationID': 0, u'company': u'henrypump', u'modbusData': u'empty', u'voltageData': u'empty'} diff --git a/Device/main.py b/Device/main.py new file mode 100644 index 0000000..5e2ad7e --- /dev/null +++ b/Device/main.py @@ -0,0 +1,127 @@ +from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient +import logging +import time +import argparse +import json +import os +from datetime import datetime +import urllib +import multiprocessing +import driver +import utilities +def main(): + + AllowedActions = ['both', 'publish', 'subscribe'] + + # Custom MQTT message callback + def customCallback(client, userdata, message): + print("Client: ") + print(client) + print("User Data: ") + print(userdata) + print("Received a new message: ") + print(message.payload) + print("from topic: ") + print(message.topic) + print("--------------\n\n") + + + # Read in command-line parameters + parser = argparse.ArgumentParser() + parser.add_argument("-e", "--endpoint", action="store", required=True, dest="host", help="Your AWS IoT custom endpoint") + parser.add_argument("-r", "--rootCA", action="store", required=True, dest="rootCAPath", help="Root CA file path") + parser.add_argument("-c", "--cert", action="store", dest="certificatePath", help="Certificate file path") + parser.add_argument("-k", "--key", action="store", dest="privateKeyPath", help="Private key file path") + parser.add_argument("-p", "--port", action="store", dest="port", type=int, help="Port number override") + parser.add_argument("-w", "--websocket", action="store_true", dest="useWebsocket", default=False, + help="Use MQTT over WebSocket") + parser.add_argument("-id", "--clientId", action="store", dest="clientId", default="basicPubSub", + help="Targeted client id") + parser.add_argument("-t", "--topic", action="store", dest="topic", default="dt/hpiot/", help="Targeted topic") + parser.add_argument("-m", "--mode", action="store", dest="mode", default="both", + help="Operation modes: %s"%str(AllowedActions)) + parser.add_argument("-M", "--message", action="store", dest="message", default="Hello World!", + help="Message to publish") + + args = parser.parse_args() + host = args.host + rootCAPath = args.rootCAPath + certificatePath = args.certificatePath + privateKeyPath = args.privateKeyPath + port = args.port + useWebsocket = args.useWebsocket + topic = args.topic + + def jitp_registration(): + #Attempt to connect to AWS IoT Core and start JITP for given certificate + myAWSIoTMQTTClient = None + myAWSIoTMQTTClient = AWSIoTMQTTClient(certificateID) + myAWSIoTMQTTClient.configureEndpoint(host, port) + myAWSIoTMQTTClient.configureCredentials(rootCAPath, './device1Cert.key', './device1CertAndCACert.pem') + while True: + try: + myAWSIoTMQTTClient.connect() + myAWSIoTMQTTClient.disconnect() + break + except Exception as e: + logger.info("Didn't connect trying again in 10 seconds: {}".format(e)) + time.sleep(10) + #Get the config that should be in the database after JITP concludes + return json.load(urllib.urlopen('https://4ax24ru9ra.execute-api.us-east-1.amazonaws.com/Gamma/HPIoTgetConfig/?certificateID={}'.format(certificateID))) + + # Configure logging + logger = logging.getLogger("AWSIoTPythonSDK.core") + logger.setLevel(logging.INFO) + streamHandler = logging.StreamHandler() + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + streamHandler.setFormatter(formatter) + logger.addHandler(streamHandler) + + #Checking for main device certificate or making it if absent + if not os.path.isfile('./device1Cert.pem'): + os.system('openssl genrsa -out device1Cert.key 2048') + os.system('openssl req -config server.conf -new -key device1Cert.key -out device1Cert.pem') + os.system('openssl x509 -req -in device1Cert.pem -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device1Cert.pem -days 365 -sha256') + + if not os.path.isfile('./device1CertAndCACert.pem'): + os.system('cat device1Cert.pem rootCA.pem > device1CertAndCACert.pem') + + + certificateID = os.popen('openssl x509 -in device1Cert.pem -outform der | sha256sum').read()[:-4] + + #Download the config from dynamodb with API call + logger.info("Attempting to download config file") + config = {} + try: + config = json.load(urllib.urlopen('https://4ax24ru9ra.execute-api.us-east-1.amazonaws.com/Gamma/HPIoTgetConfig/?certificateID={}'.format(certificateID))) + except Exception as e: + logger.error(e) + + #No config in database probably haven't been registered attempt to connect and start JITP + if 'certificateID' not in config.keys(): + config = jitp_registration() + + #config = utilities.unmarshal_dynamodb_json(config) + + + print(config) + #Get all the device names from the config + devices = [ele for ele in config.keys() if('device' in ele)] + + #Build a list of all processes, so that they can be terminated afterwards + all_processes = [] + for device in devices: + driver.run(config[device],device,port, host, rootCAPath) + ''' + process = multiprocessing.Process(target=driver.run, args=(config[device],device,port, host, rootCAPath), name="Process-{}".format(config[device]['locationID'])) + process.start() + all_processes.append(process) + logger.info(all_processes) + for process in all_processes: + if process.exitcode: + process.terminate() + ''' +if __name__ == '__main__': + main() + + diff --git a/Device/minimalmodbus.py b/Device/minimalmodbus.py new file mode 100644 index 0000000..0c89d8b --- /dev/null +++ b/Device/minimalmodbus.py @@ -0,0 +1,4028 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Jonas Berg +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""MinimalModbus: A Python driver for Modbus RTU/ASCII via serial port (via USB, RS485 or RS232).""" + +__author__ = "Jonas Berg" +__license__ = "Apache License, Version 2.0" +__status__ = "Production" +__url__ = "https://github.com/pyhys/minimalmodbus" +__version__ = "1.0.2" + + +import os +import struct +import sys +import time + +import serial + +if sys.version > "3": + import binascii + +# Allow long also in Python3 +# http://python3porting.com/noconv.html +if sys.version > "3": + long = int + +_NUMBER_OF_BYTES_BEFORE_REGISTERDATA = 1 # Within the payload +_NUMBER_OF_BYTES_PER_REGISTER = 2 +_MAX_NUMBER_OF_REGISTERS_TO_WRITE = 123 +_MAX_NUMBER_OF_REGISTERS_TO_READ = 125 +_MAX_NUMBER_OF_BITS_TO_WRITE = 1968 # 0x7B0 +_MAX_NUMBER_OF_BITS_TO_READ = 2000 # 0x7D0 +_MAX_NUMBER_OF_DECIMALS = 10 # Some instrument might store 0.00000154 Ampere as 154 etc +_MAX_BYTEORDER_VALUE = 3 +_SECONDS_TO_MILLISECONDS = 1000 +_BITS_PER_BYTE = 8 +_ASCII_HEADER = ":" +_ASCII_FOOTER = "\r\n" +_BYTEPOSITION_FOR_ASCII_HEADER = 0 # Relative to plain response +_BYTEPOSITION_FOR_SLAVEADDRESS = 0 # Relative to (stripped) response +_BYTEPOSITION_FOR_FUNCTIONCODE = 1 # Relative to (stripped) response +_BYTEPOSITION_FOR_SLAVE_ERROR_CODE = 2 # Relative to (stripped) response +_BITNUMBER_FUNCTIONCODE_ERRORINDICATION = 7 + +# Several instrument instances can share the same serialport +_serialports = {} # Key: port name (str), value: port instance +_latest_read_times = {} # Key: port name (str), value: timestamp (float) + +# ############### # +# Named constants # +# ############### # + +MODE_RTU = "rtu" +MODE_ASCII = "ascii" +BYTEORDER_BIG = 0 +BYTEORDER_LITTLE = 1 +BYTEORDER_BIG_SWAP = 2 +BYTEORDER_LITTLE_SWAP = 3 + +# Replace with enum when Python3 only +_PAYLOADFORMAT_BIT = "bit" +_PAYLOADFORMAT_BITS = "bits" +_PAYLOADFORMAT_FLOAT = "float" +_PAYLOADFORMAT_LONG = "long" +_PAYLOADFORMAT_REGISTER = "register" +_PAYLOADFORMAT_REGISTERS = "registers" +_PAYLOADFORMAT_STRING = "string" +_ALL_PAYLOADFORMATS = [ + _PAYLOADFORMAT_BIT, + _PAYLOADFORMAT_BITS, + _PAYLOADFORMAT_FLOAT, + _PAYLOADFORMAT_LONG, + _PAYLOADFORMAT_REGISTER, + _PAYLOADFORMAT_REGISTERS, + _PAYLOADFORMAT_STRING, +] + +# ######################## # +# Modbus instrument object # +# ######################## # + + +class Instrument: + """Instrument class for talking to instruments (slaves). + + Uses the Modbus RTU or ASCII protocols (via RS485 or RS232). + + Args: + * port (str): The serial port name, for example ``/dev/ttyUSB0`` (Linux), + ``/dev/tty.usbserial`` (OS X) or ``COM4`` (Windows). + * slaveaddress (int): Slave address in the range 1 to 247 (use decimal numbers, + not hex). Address 0 is for broadcast, and 248-255 are reserved. + * mode (str): Mode selection. Can be MODE_RTU or MODE_ASCII. + * close_port_after_each_call (bool): If the serial port should be closed after + each call to the instrument. + * debug (bool): Set this to :const:`True` to print the communication details + + """ + + def __init__( + self, + port, + slaveaddress, + mode=MODE_RTU, + close_port_after_each_call=False, + debug=False, + ): + """Initialize instrument and open corresponding serial port.""" + self.address = slaveaddress + """Slave address (int). Most often set by the constructor + (see the class documentation). """ + + self.mode = mode + """Slave mode (str), can be MODE_RTU or MODE_ASCII. + Most often set by the constructor (see the class documentation). + + Changing this will not affect how other instruments use the same serial port. + + New in version 0.6. + """ + + self.precalculate_read_size = True + """If this is :const:`False`, the serial port reads until timeout + instead of just reading a specific number of bytes. Defaults to :const:`True`. + + Changing this will not affect how other instruments use the same serial port. + + New in version 0.5. + """ + + self.debug = debug + """Set this to :const:`True` to print the communication details. + Defaults to :const:`False`. + + Most often set by the constructor (see the class documentation). + + Changing this will not affect how other instruments use the same serial port. + """ + + self.clear_buffers_before_each_transaction = True + """If this is :const:`True`, the serial port read and write buffers are + cleared before each request to the instrument, to avoid cumulative byte + sync errors across multiple messages. Defaults to :const:`True`. + + Changing this will not affect how other instruments use the same serial port. + + New in version 1.0. + """ + + self.close_port_after_each_call = close_port_after_each_call + """If this is :const:`True`, the serial port will be closed after each + call. Defaults to :const:`False`. + + Changing this will not affect how other instruments use the same serial port. + + Most often set by the constructor (see the class documentation). + """ + + self.handle_local_echo = False + """Set to to :const:`True` if your RS-485 adaptor has local echo enabled. + Then the transmitted message will immeadiately appear at the receive + line of the RS-485 adaptor. MinimalModbus will then read and discard + this data, before reading the data from the slave. + Defaults to :const:`False`. + + Changing this will not affect how other instruments use the same serial port. + + New in version 0.7. + """ + + self.serial = None + """The serial port object as defined by the pySerial module. Created by the constructor. + + Attributes that could be changed after initialisation: + + - port (str): Serial port name. + - Most often set by the constructor (see the class documentation). + - baudrate (int): Baudrate in Baud. + - Defaults to 19200. + - parity (probably int): Parity. See the pySerial module for documentation. + - Defaults to serial.PARITY_NONE. + - bytesize (int): Bytesize in bits. + - Defaults to 8. + - stopbits (int): The number of stopbits. + - Defaults to 1. + - timeout (float): Read timeout value in seconds. + - Defaults to 0.05 s. + - write_timeout (float): Write timeout value in seconds. + - Defaults to 2.0 s. + """ + + if port not in _serialports or not _serialports[port]: + self._print_debug("Create serial port {}".format(port)) + self.serial = _serialports[port] = serial.Serial( + port=port, + baudrate=19200, + parity=serial.PARITY_NONE, + bytesize=8, + stopbits=1, + timeout=0.05, + write_timeout=2.0, + ) + else: + self._print_debug("Serial port {} already exists".format(port)) + self.serial = _serialports[port] + if (self.serial.port is None) or (not self.serial.is_open): + self._print_debug("Serial port {} is closed. Opening.".format(port)) + self.serial.open() + + if self.close_port_after_each_call: + self._print_debug("Closing serial port {}".format(port)) + self.serial.close() + + def __repr__(self): + """Give string representation of the :class:`.Instrument` object.""" + template = ( + "{}.{}" + ) + return template.format( + self.__module__, + self.__class__.__name__, + id(self), + self.address, + self.mode, + self.close_port_after_each_call, + self.precalculate_read_size, + self.clear_buffers_before_each_transaction, + self.handle_local_echo, + self.debug, + self.serial, + ) + + def _print_debug(self, text): + if self.debug: + _print_out("MinimalModbus debug mode. " + text) + + # ################################# # + # Methods for talking to the slave # + # ################################# # + + def read_bit(self, registeraddress, functioncode=2): + """Read one bit from the slave (instrument). + + This is for a bit that has its individual address in the instrument. + + Args: + * registeraddress (int): The slave register address (use decimal numbers, not hex). + * functioncode (int): Modbus function code. Can be 1 or 2. + + Returns: + The bit value 0 or 1 (int). + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [1, 2]) + return self._generic_command( + functioncode, + registeraddress, + number_of_bits=1, + payloadformat=_PAYLOADFORMAT_BIT, + ) + + def write_bit(self, registeraddress, value, functioncode=5): + """Write one bit to the slave (instrument). + + This is for a bit that has its individual address in the instrument. + + Args: + * registeraddress (int): The slave register address (use decimal numbers, not hex). + * value (int or bool): 0 or 1, or True or False + * functioncode (int): Modbus function code. Can be 5 or 15. + + Returns: + None + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [5, 15]) + _check_int(value, minvalue=0, maxvalue=1, description="input value") + self._generic_command( + functioncode, + registeraddress, + value, + number_of_bits=1, + payloadformat=_PAYLOADFORMAT_BIT, + ) + + def read_bits(self, registeraddress, number_of_bits, functioncode=2): + """Read multiple bits from the slave (instrument). + + This is for bits that have individual addresses in the instrument. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * number_of_bits (int): Number of bits to read + * functioncode (int): Modbus function code. Can be 1 or 2. + + Returns: + A list of bit values 0 or 1 (int). The first value in the list is for + the bit at the given address. + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [1, 2]) + _check_int( + number_of_bits, + minvalue=1, + maxvalue=_MAX_NUMBER_OF_BITS_TO_READ, + description="number of bits", + ) + return self._generic_command( + functioncode, + registeraddress, + number_of_bits=number_of_bits, + payloadformat=_PAYLOADFORMAT_BITS, + ) + + def write_bits(self, registeraddress, values): + """Write multiple bits to the slave (instrument). + + This is for bits that have individual addresses in the instrument. + + Uses Modbus functioncode 15. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * values (list of int or bool): 0 or 1, or True or False. The first + value in the list is for the bit at the given address. + + Returns: + None + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + if not isinstance(values, list): + raise TypeError( + 'The "values parameter" must be a list. Given: {0!r}'.format(values) + ) + # Note: The content of the list is checked at content conversion. + _check_int( + len(values), + minvalue=1, + maxvalue=_MAX_NUMBER_OF_BITS_TO_WRITE, + description="length of input list", + ) + + self._generic_command( + 15, + registeraddress, + values, + number_of_bits=len(values), + payloadformat=_PAYLOADFORMAT_BITS, + ) + + def read_register( + self, registeraddress, number_of_decimals=0, functioncode=3, signed=False + ): + """Read an integer from one 16-bit register in the slave, possibly scaling it. + + The slave register can hold integer values in the range 0 to 65535 + ("Unsigned INT16"). + + Args: + * registeraddress (int): The slave register address (use decimal numbers, not hex). + * number_of_decimals (int): The number of decimals for content conversion. + * functioncode (int): Modbus function code. Can be 3 or 4. + * signed (bool): Whether the data should be interpreted as unsigned or signed. + + .. note:: The parameter number_of_decimals was named numberOfDecimals + before MinimalModbus 1.0 + + If a value of 77.0 is stored internally in the slave register as 770, + then use ``number_of_decimals=1`` which will divide the received data by 10 + before returning the value. + + Similarly ``number_of_decimals=2`` will divide the received data by 100 before + returning the value. + + Some manufacturers allow negative values for some registers. Instead of + an allowed integer range 0 to 65535, a range -32768 to 32767 is allowed. + This is implemented as any received value in the upper range (32768 to + 65535) is interpreted as negative value (in the range -32768 to -1). + + Use the parameter ``signed=True`` if reading from a register that can hold + negative values. Then upper range data will be automatically converted into + negative return values (two's complement). + + ============== ================== ================ =============== + ``signed`` Data type in slave Alternative name Range + ============== ================== ================ =============== + :const:`False` Unsigned INT16 Unsigned short 0 to 65535 + :const:`True` INT16 Short -32768 to 32767 + ============== ================== ================ =============== + + Returns: + The register data in numerical value (int or float). + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [3, 4]) + _check_int( + number_of_decimals, + minvalue=0, + maxvalue=_MAX_NUMBER_OF_DECIMALS, + description="number of decimals", + ) + _check_bool(signed, description="signed") + return self._generic_command( + functioncode, + registeraddress, + number_of_decimals=number_of_decimals, + number_of_registers=1, + signed=signed, + payloadformat=_PAYLOADFORMAT_REGISTER, + ) + + def write_register( + self, + registeraddress, + value, + number_of_decimals=0, + functioncode=16, + signed=False, + ): + """Write an integer to one 16-bit register in the slave, possibly scaling it. + + The slave register can hold integer values in the range 0 to + 65535 ("Unsigned INT16"). + + Args: + * registeraddress (int): The slave register address (use decimal + numbers, not hex). + * value (int or float): The value to store in the slave register (might be + scaled before sending). + * number_of_decimals (int): The number of decimals for content conversion. + * functioncode (int): Modbus function code. Can be 6 or 16. + * signed (bool): Whether the data should be interpreted as unsigned or signed. + + .. note:: The parameter number_of_decimals was named numberOfDecimals + before MinimalModbus 1.0 + + To store for example ``value=77.0``, use ``number_of_decimals=1`` if the slave register + will hold it as 770 internally. This will multiply ``value`` by 10 before sending it + to the slave register. + + Similarly ``number_of_decimals=2`` will multiply ``value`` by 100 before sending + it to the slave register. + + As the largest number that can be written to a register is 0xFFFF = 65535, + the ``value`` and ``number_of_decimals`` should max be 65535 when combined. + So when using ``number_of_decimals=3`` the maximum ``value`` is 65.535. + + For discussion on negative values, the range and on alternative names, + see :meth:`.read_register`. + + Use the parameter ``signed=True`` if writing to a register that can hold + negative values. Then negative input will be automatically converted into + upper range data (two's complement). + + Returns: + None + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [6, 16]) + _check_int( + number_of_decimals, + minvalue=0, + maxvalue=_MAX_NUMBER_OF_DECIMALS, + description="number of decimals", + ) + _check_bool(signed, description="signed") + _check_numerical(value, description="input value") + + self._generic_command( + functioncode, + registeraddress, + value, + number_of_decimals=number_of_decimals, + number_of_registers=1, + signed=signed, + payloadformat=_PAYLOADFORMAT_REGISTER, + ) + + def read_long( + self, registeraddress, functioncode=3, signed=False, byteorder=BYTEORDER_BIG + ): + """Read a long integer (32 bits) from the slave. + + Long integers (32 bits = 4 bytes) are stored in two consecutive 16-bit + registers in the slave. + + Args: + * registeraddress (int): The slave register start address (use decimal numbers, + not hex). + * functioncode (int): Modbus function code. Can be 3 or 4. + * signed (bool): Whether the data should be interpreted as unsigned or signed. + * byteorder (int): How multi-register data should be interpreted. + Defaults to BYTEORDER_BIG. + + ============== ================== ================ ========================== + ``signed`` Data type in slave Alternative name Range + ============== ================== ================ ========================== + :const:`False` Unsigned INT32 Unsigned long 0 to 4294967295 + :const:`True` INT32 Long -2147483648 to 2147483647 + ============== ================== ================ ========================== + + Returns: + The numerical value (int). + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [3, 4]) + _check_bool(signed, description="signed") + return self._generic_command( + functioncode, + registeraddress, + number_of_registers=2, + signed=signed, + byteorder=byteorder, + payloadformat=_PAYLOADFORMAT_LONG, + ) + + def write_long(self, registeraddress, value, signed=False, byteorder=BYTEORDER_BIG): + """Write a long integer (32 bits) to the slave. + + Long integers (32 bits = 4 bytes) are stored in two consecutive 16-bit + registers in the slave. + + Uses Modbus function code 16. + + For discussion on number of bits, number of registers, the range + and on alternative names, see :meth:`.read_long`. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * value (int or long): The value to store in the slave. + * signed (bool): Whether the data should be interpreted as unsigned or signed. + * byteorder (int): How multi-register data should be interpreted. + Defaults to BYTEORDER_BIG. + + Returns: + None + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + MAX_VALUE_LONG = 4294967295 # Unsigned INT32 + MIN_VALUE_LONG = -2147483648 # INT32 + + _check_int( + value, + minvalue=MIN_VALUE_LONG, + maxvalue=MAX_VALUE_LONG, + description="input value", + ) + _check_bool(signed, description="signed") + self._generic_command( + 16, + registeraddress, + value, + number_of_registers=2, + signed=signed, + byteorder=byteorder, + payloadformat=_PAYLOADFORMAT_LONG, + ) + + def read_float( + self, + registeraddress, + functioncode=3, + number_of_registers=2, + byteorder=BYTEORDER_BIG, + ): + r"""Read a floating point number from the slave. + + Floats are stored in two or more consecutive 16-bit registers in the slave. + The encoding is according to the standard IEEE 754. + + There are differences in the byte order used by different manufacturers. + A floating point value of 1.0 is encoded (in single precision) as 3f800000 + (hex). In this implementation the data will be sent as ``'\x3f\x80'`` + and ``'\x00\x00'`` to two consecutetive registers by default. Make sure to test that + it makes sense for your instrument. If not, change the ``byteorder`` argument. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * functioncode (int): Modbus function code. Can be 3 or 4. + * number_of_registers (int): The number of registers allocated for the float. + Can be 2 or 4. + * byteorder (int): How multi-register data should be interpreted. + Defaults to BYTEORDER_BIG. + + .. note:: The parameter number_of_registers was named numberOfRegisters + before MinimalModbus 1.0 + + ====================================== ================= =========== ================= + Type of floating point number in slave Size Registers Range + ====================================== ================= =========== ================= + Single precision (binary32) 32 bits (4 bytes) 2 registers 1.4E-45 to 3.4E38 + Double precision (binary64) 64 bits (8 bytes) 4 registers 5E-324 to 1.8E308 + ====================================== ================= =========== ================= + + Returns: + The numerical value (float). + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [3, 4]) + _check_int( + number_of_registers, + minvalue=2, + maxvalue=4, + description="number of registers", + ) + return self._generic_command( + functioncode, + registeraddress, + number_of_registers=number_of_registers, + byteorder=byteorder, + payloadformat=_PAYLOADFORMAT_FLOAT, + ) + + def write_float( + self, registeraddress, value, number_of_registers=2, byteorder=BYTEORDER_BIG + ): + """Write a floating point number to the slave. + + Floats are stored in two or more consecutive 16-bit registers in the slave. + + Uses Modbus function code 16. + + For discussion on precision, number of registers and on byte order, + see :meth:`.read_float`. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * value (float or int): The value to store in the slave + * number_of_registers (int): The number of registers allocated for the float. + Can be 2 or 4. + * byteorder (int): How multi-register data should be interpreted. + Defaults to BYTEORDER_BIG. + + .. note:: The parameter number_of_registers was named numberOfRegisters + before MinimalModbus 1.0 + + Returns: + None + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_numerical(value, description="input value") + _check_int( + number_of_registers, + minvalue=2, + maxvalue=4, + description="number of registers", + ) + self._generic_command( + 16, + registeraddress, + value, + number_of_registers=number_of_registers, + byteorder=byteorder, + payloadformat=_PAYLOADFORMAT_FLOAT, + ) + + def read_string(self, registeraddress, number_of_registers=16, functioncode=3): + """Read an ASCII string from the slave. + + Each 16-bit register in the slave are interpreted as two characters + (each 1 byte = 8 bits). For example 16 consecutive registers can hold 32 + characters (32 bytes). + + International characters (Unicode/UTF-8) are not supported. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * number_of_registers (int): The number of registers allocated for the string. + * functioncode (int): Modbus function code. Can be 3 or 4. + + .. note:: The parameter number_of_registers was named numberOfRegisters + before MinimalModbus 1.0 + + Returns: + The string (str). + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [3, 4]) + _check_int( + number_of_registers, + minvalue=1, + maxvalue=_MAX_NUMBER_OF_REGISTERS_TO_READ, + description="number of registers for read string", + ) + return self._generic_command( + functioncode, + registeraddress, + number_of_registers=number_of_registers, + payloadformat=_PAYLOADFORMAT_STRING, + ) + + def write_string(self, registeraddress, textstring, number_of_registers=16): + """Write an ASCII string to the slave. + + Each 16-bit register in the slave are interpreted as two characters + (each 1 byte = 8 bits). For example 16 consecutive registers can hold 32 + characters (32 bytes). + + Uses Modbus function code 16. + + International characters (Unicode/UTF-8) are not supported. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * textstring (str): The string to store in the slave, must be ASCII. + * number_of_registers (int): The number of registers allocated for the string. + + .. note:: The parameter number_of_registers was named numberOfRegisters + before MinimalModbus 1.0 + + If the ``textstring`` is longer than the ``2*number_of_registers``, an error is raised. + Shorter strings are padded with spaces. + + Returns: + None + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_int( + number_of_registers, + minvalue=1, + maxvalue=_MAX_NUMBER_OF_REGISTERS_TO_WRITE, + description="number of registers for write string", + ) + _check_string( + textstring, + "input string", + minlength=1, + maxlength=2 * number_of_registers, + force_ascii=True, + ) + self._generic_command( + 16, + registeraddress, + textstring, + number_of_registers=number_of_registers, + payloadformat=_PAYLOADFORMAT_STRING, + ) + + def read_registers(self, registeraddress, number_of_registers, functioncode=3): + """Read integers from 16-bit registers in the slave. + + The slave registers can hold integer values in the range 0 to + 65535 ("Unsigned INT16"). + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * number_of_registers (int): The number of registers to read, max 125 registers. + * functioncode (int): Modbus function code. Can be 3 or 4. + + .. note:: The parameter number_of_registers was named numberOfRegisters + before MinimalModbus 1.0 + + Any scaling of the register data, or converting it to negative number + (two's complement) must be done manually. + + Returns: + The register data (a list of int). The first value in the list is for + the register at the given address. + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + _check_functioncode(functioncode, [3, 4]) + _check_int( + number_of_registers, + minvalue=1, + maxvalue=_MAX_NUMBER_OF_REGISTERS_TO_READ, + description="number of registers", + ) + return self._generic_command( + functioncode, + registeraddress, + number_of_registers=number_of_registers, + payloadformat=_PAYLOADFORMAT_REGISTERS, + ) + + def write_registers(self, registeraddress, values): + """Write integers to 16-bit registers in the slave. + + The slave register can hold integer values in the range 0 to + 65535 ("Unsigned INT16"). + + Uses Modbus function code 16. + + The number of registers that will be written is defined by the length of + the ``values`` list. + + Args: + * registeraddress (int): The slave register start address (use decimal + numbers, not hex). + * values (list of int): The values to store in the slave registers, + max 123 values. The first value in the list is for the register + at the given address. + + .. note:: The parameter number_of_registers was named numberOfRegisters + before MinimalModbus 1.0 + + Any scaling of the register data, or converting it to negative number + (two's complement) must be done manually. + + Returns: + None + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + if not isinstance(values, list): + raise TypeError( + 'The "values parameter" must be a list. Given: {0!r}'.format(values) + ) + _check_int( + len(values), + minvalue=1, + maxvalue=_MAX_NUMBER_OF_REGISTERS_TO_WRITE, + description="length of input list", + ) + # Note: The content of the list is checked at content conversion. + + self._generic_command( + 16, + registeraddress, + values, + number_of_registers=len(values), + payloadformat=_PAYLOADFORMAT_REGISTERS, + ) + + # ############### # + # Generic command # + # ############### # + + def _generic_command( + self, + functioncode, + registeraddress, + value=None, + number_of_decimals=0, + number_of_registers=0, + number_of_bits=0, + signed=False, + byteorder=BYTEORDER_BIG, + payloadformat=None, + ): + """Perform generic command for reading and writing registers and bits. + + Args: + * functioncode (int): Modbus function code. + * registeraddress (int): The register address (use decimal numbers, not hex). + * value (numerical or string or None or list of int): The value to store + in the register. Depends on payloadformat. + * number_of_decimals (int): The number of decimals for content conversion. + Only for a single register. + * number_of_registers (int): The number of registers to read/write. + Only certain values allowed, depends on payloadformat. + * number_of_bits (int):T he number of registers to read/write. + * signed (bool): Whether the data should be interpreted as unsigned or + signed. Only for a single register or for payloadformat='long'. + * byteorder (int): How multi-register data should be interpreted. + * payloadformat (None or string): Any of the _PAYLOADFORMAT_* values + + If a value of 77.0 is stored internally in the slave register as 770, + then use ``number_of_decimals=1`` which will divide the received data + from the slave by 10 before returning the value. Similarly + ``number_of_decimals=2`` will divide the received data by 100 before returning + the value. Same functionality is also used when writing data to the slave. + + Returns: + The register data in numerical value (int or float), or the bit value 0 or + 1 (int), or ``None``. + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + """ + ALL_ALLOWED_FUNCTIONCODES = [1, 2, 3, 4, 5, 6, 15, 16] + ALLOWED_FUNCTIONCODES = {} + ALLOWED_FUNCTIONCODES[_PAYLOADFORMAT_BIT] = [1, 2, 5, 15] + ALLOWED_FUNCTIONCODES[_PAYLOADFORMAT_BITS] = [1, 2, 15] + ALLOWED_FUNCTIONCODES[_PAYLOADFORMAT_REGISTER] = [3, 4, 6, 16] + ALLOWED_FUNCTIONCODES[_PAYLOADFORMAT_FLOAT] = [3, 4, 16] + ALLOWED_FUNCTIONCODES[_PAYLOADFORMAT_STRING] = [3, 4, 16] + ALLOWED_FUNCTIONCODES[_PAYLOADFORMAT_LONG] = [3, 4, 16] + ALLOWED_FUNCTIONCODES[_PAYLOADFORMAT_REGISTERS] = [3, 4, 16] + + # Check input values + _check_functioncode(functioncode, ALL_ALLOWED_FUNCTIONCODES) + _check_registeraddress(registeraddress) + _check_int( + number_of_decimals, + minvalue=0, + maxvalue=_MAX_NUMBER_OF_DECIMALS, + description="number of decimals", + ) + _check_int( + number_of_registers, + minvalue=0, + maxvalue=max( + _MAX_NUMBER_OF_REGISTERS_TO_READ, _MAX_NUMBER_OF_REGISTERS_TO_WRITE + ), + description="number of registers", + ) + _check_int( + number_of_bits, + minvalue=0, + maxvalue=max(_MAX_NUMBER_OF_BITS_TO_READ, _MAX_NUMBER_OF_BITS_TO_WRITE), + description="number of bits", + ) + _check_bool(signed, description="signed") + _check_int( + byteorder, + minvalue=0, + maxvalue=_MAX_BYTEORDER_VALUE, + description="byteorder", + ) + + if payloadformat not in _ALL_PAYLOADFORMATS: + if not isinstance(payloadformat, str): + raise TypeError( + "The payload format should be a string. Given: {!r}".format( + payloadformat + ) + ) + raise ValueError( + "Wrong payload format variable. Given: {!r}".format(payloadformat) + ) + + number_of_register_bytes = number_of_registers * _NUMBER_OF_BYTES_PER_REGISTER + + # Check combinations: Payload format and functioncode + if functioncode not in ALLOWED_FUNCTIONCODES[payloadformat]: + raise ValueError( + "Wrong functioncode for payloadformat " + + "{!r}. Given: {!r}.".format(payloadformat, functioncode) + ) + + # Check combinations: signed + if signed: + if payloadformat not in [_PAYLOADFORMAT_REGISTER, _PAYLOADFORMAT_LONG]: + raise ValueError( + 'The "signed" parameter can not be used for this payload format. ' + + "Given format: {!r}.".format(payloadformat) + ) + + # Check combinations: number_of_decimals + if number_of_decimals > 0: + if payloadformat != _PAYLOADFORMAT_REGISTER: + raise ValueError( + 'The "number_of_decimals" parameter can not be used for this payload format. ' + + "Given format: {0!r}.".format(payloadformat) + ) + + # Check combinations: byteorder + if byteorder: + if payloadformat not in [_PAYLOADFORMAT_FLOAT, _PAYLOADFORMAT_LONG]: + raise ValueError( + 'The "byteorder" parameter can not be used for this payload format. ' + + "Given format: {0!r}.".format(payloadformat) + ) + + # Check combinations: number of bits + if payloadformat == _PAYLOADFORMAT_BIT: + if number_of_bits != 1: + raise ValueError( + "For BIT payload format the number of bits should be 1. " + + "Given: {0!r}.".format(number_of_bits) + ) + elif payloadformat == _PAYLOADFORMAT_BITS: + if number_of_bits < 1: + raise ValueError( + "For BITS payload format the number of bits should be at least 1. " + + "Given: {0!r}.".format(number_of_bits) + ) + elif number_of_bits: + raise ValueError( + "The number_of_bits parameter is wrong for payload format " + + "{0!r}. Given: {0!r}.".format(payloadformat, number_of_bits) + ) + + # Check combinations: Number of registers + if functioncode in [1, 2, 5, 15] and number_of_registers: + raise ValueError( + "The number_of_registers is not valid for this function code. " + + "number_of_registers: {0!r}, functioncode {1}.".format( + number_of_registers, functioncode + ) + ) + elif functioncode in [3, 4, 16] and not number_of_registers: + raise ValueError( + "The number_of_registers must be > 0 for functioncode " + + "{}.".format(functioncode) + ) + elif functioncode == 6 and number_of_registers != 1: + raise ValueError( + "The number_of_registers must be 1 for functioncode 6. " + + "Given: {}.".format(number_of_registers) + ) + if ( + functioncode == 16 + and payloadformat == _PAYLOADFORMAT_REGISTER + and number_of_registers != 1 + ): + raise ValueError( + "Wrong number_of_registers when writing to a " + + "single register. Given {0!r}.".format(number_of_registers) + ) + # Note: For function code 16 there is checking also in the content + # conversion functions. + + # Check combinations: Value + if functioncode in [5, 6, 15, 16] and value is None: + raise ValueError( + "The input value must be given for this function code. " + + "Given {0!r} and {1}.".format(value, functioncode) + ) + elif functioncode in [1, 2, 3, 4] and value is not None: + raise ValueError( + "The input value should not be given for this function code. " + + "Given {0!r} and {1}.".format(value, functioncode) + ) + + # Check combinations: Value for numerical + if functioncode == 16 and payloadformat in [ + _PAYLOADFORMAT_REGISTER, + _PAYLOADFORMAT_FLOAT, + _PAYLOADFORMAT_LONG, + ]: + _check_numerical(value, description="input value") + if functioncode == 6 and payloadformat == _PAYLOADFORMAT_REGISTER: + _check_numerical(value, description="input value") + + # Check combinations: Value for string + if functioncode == 16 and payloadformat == _PAYLOADFORMAT_STRING: + _check_string( + value, "input string", minlength=1, maxlength=number_of_register_bytes + ) + # Note: The string might be padded later, so the length might be shorter + # than number_of_register_bytes. + + # Check combinations: Value for registers + if functioncode == 16 and payloadformat == _PAYLOADFORMAT_REGISTERS: + if not isinstance(value, list): + raise TypeError( + "The value parameter for payloadformat REGISTERS must be a list. " + + "Given {0!r}.".format(value) + ) + + if len(value) != number_of_registers: + raise ValueError( + "The list length does not match number of registers. " + + "List: {0!r}, Number of registers: {1!r}.".format( + value, number_of_registers + ) + ) + + # Check combinations: Value for bit + if functioncode in [5, 15] and payloadformat == _PAYLOADFORMAT_BIT: + _check_int( + value, + minvalue=0, + maxvalue=1, + description="input value for payload format BIT", + ) + + # Check combinations: Value for bits + if functioncode == 15 and payloadformat == _PAYLOADFORMAT_BITS: + if not isinstance(value, list): + raise TypeError( + "The value parameter for payloadformat BITS must be a list. " + + "Given {0!r}.".format(value) + ) + + if len(value) != number_of_bits: + raise ValueError( + "The list length does not match number of bits. " + + "List: {0!r}, Number of registers: {1!r}.".format( + value, number_of_registers + ) + ) + + # Create payload + payload_to_slave = _create_payload( + functioncode, + registeraddress, + value, + number_of_decimals, + number_of_registers, + number_of_bits, + signed, + byteorder, + payloadformat, + ) + + # Communicate with instrument + payload_from_slave = self._perform_command(functioncode, payload_to_slave) + + # Parse response payload + return _parse_payload( + payload_from_slave, + functioncode, + registeraddress, + value, + number_of_decimals, + number_of_registers, + number_of_bits, + signed, + byteorder, + payloadformat, + ) + + # #################################### # + # Communication implementation details # + # #################################### # + + def _perform_command(self, functioncode, payload_to_slave): + """Perform the command having the *functioncode*. + + Args: + * functioncode (int): The function code for the command to be performed. + Can for example be 'Write register' = 16. + * payload_to_slave (str): Data to be transmitted to the slave (will be + embedded in slaveaddress, CRC etc) + + Returns: + The extracted data payload from the slave (a string). It has been + stripped of CRC etc. + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + Makes use of the :meth:`_communicate` method. The request is generated + with the :func:`_embed_payload` function, and the parsing of the + response is done with the :func:`_extract_payload` function. + + """ + DEFAULT_NUMBER_OF_BYTES_TO_READ = 1000 + + _check_functioncode(functioncode, None) + _check_string(payload_to_slave, description="payload") + + # Build request + request = _embed_payload( + self.address, self.mode, functioncode, payload_to_slave + ) + + # Calculate number of bytes to read + number_of_bytes_to_read = DEFAULT_NUMBER_OF_BYTES_TO_READ + if self.precalculate_read_size: + try: + number_of_bytes_to_read = _predict_response_size( + self.mode, functioncode, payload_to_slave + ) + except Exception: + if self.debug: + template = ( + "Could not precalculate response size for Modbus {} mode. " + + "Will read {} bytes. Request: {!r}" + ) + self._print_debug( + template.format(self.mode, number_of_bytes_to_read, request) + ) + + # Communicate + response = self._communicate(request, number_of_bytes_to_read) + + # Extract payload + payload_from_slave = _extract_payload( + response, self.address, self.mode, functioncode + ) + return payload_from_slave + + def _communicate(self, request, number_of_bytes_to_read): + """Talk to the slave via a serial port. + + Args: + request (str): The raw request that is to be sent to the slave. + number_of_bytes_to_read (int): number of bytes to read + + Returns: + The raw data (string) returned from the slave. + + Raises: + TypeError, ValueError, ModbusException, + serial.SerialException (inherited from IOError) + + Note that the answer might have strange ASCII control signs, which + makes it difficult to print it in the promt (messes up a bit). + Use repr() to make the string printable (shows ASCII values for control signs.) + + Will block until reaching *number_of_bytes_to_read* or timeout. + + If the attribute :attr:`Instrument.debug` is :const:`True`, the communication + details are printed. + + If the attribute :attr:`Instrument.close_port_after_each_call` is :const:`True` the + serial port is closed after each call. + + Timing:: + + Request from master (Master is writing) + | + | Response from slave (Master is reading) + | | + --------R-------W-----------------------------R-------W----------------------------- + | | | + | |<------- Roundtrip time ------>| + | | + -->|-----|<----- Silent period + + The resolution for Python's time.time() is lower on Windows than on Linux. + It is about 16 ms on Windows according to + https://stackoverflow.com/questions/157359/accurate-timestamping-in-python-logging + + For Python3, the information sent to and from pySerial should be of the type bytes. + This is taken care of automatically by MinimalModbus. + + """ + _check_string(request, minlength=1, description="request") + _check_int(number_of_bytes_to_read) + + self._print_debug( + "Will write to instrument (expecting {} bytes back): {!r} ({})".format( + number_of_bytes_to_read, request, _hexlify(request) + ) + ) + + if not self.serial.is_open: + self._print_debug("Opening port {}".format(self.serial.port)) + self.serial.open() + + if self.clear_buffers_before_each_transaction: + self._print_debug( + "Clearing serial buffers for port {}".format(self.serial.port) + ) + self.serial.reset_input_buffer() + self.serial.reset_output_buffer() + + if sys.version_info[0] > 2: + request = bytes( + request, encoding="latin1" + ) # Convert types to make it Python3 compatible + + # Sleep to make sure 3.5 character times have passed + minimum_silent_period = _calculate_minimum_silent_period(self.serial.baudrate) + time_since_read = _now() - _latest_read_times.get(self.serial.port, 0) + + if time_since_read < minimum_silent_period: + sleep_time = minimum_silent_period - time_since_read + + if self.debug: + template = ( + "Sleeping {:.2f} ms before sending. " + + "Minimum silent period: {:.2f} ms, time since read: {:.2f} ms." + ) + text = template.format( + sleep_time * _SECONDS_TO_MILLISECONDS, + minimum_silent_period * _SECONDS_TO_MILLISECONDS, + time_since_read * _SECONDS_TO_MILLISECONDS, + ) + self._print_debug(text) + + time.sleep(sleep_time) + + elif self.debug: + template = ( + "No sleep required before write. " + + "Time since previous read: {:.2f} ms, minimum silent period: {:.2f} ms." + ) + text = template.format( + time_since_read * _SECONDS_TO_MILLISECONDS, + minimum_silent_period * _SECONDS_TO_MILLISECONDS, + ) + self._print_debug(text) + + # Write request + latest_write_time = _now() + self.serial.write(request) + + # Read and discard local echo + if self.handle_local_echo: + local_echo_to_discard = self.serial.read(len(request)) + if self.debug: + template = "Discarding this local echo: {!r} ({} bytes)." + text = template.format( + local_echo_to_discard, len(local_echo_to_discard) + ) + self._print_debug(text) + if local_echo_to_discard != request: + template = ( + "Local echo handling is enabled, but the local echo does " + + "not match the sent request. " + + "Request: {!r} ({} bytes), local echo: {!r} ({} bytes)." + ) + text = template.format( + request, + len(request), + local_echo_to_discard, + len(local_echo_to_discard), + ) + raise LocalEchoError(text) + + # Read response + answer = self.serial.read(number_of_bytes_to_read) + _latest_read_times[self.serial.port] = _now() + + if self.close_port_after_each_call: + self._print_debug("Closing port {}".format(self.serial.port)) + self.serial.close() + + if sys.version_info[0] > 2: + # Convert types to make it Python3 compatible + answer = str(answer, encoding="latin1") + + if self.debug: + template = ( + "Response from instrument: {!r} ({}) ({} bytes), " + + "roundtrip time: {:.1f} ms. Timeout for reading: {:.1f} ms.\n" + ) + text = template.format( + answer, + _hexlify(answer), + len(answer), + (_latest_read_times.get(self.serial.port, 0) - latest_write_time) + * _SECONDS_TO_MILLISECONDS, + self.serial.timeout * _SECONDS_TO_MILLISECONDS, + ) + self._print_debug(text) + + if not answer: + raise NoResponseError("No communication with the instrument (no answer)") + + return answer + + # For backward compatibility + _performCommand = _perform_command + + +# ########## # +# Exceptions # +# ########## # + + +class ModbusException(IOError): + """Base class for Modbus communication exceptions. + + Inherits from IOError, which is an alias for OSError in Python3. + """ + + +class SlaveReportedException(ModbusException): + """Base class for exceptions that the slave (instrument) reports.""" + + +class SlaveDeviceBusyError(SlaveReportedException): + """The slave is busy processing some command.""" + + +class NegativeAcknowledgeError(SlaveReportedException): + """The slave can not fulfil the programming request. + + This typically happens when using function code 13 or 14 decimal. + """ + + +class IllegalRequestError(SlaveReportedException): + """The slave has received an illegal request.""" + + +class MasterReportedException(ModbusException): + """Base class for exceptions that the master (computer) detects.""" + + +class NoResponseError(MasterReportedException): + """No response from the slave.""" + + +class LocalEchoError(MasterReportedException): + """There is some problem with the local echo.""" + + +class InvalidResponseError(MasterReportedException): + """The response does not fulfill the Modbus standad, for example wrong checksum.""" + + +# ################ # +# Payload handling # +# ################ # + + +def _create_payload( + functioncode, + registeraddress, + value, + number_of_decimals, + number_of_registers, + number_of_bits, + signed, + byteorder, + payloadformat, +): + """Create the payload. + + Error checking should have been done before calling this function. + + For argument descriptions, see the _generic_command() method. + + """ + if functioncode in [1, 2]: + return _num_to_twobyte_string(registeraddress) + _num_to_twobyte_string( + number_of_bits + ) + if functioncode in [3, 4]: + return _num_to_twobyte_string(registeraddress) + _num_to_twobyte_string( + number_of_registers + ) + if functioncode == 5: + return _num_to_twobyte_string(registeraddress) + _bit_to_bytestring(value) + if functioncode == 6: + return _num_to_twobyte_string(registeraddress) + _num_to_twobyte_string( + value, number_of_decimals, signed=signed + ) + if functioncode == 15: + if payloadformat == _PAYLOADFORMAT_BIT: + bitlist = [value] + else: + bitlist = value + return ( + _num_to_twobyte_string(registeraddress) + + _num_to_twobyte_string(number_of_bits) + + _num_to_onebyte_string( + _calculate_number_of_bytes_for_bits(number_of_bits) + ) + + _bits_to_bytestring(bitlist) + ) + if functioncode == 16: + if payloadformat == _PAYLOADFORMAT_REGISTER: + registerdata = _num_to_twobyte_string( + value, number_of_decimals, signed=signed + ) + elif payloadformat == _PAYLOADFORMAT_STRING: + registerdata = _textstring_to_bytestring(value, number_of_registers) + elif payloadformat == _PAYLOADFORMAT_LONG: + registerdata = _long_to_bytestring( + value, signed, number_of_registers, byteorder + ) + elif payloadformat == _PAYLOADFORMAT_FLOAT: + registerdata = _float_to_bytestring(value, number_of_registers, byteorder) + elif payloadformat == _PAYLOADFORMAT_REGISTERS: + registerdata = _valuelist_to_bytestring(value, number_of_registers) + + assert len(registerdata) == number_of_registers * _NUMBER_OF_BYTES_PER_REGISTER + + return ( + _num_to_twobyte_string(registeraddress) + + _num_to_twobyte_string(number_of_registers) + + _num_to_onebyte_string(len(registerdata)) + + registerdata + ) + raise ValueError("Wrong function code: " + str(functioncode)) + + +def _parse_payload( + payload, + functioncode, + registeraddress, + value, + number_of_decimals, + number_of_registers, + number_of_bits, + signed, + byteorder, + payloadformat, +): + _check_response_payload( + payload, + functioncode, + registeraddress, + value, + number_of_decimals, + number_of_registers, + number_of_bits, + signed, + byteorder, + payloadformat, + ) + + if functioncode in [1, 2]: + registerdata = payload[_NUMBER_OF_BYTES_BEFORE_REGISTERDATA:] + if payloadformat == _PAYLOADFORMAT_BIT: + return _bytestring_to_bits(registerdata, number_of_bits)[0] + elif payloadformat == _PAYLOADFORMAT_BITS: + return _bytestring_to_bits(registerdata, number_of_bits) + + if functioncode in [3, 4]: + registerdata = payload[_NUMBER_OF_BYTES_BEFORE_REGISTERDATA:] + if payloadformat == _PAYLOADFORMAT_STRING: + return _bytestring_to_textstring(registerdata, number_of_registers) + + elif payloadformat == _PAYLOADFORMAT_LONG: + return _bytestring_to_long( + registerdata, signed, number_of_registers, byteorder + ) + + elif payloadformat == _PAYLOADFORMAT_FLOAT: + return _bytestring_to_float(registerdata, number_of_registers, byteorder) + + elif payloadformat == _PAYLOADFORMAT_REGISTERS: + return _bytestring_to_valuelist(registerdata, number_of_registers) + + elif payloadformat == _PAYLOADFORMAT_REGISTER: + return _twobyte_string_to_num( + registerdata, number_of_decimals, signed=signed + ) + + +def _embed_payload(slaveaddress, mode, functioncode, payloaddata): + """Build a request from the slaveaddress, the function code and the payload data. + + Args: + * slaveaddress (int): The address of the slave. + * mode (str): The modbus protcol mode (MODE_RTU or MODE_ASCII) + * functioncode (int): The function code for the command to be performed. + Can for example be 16 (Write register). + * payloaddata (str): The byte string to be sent to the slave. + + Returns: + The built (raw) request string for sending to the slave (including CRC etc). + + Raises: + ValueError, TypeError. + + The resulting request has the format: + * RTU Mode: slaveaddress byte + functioncode byte + payloaddata + CRC (which is two bytes). + * ASCII Mode: header (:) + slaveaddress (2 characters) + functioncode + (2 characters) + payloaddata + LRC (which is two characters) + footer (CRLF) + + The LRC or CRC is calculated from the byte string made up of slaveaddress + + functioncode + payloaddata. + The header, LRC/CRC, and footer are excluded from the calculation. + + """ + _check_slaveaddress(slaveaddress) + _check_mode(mode) + _check_functioncode(functioncode, None) + _check_string(payloaddata, description="payload") + + first_part = ( + _num_to_onebyte_string(slaveaddress) + + _num_to_onebyte_string(functioncode) + + payloaddata + ) + + if mode == MODE_ASCII: + request = ( + _ASCII_HEADER + + _hexencode(first_part) + + _hexencode(_calculate_lrc_string(first_part)) + + _ASCII_FOOTER + ) + else: + request = first_part + _calculate_crc_string(first_part) + + return request + + +def _extract_payload(response, slaveaddress, mode, functioncode): + """Extract the payload data part from the slave's response. + + Args: + * response (str): The raw response byte string from the slave. + This is different for RTU and ASCII. + * slaveaddress (int): The adress of the slave. Used here for error checking only. + * mode (str): The modbus protcol mode (MODE_RTU or MODE_ASCII) + * functioncode (int): Used here for error checking only. + + Returns: + The payload part of the *response* string. Conversion from Modbus ASCII + has been done if applicable. + + Raises: + ValueError, TypeError, ModbusException (or subclasses). + + Raises an exception if there is any problem with the received address, + the functioncode or the CRC. + + The received response should have the format: + + * RTU Mode: slaveaddress byte + functioncode byte + payloaddata + CRC (which is two bytes) + * ASCII Mode: header (:) + slaveaddress byte + functioncode byte + + payloaddata + LRC (which is two characters) + footer (CRLF) + + For development purposes, this function can also be used to extract the payload + from the request sent TO the slave. + + """ + # Number of bytes before the response payload (in stripped response) + NUMBER_OF_RESPONSE_STARTBYTES = 2 + + NUMBER_OF_CRC_BYTES = 2 + NUMBER_OF_LRC_BYTES = 1 + MINIMAL_RESPONSE_LENGTH_RTU = NUMBER_OF_RESPONSE_STARTBYTES + NUMBER_OF_CRC_BYTES + MINIMAL_RESPONSE_LENGTH_ASCII = 9 + + # Argument validity testing (ValueError/TypeError at lib programming error) + _check_string(response, description="response") + _check_slaveaddress(slaveaddress) + _check_mode(mode) + _check_functioncode(functioncode, None) + + plainresponse = response + + # Validate response length + if mode == MODE_ASCII: + if len(response) < MINIMAL_RESPONSE_LENGTH_ASCII: + raise InvalidResponseError( + "Too short Modbus ASCII response (minimum length {} bytes). Response: {!r}".format( + MINIMAL_RESPONSE_LENGTH_ASCII, response + ) + ) + elif len(response) < MINIMAL_RESPONSE_LENGTH_RTU: + raise InvalidResponseError( + "Too short Modbus RTU response (minimum length {} bytes). Response: {!r}".format( + MINIMAL_RESPONSE_LENGTH_RTU, response + ) + ) + + if mode == MODE_ASCII: + + # Validate the ASCII header and footer. + if response[_BYTEPOSITION_FOR_ASCII_HEADER] != _ASCII_HEADER: + raise InvalidResponseError( + "Did not find header " + + "({!r}) as start of ASCII response. The plain response is: {!r}".format( + _ASCII_HEADER, response + ) + ) + elif response[-len(_ASCII_FOOTER) :] != _ASCII_FOOTER: + raise InvalidResponseError( + "Did not find footer " + + "({!r}) as end of ASCII response. The plain response is: {!r}".format( + _ASCII_FOOTER, response + ) + ) + + # Strip ASCII header and footer + response = response[1:-2] + + if len(response) % 2 != 0: + template = ( + "Stripped ASCII frames should have an even number of bytes, but is {} bytes. " + + "The stripped response is: {!r} (plain response: {!r})" + ) + raise InvalidResponseError( + template.format(len(response), response, plainresponse) + ) + + # Convert the ASCII (stripped) response string to RTU-like response string + response = _hexdecode(response) + + # Validate response checksum + if mode == MODE_ASCII: + calculate_checksum = _calculate_lrc_string + number_of_checksum_bytes = NUMBER_OF_LRC_BYTES + else: + calculate_checksum = _calculate_crc_string + number_of_checksum_bytes = NUMBER_OF_CRC_BYTES + + received_checksum = response[-number_of_checksum_bytes:] + response_without_checksum = response[0 : (len(response) - number_of_checksum_bytes)] + calculated_checksum = calculate_checksum(response_without_checksum) + + if received_checksum != calculated_checksum: + template = ( + "Checksum error in {} mode: {!r} instead of {!r} . The response " + + "is: {!r} (plain response: {!r})" + ) + text = template.format( + mode, received_checksum, calculated_checksum, response, plainresponse + ) + raise InvalidResponseError(text) + + # Check slave address + responseaddress = ord(response[_BYTEPOSITION_FOR_SLAVEADDRESS]) + + if responseaddress != slaveaddress: + raise InvalidResponseError( + "Wrong return slave address: {} instead of {}. The response is: {!r}".format( + responseaddress, slaveaddress, response + ) + ) + + # Check if slave indicates error + _check_response_slaveerrorcode(response) + + # Check function code + received_functioncode = ord(response[_BYTEPOSITION_FOR_FUNCTIONCODE]) + if received_functioncode != functioncode: + raise InvalidResponseError( + "Wrong functioncode: {} instead of {}. The response is: {!r}".format( + received_functioncode, functioncode, response + ) + ) + + # Read data payload + first_databyte_number = NUMBER_OF_RESPONSE_STARTBYTES + + if mode == MODE_ASCII: + last_databyte_number = len(response) - NUMBER_OF_LRC_BYTES + else: + last_databyte_number = len(response) - NUMBER_OF_CRC_BYTES + + payload = response[first_databyte_number:last_databyte_number] + return payload + + +# ###################################### # +# Serial communication utility functions # +# ###################################### # + + +def _predict_response_size(mode, functioncode, payload_to_slave): + """Calculate the number of bytes that should be received from the slave. + + Args: + * mode (str): The modbus protcol mode (MODE_RTU or MODE_ASCII) + * functioncode (int): Modbus function code. + * payload_to_slave (str): The raw request that is to be sent to the slave + (not hex encoded string) + + Returns: + The preducted number of bytes (int) in the response. + + Raises: + ValueError, TypeError. + + """ + MIN_PAYLOAD_LENGTH = 4 # For implemented functioncodes here + BYTERANGE_FOR_GIVEN_SIZE = slice(2, 4) # Within the payload + + NUMBER_OF_PAYLOAD_BYTES_IN_WRITE_CONFIRMATION = 4 + NUMBER_OF_PAYLOAD_BYTES_FOR_BYTECOUNTFIELD = 1 + + RTU_TO_ASCII_PAYLOAD_FACTOR = 2 + + NUMBER_OF_RTU_RESPONSE_STARTBYTES = 2 + NUMBER_OF_RTU_RESPONSE_ENDBYTES = 2 + NUMBER_OF_ASCII_RESPONSE_STARTBYTES = 5 + NUMBER_OF_ASCII_RESPONSE_ENDBYTES = 4 + + # Argument validity testing + _check_mode(mode) + _check_functioncode(functioncode, None) + _check_string(payload_to_slave, description="payload", minlength=MIN_PAYLOAD_LENGTH) + + # Calculate payload size + if functioncode in [5, 6, 15, 16]: + response_payload_size = NUMBER_OF_PAYLOAD_BYTES_IN_WRITE_CONFIRMATION + + elif functioncode in [1, 2, 3, 4]: + given_size = _twobyte_string_to_num(payload_to_slave[BYTERANGE_FOR_GIVEN_SIZE]) + if functioncode in [1, 2]: + # Algorithm from MODBUS APPLICATION PROTOCOL SPECIFICATION V1.1b + number_of_inputs = given_size + response_payload_size = ( + NUMBER_OF_PAYLOAD_BYTES_FOR_BYTECOUNTFIELD + + number_of_inputs // 8 + + (1 if number_of_inputs % 8 else 0) + ) + + elif functioncode in [3, 4]: + number_of_registers = given_size + response_payload_size = ( + NUMBER_OF_PAYLOAD_BYTES_FOR_BYTECOUNTFIELD + + number_of_registers * _NUMBER_OF_BYTES_PER_REGISTER + ) + + else: + raise ValueError( + "Wrong functioncode: {}. The payload is: {!r}".format( + functioncode, payload_to_slave + ) + ) + + # Calculate number of bytes to read + if mode == MODE_ASCII: + return ( + NUMBER_OF_ASCII_RESPONSE_STARTBYTES + + response_payload_size * RTU_TO_ASCII_PAYLOAD_FACTOR + + NUMBER_OF_ASCII_RESPONSE_ENDBYTES + ) + else: + return ( + NUMBER_OF_RTU_RESPONSE_STARTBYTES + + response_payload_size + + NUMBER_OF_RTU_RESPONSE_ENDBYTES + ) + + +def _calculate_minimum_silent_period(baudrate): + """Calculate the silent period length between messages. + + It should correspond to the time to send 3.5 characters. + + Args: + baudrate (numerical): The baudrate for the serial port + + Returns: + The number of seconds (float) that should pass between each message on the bus. + + Raises: + ValueError, TypeError. + + """ + # Avoid division by zero + _check_numerical(baudrate, minvalue=1, description="baudrate") + + BITTIMES_PER_CHARACTERTIME = 11 + MINIMUM_SILENT_CHARACTERTIMES = 3.5 + MINIMUM_SILENT_TIME_SECONDS = 0.00175 # See Modbus standard + + bittime = 1 / float(baudrate) + return max( + bittime * BITTIMES_PER_CHARACTERTIME * MINIMUM_SILENT_CHARACTERTIMES, + MINIMUM_SILENT_TIME_SECONDS, + ) + + +# ########################## # +# String and num conversions # +# ########################## # + + +def _num_to_onebyte_string(inputvalue): + """Convert a numerical value to a one-byte string. + + Args: + inputvalue (int): The value to be converted. Should be >=0 and <=255. + + Returns: + A one-byte string created by chr(inputvalue). + + Raises: + TypeError, ValueError + + """ + _check_int(inputvalue, minvalue=0, maxvalue=0xFF) + + return chr(inputvalue) + + +def _num_to_twobyte_string(value, number_of_decimals=0, lsb_first=False, signed=False): + r"""Convert a numerical value to a two-byte string, possibly scaling it. + + Args: + * value (float or int): The numerical value to be converted. + * number_of_decimals (int): Number of decimals, 0 or more, for scaling. + * lsb_first (bool): Whether the least significant byte should be first in + the resulting string. + * signed (bool): Whether negative values should be accepted. + + Returns: + A two-byte string. + + Raises: + TypeError, ValueError. Gives DeprecationWarning instead of ValueError + for some values in Python 2.6. + + Use ``number_of_decimals=1`` to multiply ``value`` by 10 before sending it to + the slave register. Similarly ``number_of_decimals=2`` will multiply ``value`` + by 100 before sending it to the slave register. + + Use the parameter ``signed=True`` if making a bytestring that can hold + negative values. Then negative input will be automatically converted into + upper range data (two's complement). + + The byte order is controlled by the ``lsb_first`` parameter, as seen here: + + ======================= ============= ==================================== + ``lsb_first`` parameter Endianness Description + ======================= ============= ==================================== + False (default) Big-endian Most significant byte is sent first + True Little-endian Least significant byte is sent first + ======================= ============= ==================================== + + For example: + To store for example value=77.0, use ``number_of_decimals = 1`` if the + register will hold it as 770 internally. The value 770 (dec) is 0302 (hex), + where the most significant byte is 03 (hex) and the least significant byte + is 02 (hex). With ``lsb_first = False``, the most significant byte is given first + why the resulting string is ``\x03\x02``, which has the length 2. + + """ + _check_numerical(value, description="inputvalue") + _check_int( + number_of_decimals, + minvalue=0, + maxvalue=_MAX_NUMBER_OF_DECIMALS, + description="number of decimals", + ) + _check_bool(lsb_first, description="lsb_first") + _check_bool(signed, description="signed parameter") + + multiplier = 10 ** number_of_decimals + integer = int(float(value) * multiplier) + + if lsb_first: + formatcode = "<" # Little-endian + else: + formatcode = ">" # Big-endian + if signed: + formatcode += "h" # (Signed) short (2 bytes) + else: + formatcode += "H" # Unsigned short (2 bytes) + + outstring = _pack(formatcode, integer) + assert len(outstring) == 2 + return outstring + + +def _twobyte_string_to_num(bytestring, number_of_decimals=0, signed=False): + r"""Convert a two-byte string to a numerical value, possibly scaling it. + + Args: + * bytestring (str): A string of length 2. + * number_of_decimals (int): The number of decimals. Defaults to 0. + * signed (bol): Whether large positive values should be interpreted as + negative values. + + Returns: + The numerical value (int or float) calculated from the ``bytestring``. + + Raises: + TypeError, ValueError + + Use the parameter ``signed=True`` if converting a bytestring that can hold + negative values. Then upper range data will be automatically converted into + negative return values (two's complement). + + Use ``number_of_decimals=1`` to divide the received data by 10 before returning + the value. Similarly ``number_of_decimals=2`` will divide the received data by + 100 before returning the value. + + The byte order is big-endian, meaning that the most significant byte is sent first. + + For example: + A string ``\x03\x02`` (which has the length 2) corresponds to 0302 (hex) = + 770 (dec). If ``number_of_decimals = 1``, then this is converted to 77.0 (float). + + """ + _check_string(bytestring, minlength=2, maxlength=2, description="bytestring") + _check_int( + number_of_decimals, + minvalue=0, + maxvalue=_MAX_NUMBER_OF_DECIMALS, + description="number of decimals", + ) + _check_bool(signed, description="signed parameter") + + formatcode = ">" # Big-endian + if signed: + formatcode += "h" # (Signed) short (2 bytes) + else: + formatcode += "H" # Unsigned short (2 bytes) + + fullregister = _unpack(formatcode, bytestring) + + if number_of_decimals == 0: + return fullregister + divisor = 10 ** number_of_decimals + return fullregister / float(divisor) + + +def _long_to_bytestring( + value, signed=False, number_of_registers=2, byteorder=BYTEORDER_BIG +): + """Convert a long integer to a bytestring. + + Long integers (32 bits = 4 bytes) are stored in two consecutive 16-bit registers + in the slave. + + Args: + * value (int): The numerical value to be converted. + * signed (bool): Whether large positive values should be interpreted as + negative values. + * number_of_registers (int): Should be 2. For error checking only. + * byteorder (int): How multi-register data should be interpreted. + + Returns: + A bytestring (4 bytes). + + Raises: + TypeError, ValueError + + """ + _check_int(value, description="inputvalue") + _check_bool(signed, description="signed parameter") + _check_int( + number_of_registers, minvalue=2, maxvalue=2, description="number of registers" + ) + _check_int( + byteorder, minvalue=0, maxvalue=_MAX_BYTEORDER_VALUE, description="byteorder" + ) + + if byteorder in [BYTEORDER_BIG, BYTEORDER_BIG_SWAP]: + formatcode = ">" + else: + formatcode = "<" + if signed: + formatcode += "l" # (Signed) long (4 bytes) + else: + formatcode += "L" # Unsigned long (4 bytes) + + outstring = _pack(formatcode, value) + if byteorder in [BYTEORDER_BIG_SWAP, BYTEORDER_LITTLE_SWAP]: + outstring = _swap(outstring) + + assert len(outstring) == 4 + return outstring + + +def _bytestring_to_long( + bytestring, signed=False, number_of_registers=2, byteorder=BYTEORDER_BIG +): + """Convert a bytestring to a long integer. + + Long integers (32 bits = 4 bytes) are stored in two consecutive 16-bit registers + in the slave. + + Args: + * bytestring (str): A string of length 4. + * signed (bol): Whether large positive values should be interpreted as + negative values. + * number_of_registers (int): Should be 2. For error checking only. + * byteorder (int): How multi-register data should be interpreted. + + Returns: + The numerical value (int). + + Raises: + ValueError, TypeError + + """ + _check_string(bytestring, "byte string", minlength=4, maxlength=4) + _check_bool(signed, description="signed parameter") + _check_int( + number_of_registers, minvalue=2, maxvalue=2, description="number of registers" + ) + _check_int( + byteorder, minvalue=0, maxvalue=_MAX_BYTEORDER_VALUE, description="byteorder" + ) + + if byteorder in [BYTEORDER_BIG, BYTEORDER_BIG_SWAP]: + formatcode = ">" + else: + formatcode = "<" + if signed: + formatcode += "l" # (Signed) long (4 bytes) + else: + formatcode += "L" # Unsigned long (4 bytes) + + if byteorder in [BYTEORDER_BIG_SWAP, BYTEORDER_LITTLE_SWAP]: + bytestring = _swap(bytestring) + + return _unpack(formatcode, bytestring) + + +def _float_to_bytestring(value, number_of_registers=2, byteorder=BYTEORDER_BIG): + r"""Convert a numerical value to a bytestring. + + Floats are stored in two or more consecutive 16-bit registers in the slave. The + encoding is according to the standard IEEE 754. + + ====================================== ================= =========== ================= + Type of floating point number in slave Size Registers Range + ====================================== ================= =========== ================= + Single precision (binary32) 32 bits (4 bytes) 2 registers 1.4E-45 to 3.4E38 + Double precision (binary64) 64 bits (8 bytes) 4 registers 5E-324 to 1.8E308 + ====================================== ================= =========== ================= + + A floating point value of 1.0 is encoded (in single precision) as 3f800000 (hex). + This will give a byte string ``'\x3f\x80\x00\x00'`` (big endian). + + Args: + * value (float or int): The numerical value to be converted. + * number_of_registers (int): Can be 2 or 4. + * byteorder (int): How multi-register data should be interpreted. + + Returns: + A bytestring (4 or 8 bytes). + + Raises: + TypeError, ValueError + + """ + _check_numerical(value, description="inputvalue") + _check_int( + number_of_registers, minvalue=2, maxvalue=4, description="number of registers" + ) + _check_int( + byteorder, minvalue=0, maxvalue=_MAX_BYTEORDER_VALUE, description="byteorder" + ) + + if byteorder in [BYTEORDER_BIG, BYTEORDER_BIG_SWAP]: + formatcode = ">" + else: + formatcode = "<" + if number_of_registers == 2: + formatcode += "f" # Float (4 bytes) + lengthtarget = 4 + elif number_of_registers == 4: + formatcode += "d" # Double (8 bytes) + lengthtarget = 8 + else: + raise ValueError( + "Wrong number of registers! Given value is {0!r}".format( + number_of_registers + ) + ) + + outstring = _pack(formatcode, value) + if byteorder in [BYTEORDER_BIG_SWAP, BYTEORDER_LITTLE_SWAP]: + outstring = _swap(outstring) + assert len(outstring) == lengthtarget + return outstring + + +def _bytestring_to_float(bytestring, number_of_registers=2, byteorder=BYTEORDER_BIG): + """Convert a four-byte string to a float. + + Floats are stored in two or more consecutive 16-bit registers in the slave. + + For discussion on precision, number of bits, number of registers, the range, byte order + and on alternative names, see :func:`minimalmodbus._float_to_bytestring`. + + Args: + * bytestring (str): A string of length 4 or 8. + * number_of_registers (int): Can be 2 or 4. + * byteorder (int): How multi-register data should be interpreted. + + Returns: + A float. + + Raises: + TypeError, ValueError + + """ + _check_string(bytestring, minlength=4, maxlength=8, description="bytestring") + _check_int( + number_of_registers, minvalue=2, maxvalue=4, description="number of registers" + ) + _check_int( + byteorder, minvalue=0, maxvalue=_MAX_BYTEORDER_VALUE, description="byteorder" + ) + number_of_bytes = _NUMBER_OF_BYTES_PER_REGISTER * number_of_registers + + if byteorder in [BYTEORDER_BIG, BYTEORDER_BIG_SWAP]: + formatcode = ">" + else: + formatcode = "<" + if number_of_registers == 2: + formatcode += "f" # Float (4 bytes) + elif number_of_registers == 4: + formatcode += "d" # Double (8 bytes) + else: + raise ValueError( + "Wrong number of registers! Given value is {0!r}".format( + number_of_registers + ) + ) + + if len(bytestring) != number_of_bytes: + raise ValueError( + "Wrong length of the byte string! Given value is " + + "{0!r}, and number_of_registers is {1!r}.".format( + bytestring, number_of_registers + ) + ) + + if byteorder in [BYTEORDER_BIG_SWAP, BYTEORDER_LITTLE_SWAP]: + bytestring = _swap(bytestring) + return _unpack(formatcode, bytestring) + + +def _textstring_to_bytestring(inputstring, number_of_registers=16): + """Convert a text string to a bytestring. + + Each 16-bit register in the slave are interpreted as two characters (1 byte = 8 bits). + For example 16 consecutive registers can hold 32 characters (32 bytes). + + Not much of conversion is done, mostly error checking and string padding. + If the inputstring is shorter that the allocated space, it is padded with + spaces in the end. + + Args: + * inputstring (str): The string to be stored in the slave. + Max 2*number_of_registers characters. + * number_of_registers (int): The number of registers allocated for the string. + + Returns: + A bytestring (str). + + Raises: + TypeError, ValueError + + """ + _check_int( + number_of_registers, + minvalue=1, + maxvalue=_MAX_NUMBER_OF_REGISTERS_TO_WRITE, + description="number of registers", + ) + max_characters = _NUMBER_OF_BYTES_PER_REGISTER * number_of_registers + _check_string(inputstring, "input string", minlength=1, maxlength=max_characters) + + bytestring = inputstring.ljust(max_characters) # Pad with space + assert len(bytestring) == max_characters + return bytestring + + +def _bytestring_to_textstring(bytestring, number_of_registers=16): + """Convert a bytestring to a text string. + + Each 16-bit register in the slave are interpreted as two characters (1 byte = 8 bits). + For example 16 consecutive registers can hold 32 characters (32 bytes). + + Not much of conversion is done, mostly error checking. + + Args: + * bytestring (str): The string from the slave. Length = 2*number_of_registers + * number_of_registers (int): The number of registers allocated for the string. + + Returns: + A the text string (str). + + Raises: + TypeError, ValueError + + """ + _check_int( + number_of_registers, + minvalue=1, + maxvalue=_MAX_NUMBER_OF_REGISTERS_TO_READ, + description="number of registers", + ) + max_characters = _NUMBER_OF_BYTES_PER_REGISTER * number_of_registers + _check_string( + bytestring, "byte string", minlength=max_characters, maxlength=max_characters + ) + + textstring = bytestring + return textstring + + +def _valuelist_to_bytestring(valuelist, number_of_registers): + """Convert a list of numerical values to a bytestring. + + Each element is 'unsigned INT16'. + + Args: + * valuelist (list of int): The input list. The elements should be in the + range 0 to 65535. + * number_of_registers (int): The number of registers. For error checking. + Should equal the number of elements in valuelist. + + Returns: + A bytestring (str). Length = 2*number_of_registers + + Raises: + TypeError, ValueError + + """ + MINVALUE = 0 + MAXVALUE = 0xFFFF + + _check_int(number_of_registers, minvalue=1, description="number of registers") + + if not isinstance(valuelist, list): + raise TypeError( + "The valuelist parameter must be a list. Given {0!r}.".format(valuelist) + ) + + for value in valuelist: + _check_int( + value, + minvalue=MINVALUE, + maxvalue=MAXVALUE, + description="elements in the input value list", + ) + + _check_int( + len(valuelist), + minvalue=number_of_registers, + maxvalue=number_of_registers, + description="length of the list", + ) + + number_of_bytes = _NUMBER_OF_BYTES_PER_REGISTER * number_of_registers + + bytestring = "" + for value in valuelist: + bytestring += _num_to_twobyte_string(value, signed=False) + + assert len(bytestring) == number_of_bytes + return bytestring + + +def _bytestring_to_valuelist(bytestring, number_of_registers): + """Convert a bytestring to a list of numerical values. + + The bytestring is interpreted as 'unsigned INT16'. + + Args: + * bytestring (str): The string from the slave. Length = 2*number_of_registers + * number_of_registers (int): The number of registers. For error checking. + + Returns: + A list of integers. + + Raises: + TypeError, ValueError + + """ + _check_int(number_of_registers, minvalue=1, description="number of registers") + number_of_bytes = _NUMBER_OF_BYTES_PER_REGISTER * number_of_registers + _check_string( + bytestring, "byte string", minlength=number_of_bytes, maxlength=number_of_bytes + ) + + values = [] + for i in range(number_of_registers): + offset = _NUMBER_OF_BYTES_PER_REGISTER * i + substring = bytestring[offset : (offset + _NUMBER_OF_BYTES_PER_REGISTER)] + values.append(_twobyte_string_to_num(substring)) + + return values + + +def _now(): + """Return a timestamp for time duration measurements. + + Returns a float, that increases with 1.0 per second. + The starting point is undefined. + """ + if hasattr(time, "monotonic"): + return time.monotonic() + return time.time() + + +def _pack(formatstring, value): + """Pack a value into a bytestring. + + Uses the built-in :mod:`struct` Python module. + + Args: + * formatstring (str): String for the packing. See the :mod:`struct` module + for details. + * value (depends on formatstring): The value to be packed + + Returns: + A bytestring (str). + + Raises: + ValueError + + Note that the :mod:`struct` module produces byte buffers for Python3, + but bytestrings for Python2. This is compensated for automatically. + + """ + _check_string(formatstring, description="formatstring", minlength=1) + + try: + result = struct.pack(formatstring, value) + except Exception: + errortext = ( + "The value to send is probably out of range, as the num-to-bytestring " + ) + errortext += "conversion failed. Value: {0!r} Struct format code is: {1}" + raise ValueError(errortext.format(value, formatstring)) + + if sys.version_info[0] > 2: + return str( + result, encoding="latin1" + ) # Convert types to make it Python3 compatible + return result + + +def _unpack(formatstring, packed): + """Unpack a bytestring into a value. + + Uses the built-in :mod:`struct` Python module. + + Args: + * formatstring (str): String for the packing. See the :mod:`struct` module + for details. + * packed (str): The bytestring to be unpacked. + + Returns: + A value. The type depends on the formatstring. + + Raises: + ValueError + + Note that the :mod:`struct` module wants byte buffers for Python3, + but bytestrings for Python2. This is compensated for automatically. + + """ + _check_string(formatstring, description="formatstring", minlength=1) + _check_string(packed, description="packed string", minlength=1) + + if sys.version_info[0] > 2: + packed = bytes( + packed, encoding="latin1" + ) # Convert types to make it Python3 compatible + + try: + value = struct.unpack(formatstring, packed)[0] + except Exception: + errortext = ( + "The received bytestring is probably wrong, as the bytestring-to-num " + ) + errortext += "conversion failed. Bytestring: {0!r} Struct format code is: {1}" + raise InvalidResponseError(errortext.format(packed, formatstring)) + + return value + + +def _swap(bytestring): + """Swap characters pairwise in a string. + + This corresponds to a "byte swap". + + Args: + * bytestring (str): input. The length should be an even number. + + Return the string with characters swapped. + + """ + length = len(bytestring) + if length % 2: + raise ValueError( + "The length of the bytestring should be even. Given {!r}.".format( + bytestring + ) + ) + templist = list(bytestring) + templist[1:length:2], templist[:length:2] = ( + templist[:length:2], + templist[1:length:2], + ) + return "".join(templist) + + +def _hexencode(bytestring, insert_spaces=False): + r"""Convert a byte string to a hex encoded string. + + For example 'J' will return '4A', and ``'\x04'`` will return '04'. + + Args: + * bytestring (str): Can be for example ``'A\x01B\x45'``. + * insert_spaces (bool): Insert space characters between pair of characters + to increase readability. + + Returns: + A string of twice the length, with characters in the range '0' to '9' and + 'A' to 'F'. The string will be longer if spaces are inserted. + + Raises: + TypeError, ValueError + + """ + _check_string(bytestring, description="byte string") + + separator = "" if not insert_spaces else " " + + # Use plain string formatting instead of binhex.hexlify, + # in order to have it Python 2.x and 3.x compatible + + byte_representions = [] + for char in bytestring: + byte_representions.append("{0:02X}".format(ord(char))) + return separator.join(byte_representions).strip() + + +def _hexdecode(hexstring): + r"""Convert a hex encoded string to a byte string. + + For example '4A' will return 'J', and '04' will return ``'\x04'`` (which has + length 1). + + Args: + * hexstring (str): Can be for example 'A3' or 'A3B4'. Must be of even length. + * Allowed characters are '0' to '9', 'a' to 'f' and 'A' to 'F' (not space). + + Returns: + A string of half the length, with characters corresponding to all 0-255 + values for each byte. + + Raises: + TypeError, ValueError + + """ + # Note: For Python3 the appropriate would be: raise TypeError(new_error_message) from err + # but the Python2 interpreter will indicate SyntaxError. + # Thus we need to live with this warning in Python3: + # 'During handling of the above exception, another exception occurred' + + _check_string(hexstring, description="hexstring") + + if len(hexstring) % 2 != 0: + raise ValueError( + "The input hexstring must be of even length. Given: {!r}".format(hexstring) + ) + + if sys.version_info[0] > 2: + converted_bytes = bytes(hexstring, "latin1") + try: + return str(binascii.unhexlify(converted_bytes), encoding="latin1") + except binascii.Error as err: + new_error_message = "Hexdecode reported an error: {!s}. Input hexstring: {}".format( + err.args[0], hexstring + ) + raise TypeError(new_error_message) + + else: + try: + return hexstring.decode("hex") + except TypeError: + # TODO When Python3 only, show info from first exception + raise TypeError( + "Hexdecode reported an error. Input hexstring: {}".format(hexstring) + ) + + +def _hexlify(bytestring): + """Convert a byte string to a hex encoded string, with spaces for easier reading. + + This is just a facade for _hexencode() with insert_spaces = True. + + See _hexencode() for details. + + """ + return _hexencode(bytestring, insert_spaces=True) + + +def _calculate_number_of_bytes_for_bits(number_of_bits): + """Calculate number of full bytes required to house a number of bits. + + Args: + * number_of_bits (str): Number of bits + + Error checking should have been done before. + + Algorithm from MODBUS APPLICATION PROTOCOL SPECIFICATION V1.1b + + """ + result = number_of_bits // _BITS_PER_BYTE # Integer division in Python2 and 3 + if number_of_bits % _BITS_PER_BYTE: + result += 1 + return result + + +def _bit_to_bytestring(value): + """Create the bit pattern that is used for writing single bits. + + Used for functioncode 5. The same value is sent back in the response + from the slave. + + This is basically a storage of numerical constants. + + Args: + * value (int): can be 0 or 1 + + Returns: + The bit pattern (string). + + Raises: + TypeError, ValueError + + """ + _check_int(value, minvalue=0, maxvalue=1, description="inputvalue") + + if value == 0: + return "\x00\x00" + else: + return "\xff\x00" + + +def _bits_to_bytestring(valuelist): + """Build a bytestring from a list of bits. + + This is used for functioncode 15. + + Args: + * valuelist (list of int): 0 or 1 + + Returns a bytestring. + + """ + if not isinstance(valuelist, list): + raise TypeError( + "The input should be a list. " + "Given: {!r}".format(valuelist) + ) + for value in valuelist: + if value not in [0, 1, False, True]: + raise ValueError( + "Wrong value in list of bits. " + "Given: {!r}".format(value) + ) + + list_position = 0 + outputstring = "" + while list_position < len(valuelist): + sublist = valuelist[list_position : (list_position + _BITS_PER_BYTE)] + + bytevalue = 0 + for bitposition, value in enumerate(sublist): + bytevalue |= value << bitposition + outputstring += chr(bytevalue) + + list_position += _BITS_PER_BYTE + return outputstring + + +def _bytestring_to_bits(bytestring, number_of_bits): + """Parse bits from a bytestring. + + This is used for parsing the bits in response messages for functioncode 1 and 2. + + The first byte in the bytestring contains info on the addressed bit + (in LSB in that byte). Second bit from right contains info on the bit + on the next address. + + Next byte in the bytestring contains data on next 8 bits. Might be padded with + zeros toward MSB. + + Args: + * bytestring (str): input string + * number_of_bits (int): Number of bits to extract + + Returns a list of values (0 or 1). The length of the list is equal to number_of_bits. + + """ + expected_length = _calculate_number_of_bytes_for_bits(number_of_bits) + if len(bytestring) != expected_length: + raise ValueError( + "Wrong length of bytestring. Expected is " + + "{} bytes (for {} bits), actual is {} bytes.".format( + expected_length, number_of_bits, len(bytestring) + ) + ) + total_list = [] + for character in bytestring: + bytevalue = ord(character) + for bitposition in range(_BITS_PER_BYTE): + bitvalue = (bytevalue & (1 << bitposition)) > 0 + total_list.append(int(bitvalue)) + return total_list[:number_of_bits] + + +# ################### # +# Number manipulation # +# ################### # + + +def _twos_complement(x, bits=16): + """Calculate the two's complement of an integer. + + Then also negative values can be represented by an upper range of positive values. + See https://en.wikipedia.org/wiki/Two%27s_complement + + Args: + * x (int): input integer. + * bits (int): number of bits, must be > 0. + + Returns: + An int, that represents the two's complement of the input. + + Example for bits=8: + + ==== ======= + x returns + ==== ======= + 0 0 + 1 1 + 127 127 + -128 128 + -127 129 + -1 255 + ==== ======= + + """ + _check_int(bits, minvalue=0, description="number of bits") + _check_int(x, description="input") + upperlimit = 2 ** (bits - 1) - 1 + lowerlimit = -2 ** (bits - 1) + if x > upperlimit or x < lowerlimit: + raise ValueError( + "The input value is out of range. Given value is " + + "{0}, but allowed range is {1} to {2} when using {3} bits.".format( + x, lowerlimit, upperlimit, bits + ) + ) + + # Calculate two'2 complement + if x >= 0: + return x + return x + 2 ** bits + + +def _from_twos_complement(x, bits=16): + """Calculate the inverse(?) of a two's complement of an integer. + + Args: + * x (int): input integer. + * bits (int): number of bits, must be > 0. + + Returns: + An int, that represents the inverse(?) of two's complement of the input. + + Example for bits=8: + + === ======= + x returns + === ======= + 0 0 + 1 1 + 127 127 + 128 -128 + 129 -127 + 255 -1 + === ======= + + """ + _check_int(bits, minvalue=0, description="number of bits") + + _check_int(x, description="input") + upperlimit = 2 ** (bits) - 1 + lowerlimit = 0 + if x > upperlimit or x < lowerlimit: + raise ValueError( + "The input value is out of range. Given value is " + + "{0}, but allowed range is {1} to {2} when using {3} bits.".format( + x, lowerlimit, upperlimit, bits + ) + ) + + # Calculate inverse(?) of two'2 complement + limit = 2 ** (bits - 1) - 1 + if x <= limit: + return x + return x - 2 ** bits + + +# ################ # +# Bit manipulation # +# ################ # + + +def _set_bit_on(x, bit_num): + """Set bit 'bit_num' to True. + + Args: + * x (int): The value before. + * bit_num (int): The bit number that should be set to True. + + Returns: + The value after setting the bit. This is an integer. + + For example: + For x = 4 (dec) = 0100 (bin), setting bit number 0 results in 0101 (bin) = 5 (dec). + + """ + _check_int(x, minvalue=0, description="input value") + _check_int(bit_num, minvalue=0, description="bitnumber") + + return x | (1 << bit_num) + + +def _check_bit(x, bit_num): + """Check if bit 'bit_num' is set the input integer. + + Args: + * x (int): The input value. + * bit_num (int): The bit number to be checked + + Returns: + True or False + + For example: + For x = 4 (dec) = 0100 (bin), checking bit number 2 results in True, and + checking bit number 3 results in False. + + """ + _check_int(x, minvalue=0, description="input value") + _check_int(bit_num, minvalue=0, description="bitnumber") + + return (x & (1 << bit_num)) > 0 + + +# ######################## # +# Error checking functions # +# ######################## # + + +_CRC16TABLE = ( + 0, + 49345, + 49537, + 320, + 49921, + 960, + 640, + 49729, + 50689, + 1728, + 1920, + 51009, + 1280, + 50625, + 50305, + 1088, + 52225, + 3264, + 3456, + 52545, + 3840, + 53185, + 52865, + 3648, + 2560, + 51905, + 52097, + 2880, + 51457, + 2496, + 2176, + 51265, + 55297, + 6336, + 6528, + 55617, + 6912, + 56257, + 55937, + 6720, + 7680, + 57025, + 57217, + 8000, + 56577, + 7616, + 7296, + 56385, + 5120, + 54465, + 54657, + 5440, + 55041, + 6080, + 5760, + 54849, + 53761, + 4800, + 4992, + 54081, + 4352, + 53697, + 53377, + 4160, + 61441, + 12480, + 12672, + 61761, + 13056, + 62401, + 62081, + 12864, + 13824, + 63169, + 63361, + 14144, + 62721, + 13760, + 13440, + 62529, + 15360, + 64705, + 64897, + 15680, + 65281, + 16320, + 16000, + 65089, + 64001, + 15040, + 15232, + 64321, + 14592, + 63937, + 63617, + 14400, + 10240, + 59585, + 59777, + 10560, + 60161, + 11200, + 10880, + 59969, + 60929, + 11968, + 12160, + 61249, + 11520, + 60865, + 60545, + 11328, + 58369, + 9408, + 9600, + 58689, + 9984, + 59329, + 59009, + 9792, + 8704, + 58049, + 58241, + 9024, + 57601, + 8640, + 8320, + 57409, + 40961, + 24768, + 24960, + 41281, + 25344, + 41921, + 41601, + 25152, + 26112, + 42689, + 42881, + 26432, + 42241, + 26048, + 25728, + 42049, + 27648, + 44225, + 44417, + 27968, + 44801, + 28608, + 28288, + 44609, + 43521, + 27328, + 27520, + 43841, + 26880, + 43457, + 43137, + 26688, + 30720, + 47297, + 47489, + 31040, + 47873, + 31680, + 31360, + 47681, + 48641, + 32448, + 32640, + 48961, + 32000, + 48577, + 48257, + 31808, + 46081, + 29888, + 30080, + 46401, + 30464, + 47041, + 46721, + 30272, + 29184, + 45761, + 45953, + 29504, + 45313, + 29120, + 28800, + 45121, + 20480, + 37057, + 37249, + 20800, + 37633, + 21440, + 21120, + 37441, + 38401, + 22208, + 22400, + 38721, + 21760, + 38337, + 38017, + 21568, + 39937, + 23744, + 23936, + 40257, + 24320, + 40897, + 40577, + 24128, + 23040, + 39617, + 39809, + 23360, + 39169, + 22976, + 22656, + 38977, + 34817, + 18624, + 18816, + 35137, + 19200, + 35777, + 35457, + 19008, + 19968, + 36545, + 36737, + 20288, + 36097, + 19904, + 19584, + 35905, + 17408, + 33985, + 34177, + 17728, + 34561, + 18368, + 18048, + 34369, + 33281, + 17088, + 17280, + 33601, + 16640, + 33217, + 32897, + 16448, +) +r"""CRC-16 lookup table with 256 elements. + +Built with this code:: + + poly=0xA001 + table = [] + for index in range(256): + data = index << 1 + crc = 0 + for _ in range(8, 0, -1): + data >>= 1 + if (data ^ crc) & 0x0001: + crc = (crc >> 1) ^ poly + else: + crc >>= 1 + table.append(crc) + output = '' + for i, m in enumerate(table): + if not i%11: + output += "\n" + output += "{:5.0f}, ".format(m) + print output +""" + + +def _calculate_crc_string(inputstring): + """Calculate CRC-16 for Modbus. + + Args: + inputstring (str): An arbitrary-length message (without the CRC). + + Returns: + A two-byte CRC string, where the least significant byte is first. + + """ + _check_string(inputstring, description="input CRC string") + + # Preload a 16-bit register with ones + register = 0xFFFF + + for char in inputstring: + register = (register >> 8) ^ _CRC16TABLE[(register ^ ord(char)) & 0xFF] + + return _num_to_twobyte_string(register, lsb_first=True) + + +def _calculate_lrc_string(inputstring): + """Calculate LRC for Modbus. + + Args: + inputstring (str): An arbitrary-length message (without the beginning + colon and terminating CRLF). It should already be decoded from hex-string. + + Returns: + A one-byte LRC bytestring (not encoded to hex-string) + + Algorithm from the document 'MODBUS over serial line specification and + implementation guide V1.02'. + + The LRC is calculated as 8 bits (one byte). + + For example a LRC 0110 0001 (bin) = 61 (hex) = 97 (dec) = 'a'. This function will + then return 'a'. + + In Modbus ASCII mode, this should be transmitted using two characters. This + example should be transmitted '61', which is a string of length two. This function + does not handle that conversion for transmission. + + """ + _check_string(inputstring, description="input LRC string") + + register = 0 + for character in inputstring: + register += ord(character) + + lrc = ((register ^ 0xFF) + 1) & 0xFF + + return _num_to_onebyte_string(lrc) + + +def _check_mode(mode): + """Check that the Modbus mode is valie. + + Args: + mode (string): The Modbus mode (MODE_RTU or MODE_ASCII) + + Raises: + TypeError, ValueError + + """ + if not isinstance(mode, str): + raise TypeError("The {0} should be a string. Given: {1!r}".format("mode", mode)) + + if mode not in [MODE_RTU, MODE_ASCII]: + raise ValueError( + "Unreconized Modbus mode given. Must be 'rtu' or 'ascii' but {0!r} was given.".format( + mode + ) + ) + + +def _check_functioncode(functioncode, list_of_allowed_values=None): + """Check that the given functioncode is in the list_of_allowed_values. + + Also verifies that 1 <= function code <= 127. + + Args: + * functioncode (int): The function code + * list_of_allowed_values (list of int): Allowed values. Use *None* to bypass + this part of the checking. + + Raises: + TypeError, ValueError + + """ + FUNCTIONCODE_MIN = 1 + FUNCTIONCODE_MAX = 127 + + _check_int( + functioncode, FUNCTIONCODE_MIN, FUNCTIONCODE_MAX, description="functioncode" + ) + + if list_of_allowed_values is None: + return + + if not isinstance(list_of_allowed_values, list): + raise TypeError( + "The list_of_allowed_values should be a list. Given: {0!r}".format( + list_of_allowed_values + ) + ) + + for value in list_of_allowed_values: + _check_int( + value, + FUNCTIONCODE_MIN, + FUNCTIONCODE_MAX, + description="functioncode inside list_of_allowed_values", + ) + + if functioncode not in list_of_allowed_values: + raise ValueError( + "Wrong function code: {0}, allowed values are {1!r}".format( + functioncode, list_of_allowed_values + ) + ) + + +def _check_slaveaddress(slaveaddress): + """Check that the given slaveaddress is valid. + + Args: + slaveaddress (int): The slave address + + Raises: + TypeError, ValueError + + """ + SLAVEADDRESS_MAX = 255 # Allows usage also of reserved addresses + SLAVEADDRESS_MIN = 0 + + _check_int( + slaveaddress, SLAVEADDRESS_MIN, SLAVEADDRESS_MAX, description="slaveaddress" + ) + + +def _check_registeraddress(registeraddress): + """Check that the given registeraddress is valid. + + Args: + registeraddress (int): The register address + + Raises: + TypeError, ValueError + + """ + REGISTERADDRESS_MAX = 0xFFFF + REGISTERADDRESS_MIN = 0 + + _check_int( + registeraddress, + REGISTERADDRESS_MIN, + REGISTERADDRESS_MAX, + description="registeraddress", + ) + + +def _check_response_payload( + payload, + functioncode, + registeraddress, + value, + number_of_decimals, + number_of_registers, + number_of_bits, + signed, + byteorder, # Not used. For keeping same signature as _parse_payload() + payloadformat, # Not used. For keeping same signature as _parse_payload() +): + if functioncode in [1, 2, 3, 4]: + _check_response_bytecount(payload) + + if functioncode in [5, 6, 15, 16]: + _check_response_registeraddress(payload, registeraddress) + + if functioncode == 5: + _check_response_writedata(payload, _bit_to_bytestring(value)) + elif functioncode == 6: + _check_response_writedata( + payload, _num_to_twobyte_string(value, number_of_decimals, signed=signed) + ) + elif functioncode == 15: + # response number of bits + _check_response_number_of_registers(payload, number_of_bits) + + elif functioncode == 16: + _check_response_number_of_registers(payload, number_of_registers) + + # Response for read bits + if functioncode in [1, 2]: + registerdata = payload[_NUMBER_OF_BYTES_BEFORE_REGISTERDATA:] + expected_number_of_bytes = _calculate_number_of_bytes_for_bits(number_of_bits) + if len(registerdata) != expected_number_of_bytes: + raise InvalidResponseError( + "The data length is wrong for payloadformat BIT/BITS." + + " Expected: {} Actual: {}.".format( + expected_number_of_bytes, len(registerdata) + ) + ) + + # Response for read registers + if functioncode in [3, 4]: + registerdata = payload[_NUMBER_OF_BYTES_BEFORE_REGISTERDATA:] + number_of_register_bytes = number_of_registers * _NUMBER_OF_BYTES_PER_REGISTER + if len(registerdata) != number_of_register_bytes: + raise InvalidResponseError( + "The register data length is wrong. " + + "Registerdata: {!r} bytes. Expected: {!r}.".format( + len(registerdata), number_of_register_bytes + ) + ) + + +def _check_response_slaveerrorcode(response): + """Check if the slave indicates an error. + + Args: + * response (string): Response from the slave + + The response is in RTU format, but the checksum might be one or two bytes + depending on whether it was sent in RTU or ASCII mode. + + Checking of type and length of the response should be done before calling + this functions. + + Raises: + SlaveReportedException or subclass + + """ + NON_ERRORS = [5] + SLAVE_ERRORS = { + 1: IllegalRequestError("Slave reported illegal function"), + 2: IllegalRequestError("Slave reported illegal data address"), + 3: IllegalRequestError("Slave reported illegal data value"), + 4: SlaveReportedException("Slave reported device failure"), + 6: SlaveDeviceBusyError("Slave reported device busy"), + 7: NegativeAcknowledgeError("Slave reported negative acknowledge"), + 8: SlaveReportedException("Slave reported memory parity error"), + 10: SlaveReportedException("Slave reported gateway path unavailable"), + 11: SlaveReportedException( + "Slave reported gateway target device failed to respond" + ), + } + + if len(response) < _BYTEPOSITION_FOR_SLAVE_ERROR_CODE + 1: + return # This check is also done before calling, do not raise exception here. + + received_functioncode = ord(response[_BYTEPOSITION_FOR_FUNCTIONCODE]) + + if _check_bit(received_functioncode, _BITNUMBER_FUNCTIONCODE_ERRORINDICATION): + slave_error_code = ord(response[_BYTEPOSITION_FOR_SLAVE_ERROR_CODE]) + + if slave_error_code in NON_ERRORS: + return + + error = SLAVE_ERRORS.get( + slave_error_code, + SlaveReportedException( + "Slave reported error code " + str(slave_error_code) + ), + ) + raise error + + +def _check_response_bytecount(payload): + """Check that the number of bytes as given in the response is correct. + + The first byte in the payload indicates the length of the payload (first + byte not counted). + + Args: + payload (string): The payload + + Raises: + TypeError, ValueError, InvalidResponseError + + """ + POSITION_FOR_GIVEN_NUMBER = 0 + NUMBER_OF_BYTES_TO_SKIP = 1 + + _check_string( + payload, minlength=1, description="payload", exception_type=InvalidResponseError + ) + + given_number_of_databytes = ord(payload[POSITION_FOR_GIVEN_NUMBER]) + counted_number_of_databytes = len(payload) - NUMBER_OF_BYTES_TO_SKIP + + if given_number_of_databytes != counted_number_of_databytes: + errortemplate = ( + "Wrong given number of bytes in the response: " + + "{0}, but counted is {1} as data payload length is {2}." + + " The data payload is: {3!r}" + ) + errortext = errortemplate.format( + given_number_of_databytes, + counted_number_of_databytes, + len(payload), + payload, + ) + raise InvalidResponseError(errortext) + + +def _check_response_registeraddress(payload, registeraddress): + """Check that the start adress as given in the response is correct. + + The first two bytes in the payload holds the address value. + + Args: + * payload (string): The payload + * registeraddress (int): What the register address actually shoud be + (use decimal numbers, not hex). + + Raises: + TypeError, ValueError, InvalidResponseError + + """ + _check_string( + payload, minlength=2, description="payload", exception_type=InvalidResponseError + ) + _check_registeraddress(registeraddress) + + BYTERANGE_FOR_STARTADDRESS = slice(0, 2) + + bytes_for_startaddress = payload[BYTERANGE_FOR_STARTADDRESS] + received_startaddress = _twobyte_string_to_num(bytes_for_startaddress) + + if received_startaddress != registeraddress: + raise InvalidResponseError( + "Wrong given write start adress: " + + "{0}, but commanded is {1}. The data payload is: {2!r}".format( + received_startaddress, registeraddress, payload + ) + ) + + +def _check_response_number_of_registers(payload, number_of_registers): + """Check that the number of written registers as given in the response is correct. + + The bytes 2 and 3 (zero based counting) in the payload holds the value. + + Args: + * payload (string): The payload + * number_of_registers (int): Number of registers that have been written + + Raises: + TypeError, ValueError, InvalidResponseError + + """ + _check_string( + payload, minlength=4, description="payload", exception_type=InvalidResponseError + ) + _check_int( + number_of_registers, + minvalue=1, + maxvalue=max( + _MAX_NUMBER_OF_REGISTERS_TO_READ, _MAX_NUMBER_OF_REGISTERS_TO_WRITE + ), + description="number of registers", + ) + + BYTERANGE_FOR_NUMBER_OF_REGISTERS = slice(2, 4) + + bytes_for_mumber_of_registers = payload[BYTERANGE_FOR_NUMBER_OF_REGISTERS] + received_number_of_written_registers = _twobyte_string_to_num( + bytes_for_mumber_of_registers + ) + + if received_number_of_written_registers != number_of_registers: + raise InvalidResponseError( + "Wrong number of registers to write in the response: " + + "{0}, but commanded is {1}. The data payload is: {2!r}".format( + received_number_of_written_registers, number_of_registers, payload + ) + ) + + +def _check_response_writedata(payload, writedata): + """Check that the write data as given in the response is correct. + + The bytes 2 and 3 (zero based counting) in the payload holds the write data. + + Args: + * payload (string): The payload + * writedata (string): The data that should have been written. + Length should be 2 bytes. + + Raises: + TypeError, ValueError, InvalidResponseError + + """ + _check_string( + payload, minlength=4, description="payload", exception_type=InvalidResponseError + ) + _check_string(writedata, minlength=2, maxlength=2, description="writedata") + + BYTERANGE_FOR_WRITEDATA = slice(2, 4) + + received_writedata = payload[BYTERANGE_FOR_WRITEDATA] + + if received_writedata != writedata: + raise InvalidResponseError( + "Wrong write data in the response: " + + "{0!r}, but commanded is {1!r}. The data payload is: {2!r}".format( + received_writedata, writedata, payload + ) + ) + + +def _check_string( + inputstring, + description, + minlength=0, + maxlength=None, + force_ascii=False, + exception_type=ValueError, +): + """Check that the given string is valid. + + Args: + * inputstring (string): The string to be checked + * description (string): Used in error messages for the checked inputstring + * minlength (int): Minimum length of the string + * maxlength (int or None): Maximum length of the string + * force_ascii (bool): Enforce that the string is ASCII + * exception_type (Exception): The type of exception to raise for length errors + + The force_ascii argument is valid only for Python3, as all strings are ASCII in Python2. + + Raises: + TypeError, ValueError or the one given by exception_type + + Uses the function :func:`_check_int` internally. + + """ + # Type checking + if not isinstance(description, str): + raise TypeError( + "The description should be a string. Given: {0!r}".format(description) + ) + + if not isinstance(inputstring, str): + raise TypeError( + "The {0} should be a string. Given: {1!r}".format(description, inputstring) + ) + + if not isinstance(maxlength, (int, type(None))): + raise TypeError( + "The maxlength must be an integer or None. Given: {0!r}".format(maxlength) + ) + try: + issubclass(exception_type, Exception) + except TypeError: + raise TypeError( + "The exception_type must be an exception class. " + + "It not even a class. Given: {0!r}".format(type(exception_type)) + ) + if not issubclass(exception_type, Exception): + raise TypeError( + "The exception_type must be an exception class. Given: {0!r}".format( + type(exception_type) + ) + ) + + # Check values + _check_int(minlength, minvalue=0, maxvalue=None, description="minlength") + + if len(inputstring) < minlength: + raise exception_type( + "The {0} is too short: {1}, but minimum value is {2}. Given: {3!r}".format( + description, len(inputstring), minlength, inputstring + ) + ) + + if maxlength is not None: + if maxlength < 0: + raise ValueError( + "The maxlength must be positive. Given: {0}".format(maxlength) + ) + + if maxlength < minlength: + raise ValueError( + "The maxlength must not be smaller than minlength. Given: {0} and {1}".format( + maxlength, minlength + ) + ) + + if len(inputstring) > maxlength: + raise exception_type( + "The {0} is too long: {1}, but maximum value is {2}. Given: {3!r}".format( + description, len(inputstring), maxlength, inputstring + ) + ) + + if force_ascii and sys.version > "3": + try: + inputstring.encode("ascii") + except UnicodeEncodeError: + raise ValueError( + "The {0} must be ASCII. Given: {1!r}".format(description, inputstring) + ) + + +def _check_int(inputvalue, minvalue=None, maxvalue=None, description="inputvalue"): + """Check that the given integer is valid. + + Args: + * inputvalue (int or long): The integer to be checked + * minvalue (int or long, or None): Minimum value of the integer + * maxvalue (int or long, or None): Maximum value of the integer + * description (string): Used in error messages for the checked inputvalue + + Raises: + TypeError, ValueError + + Note: Can not use the function :func:`_check_string`, as that function uses this + function internally. + + """ + if not isinstance(description, str): + raise TypeError( + "The description should be a string. Given: {0!r}".format(description) + ) + + if not isinstance(inputvalue, (int, long)): + raise TypeError( + "The {0} must be an integer. Given: {1!r}".format(description, inputvalue) + ) + + if not isinstance(minvalue, (int, long, type(None))): + raise TypeError( + "The minvalue must be an integer or None. Given: {0!r}".format(minvalue) + ) + + if not isinstance(maxvalue, (int, long, type(None))): + raise TypeError( + "The maxvalue must be an integer or None. Given: {0!r}".format(maxvalue) + ) + + _check_numerical(inputvalue, minvalue, maxvalue, description) + + +def _check_numerical( + inputvalue, minvalue=None, maxvalue=None, description="inputvalue" +): + """Check that the given numerical value is valid. + + Args: + * inputvalue (numerical): The value to be checked. + * minvalue (numerical): Minimum value Use None to skip this part of the test. + * maxvalue (numerical): Maximum value. Use None to skip this part of the test. + * description (string): Used in error messages for the checked inputvalue + + Raises: + TypeError, ValueError + + Note: Can not use the function :func:`_check_string`, as it uses this function + internally. + + """ + # Type checking + if not isinstance(description, str): + raise TypeError( + "The description should be a string. Given: {0!r}".format(description) + ) + + if not isinstance(inputvalue, (int, long, float)): + raise TypeError( + "The {0} must be numerical. Given: {1!r}".format(description, inputvalue) + ) + + if not isinstance(minvalue, (int, float, long, type(None))): + raise TypeError( + "The minvalue must be numeric or None. Given: {0!r}".format(minvalue) + ) + + if not isinstance(maxvalue, (int, float, long, type(None))): + raise TypeError( + "The maxvalue must be numeric or None. Given: {0!r}".format(maxvalue) + ) + + # Consistency checking + if (minvalue is not None) and (maxvalue is not None): + if maxvalue < minvalue: + raise ValueError( + "The maxvalue must not be smaller than minvalue. " + + "Given: {0} and {1}, respectively.".format(maxvalue, minvalue) + ) + + # Value checking + if minvalue is not None: + if inputvalue < minvalue: + raise ValueError( + "The {0} is too small: {1}, but minimum value is {2}.".format( + description, inputvalue, minvalue + ) + ) + + if maxvalue is not None: + if inputvalue > maxvalue: + raise ValueError( + "The {0} is too large: {1}, but maximum value is {2}.".format( + description, inputvalue, maxvalue + ) + ) + + +def _check_bool(inputvalue, description="inputvalue"): + """Check that the given inputvalue is a boolean. + + Args: + * inputvalue (boolean): The value to be checked. + * description (string): Used in error messages for the checked inputvalue. + + Raises: + TypeError, ValueError + + """ + _check_string(description, minlength=1, description="description string") + if not isinstance(inputvalue, bool): + raise TypeError( + "The {0} must be boolean. Given: {1!r}".format(description, inputvalue) + ) + + +##################### +# Development tools # +##################### + + +def _print_out(inputstring): + """Print the inputstring. To make it compatible with Python2 and Python3. + + Args: + inputstring (str): The string that should be printed. + + Raises: + TypeError + + """ + _check_string(inputstring, description="string to print") + + sys.stdout.write(inputstring + "\n") + sys.stdout.flush() + + +# def _interpretRawMessage(inputstr): +# r"""Generate a human readable description of a Modbus bytestring. + +# Args: +# inputstr (str): The bytestring that should be interpreted. + +# Returns: +# A descriptive string. + +# For example, the string ``'\n\x03\x10\x01\x00\x01\xd0q'`` should give something like:: + +# T ODO: update + +# Modbus bytestring decoder +# Input string (length 8 characters): '\n\x03\x10\x01\x00\x01\xd0q' +# Probably modbus RTU mode. +# Slave address: 10 (dec). Function code: 3 (dec). +# Valid message. Extracted payload: '\x10\x01\x00\x01' + +# Pos Character Hex Dec Probable interpretation +# ------------------------------------------------- +# 0: '\n' 0A 10 Slave address +# 1: '\x03' 03 3 Function code +# 2: '\x10' 10 16 Payload +# 3: '\x01' 01 1 Payload +# 4: '\x00' 00 0 Payload +# 5: '\x01' 01 1 Payload +# 6: '\xd0' D0 208 Checksum, CRC LSB +# 7: 'q' 71 113 Checksum, CRC MSB + +# """ +# raise NotImplementedError() +# output = "" +# output += "Modbus bytestring decoder\n" +# output += "Input string (length {} characters): {!r} \n".format( +# len(inputstr), inputstr +# ) + +# # Detect modbus type +# if inputstr.startswith(_ASCII_HEADER) and inputstr.endswith(_ASCII_FOOTER): +# mode = MODE_ASCII +# else: +# mode = MODE_RTU +# output += "Probably Modbus {} mode.\n".format(mode.upper()) + +# # Extract slave address and function code +# try: +# if mode == MODE_ASCII: +# slaveaddress = int(inputstr[1:3]) +# functioncode = int(inputstr[3:5]) +# else: +# slaveaddress = ord(inputstr[0]) +# functioncode = ord(inputstr[1]) +# output += "Slave address: {} (dec). Function code: {} (dec).\n".format( +# slaveaddress, functioncode +# ) +# except Exception: +# output += "\nCould not extract slave address and function code. \n\n" + +# # Check message validity +# try: +# extractedpayload = _extract_payload(inputstr, slaveaddress, mode, functioncode) +# output += "Valid message. Extracted payload: {!r}\n".format(extractedpayload) +# except (ValueError, TypeError) as err: +# output += "\nThe message does not seem to be valid Modbus {}. ".format(mode.upper()) +# output += "Error message: \n{}. \n\n".format(err.messages) +# except NameError as err: +# output += ( +# "\nNo message validity checking. \n\n" +# ) # Slave address or function code not available + +# # Generate table describing the message +# if mode == MODE_RTU: +# output += "\nPos Character Hex Dec Probable interpretation \n" +# output += "------------------------------------------------- \n" +# for i, character in enumerate(inputstr): +# if i == 0: +# description = "Slave address" +# elif i == 1: +# description = "Function code" +# elif i == len(inputstr) - 2: +# description = "Checksum, CRC LSB" +# elif i == len(inputstr) - 1: +# description = "Checksum, CRC MSB" +# else: +# description = "Payload" +# output += "{0:3.0f}: {1!r:<8} {2:02X} {2: 4.0f} {3:<10} \n".format( +# i, character, ord(character), description +# ) + +# elif mode == MODE_ASCII: +# output += "\nPos Character(s) Converted Hex Dec Probable interpretation \n" +# output += "--------------------------------------------------------------- \n" + +# i = 0 +# while i < len(inputstr): + +# if inputstr[i] in [":", "\r", "\n"]: +# if inputstr[i] == ":": +# description = "Start character" +# else: +# description = "Stop character" + +# output += "{0:3.0f}: {1!r:<8} {2} \n".format( +# i, inputstr[i], description +# ) +# i += 1 + +# else: +# if i == 1: +# description = "Slave address" +# elif i == 3: +# description = "Function code" +# elif i == len(inputstr) - 4: +# description = "Checksum (LRC)" +# else: +# description = "Payload" + +# try: +# hexvalue = _hexdecode(inputstr[i:(i + 2)]) +# output += "{0:3.0f}: {1!r:<8} {2!r} {3:02X} {3: 4.0f} {4} \n". +# format( +# i, inputstr[i:(i + 2)], hexvalue, ord(hexvalue), description +# ) +# except Exception: +# output += "{0:3.0f}: {1!r:<8} ? ? ? {2} \n".format( +# i, inputstr[i:(i + 2)], description +# ) +# i += 2 + +# # Generate description for the payload +# output += "\n\n" +# try: +# output += _interpretPayload(functioncode, extractedpayload) +# except Exception: +# output += ( +# "\nCould not interpret the payload. \n\n" +# ) # Payload or function code not available + +# return output + + +# def _interpretPayload(functioncode, payload): +# r"""Generate a human readable description of a Modbus payload. + +# Args: +# * functioncode (int): Function code +# * payload (str): The payload that should be interpreted. It should be a +# byte string. + +# Returns: +# A descriptive string. + +# For example, the payload ``'\x10\x01\x00\x01'`` for functioncode 3 should give +# something like:: + +# T ODO: Update + +# """ +# raise NotImplementedError() +# output = "" +# output += "Modbus payload decoder\n" +# output += "Input payload (length {} characters): {!r} \n".format( +# len(payload), payload +# ) +# output += "Function code: {} (dec).\n".format(functioncode) + +# if len(payload) == 4: +# FourbyteMessageFirstHalfValue = _twobyte_string_to_num(payload[0:2]) +# FourbyteMessageSecondHalfValue = _twobyte_string_to_num(payload[2:4]) + +# return output + + +def _get_diagnostic_string(): + """Generate a diagnostic string, showing the module version, the platform etc. + + Returns: + A descriptive string. + + """ + text = "\n## Diagnostic output from minimalmodbus ## \n\n" + text += "Minimalmodbus version: " + __version__ + "\n" + text += "Minimalmodbus status: " + __status__ + "\n" + text += "File name (with relative path): " + __file__ + "\n" + text += "Full file path: " + os.path.abspath(__file__) + "\n\n" + text += "pySerial version: " + serial.VERSION + "\n" + text += "pySerial full file path: " + os.path.abspath(serial.__file__) + "\n\n" + text += "Platform: " + sys.platform + "\n" + text += "Filesystem encoding: " + repr(sys.getfilesystemencoding()) + "\n" + text += "Byteorder: " + sys.byteorder + "\n" + text += "Python version: " + sys.version + "\n" + text += "Python version info: " + repr(sys.version_info) + "\n" + text += "Python flags: " + repr(sys.flags) + "\n" + text += "Python argv: " + repr(sys.argv) + "\n" + text += "Python prefix: " + repr(sys.prefix) + "\n" + text += "Python exec prefix: " + repr(sys.exec_prefix) + "\n" + text += "Python executable: " + repr(sys.executable) + "\n" + try: + text += "Long info: " + repr(sys.long_info) + "\n" + except Exception: + text += "Long info: (none)\n" # For Python3 compatibility + try: + text += "Float repr style: " + repr(sys.float_repr_style) + "\n\n" + except Exception: + text += "Float repr style: (none) \n\n" # For Python 2.6 compatibility + text += "Variable __name__: " + __name__ + "\n" + text += "Current directory: " + os.getcwd() + "\n\n" + text += "Python path: \n" + text += "\n".join(sys.path) + "\n" + text += "\n## End of diagnostic output ## \n" + return text + + +# For backward compatibility +_getDiagnosticString = _get_diagnostic_string diff --git a/Device/minimalmodbus.pyc b/Device/minimalmodbus.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0edfbb4f0d95b3246a4d42c5d7b9440b52a589c6 GIT binary patch literal 102806 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

;1WtC!E_6 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

|b7`&L>;xA`&}4$DYO$oAzaLPN{OmzI{& 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 literal 0 HcmV?d00001 diff --git a/Device/pycomm/__init__.py b/Device/pycomm/__init__.py new file mode 100644 index 0000000..8c1f233 --- /dev/null +++ b/Device/pycomm/__init__.py @@ -0,0 +1 @@ +__author__ = 'agostino' diff --git a/Device/pycomm/__init__.pyc b/Device/pycomm/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..330a6c3244a41482ebe4e4fed05b72eb720b9c71 GIT binary patch literal 139 zcmZSn%*!Qct`wKd00oRd+5w1*xqw6p149&$WMl}|U;=VWIDkZAdVX<9W?sIZ21scM zNLhS*VrfZ6eo=h929U>qAc}>6+=9yF{M=mq`1s7c%#!$cy@E=xIX1cZDWy57b|6!V GLD~Ql*%@;H literal 0 HcmV?d00001 diff --git a/Device/pycomm/ab_comm/__init__.py b/Device/pycomm/ab_comm/__init__.py new file mode 100644 index 0000000..28c38a3 --- /dev/null +++ b/Device/pycomm/ab_comm/__init__.py @@ -0,0 +1,2 @@ +__author__ = 'agostino' +import logging diff --git a/Device/pycomm/ab_comm/__init__.pyc b/Device/pycomm/ab_comm/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a3f8e5c2434d00ad73eea9f192e1e7f7e2d9599 GIT binary patch literal 178 zcmZSn%*!Qct`wKd00m4y+5w1*#ehT#149&$WMoKTV#r}+hypW$HJE`?B^*E^F+IPy zBr`8R^FI*yX@K;WZ~=+<_{7qZjQpbb_!4#?Hzz+mJu@#|1IT1R5XDkJZb4;oer~RQ mVp2Sqj*rjG%PfhH*DI(5TVRu$pHiBWYR3pvS`0FtjS&FySS9NK literal 0 HcmV?d00001 diff --git a/Device/pycomm/ab_comm/clx.py b/Device/pycomm/ab_comm/clx.py new file mode 100644 index 0000000..2f9f02c --- /dev/null +++ b/Device/pycomm/ab_comm/clx.py @@ -0,0 +1,912 @@ +# -*- coding: utf-8 -*- +# +# clx.py - Ethernet/IP Client for Rockwell PLCs +# +# +# Copyright (c) 2014 Agostino Ruscito +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +from pycomm.cip.cip_base import * +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +logger = logging.getLogger(__name__) +logger.addHandler(NullHandler()) + +string_sizes = [82, 12, 16, 20, 40, 8] + + +class Driver(Base): + """ + This Ethernet/IP client is based on Rockwell specification. Please refer to the link below for details. + + http://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf + + The following services have been implemented: + - Read Tag Service (0x4c) + - Read Tag Fragment Service (0x52) + - Write Tag Service (0x4d) + - Write Tag Fragment Service (0x53) + - Multiple Service Packet (0x0a) + + The client has been successfully tested with the following PLCs: + - CompactLogix 5330ERM + - CompactLogix 5370 + - ControlLogix 5572 and 1756-EN2T Module + +""" + + def __init__(self): + super(Driver, self).__init__() + + self._buffer = {} + self._get_template_in_progress = False + self.__version__ = '0.2' + + def get_last_tag_read(self): + """ Return the last tag read by a multi request read + + :return: A tuple (tag name, value, type) + """ + return self._last_tag_read + + def get_last_tag_write(self): + """ Return the last tag write by a multi request write + + :return: A tuple (tag name, 'GOOD') if the write was successful otherwise (tag name, 'BAD') + """ + return self._last_tag_write + + def _parse_instance_attribute_list(self, start_tag_ptr, status): + """ extract the tags list from the message received + + :param start_tag_ptr: The point in the message string where the tag list begin + :param status: The status of the message receives + """ + tags_returned = self._reply[start_tag_ptr:] + tags_returned_length = len(tags_returned) + idx = 0 + instance = 0 + count = 0 + try: + while idx < tags_returned_length: + instance = unpack_dint(tags_returned[idx:idx+4]) + idx += 4 + tag_length = unpack_uint(tags_returned[idx:idx+2]) + idx += 2 + tag_name = tags_returned[idx:idx+tag_length] + idx += tag_length + symbol_type = unpack_uint(tags_returned[idx:idx+2]) + idx += 2 + count += 1 + self._tag_list.append({'instance_id': instance, + 'tag_name': tag_name, + 'symbol_type': symbol_type}) + except Exception as e: + raise DataError(e) + + if status == SUCCESS: + self._last_instance = -1 + elif status == 0x06: + self._last_instance = instance + 1 + else: + self._status = (1, 'unknown status during _parse_tag_list') + self._last_instance = -1 + + def _parse_structure_makeup_attributes(self, start_tag_ptr, status): + """ extract the tags list from the message received + + :param start_tag_ptr: The point in the message string where the tag list begin + :param status: The status of the message receives + """ + self._buffer = {} + + if status != SUCCESS: + self._buffer['Error'] = status + return + + attribute = self._reply[start_tag_ptr:] + idx = 4 + try: + if unpack_uint(attribute[idx:idx + 2]) == SUCCESS: + idx += 2 + self._buffer['object_definition_size'] = unpack_dint(attribute[idx:idx + 4]) + else: + self._buffer['Error'] = 'object_definition Error' + return + + idx += 6 + if unpack_uint(attribute[idx:idx + 2]) == SUCCESS: + idx += 2 + self._buffer['structure_size'] = unpack_dint(attribute[idx:idx + 4]) + else: + self._buffer['Error'] = 'structure Error' + return + + idx += 6 + if unpack_uint(attribute[idx:idx + 2]) == SUCCESS: + idx += 2 + self._buffer['member_count'] = unpack_uint(attribute[idx:idx + 2]) + else: + self._buffer['Error'] = 'member_count Error' + return + + idx += 4 + if unpack_uint(attribute[idx:idx + 2]) == SUCCESS: + idx += 2 + self._buffer['structure_handle'] = unpack_uint(attribute[idx:idx + 2]) + else: + self._buffer['Error'] = 'structure_handle Error' + return + + return self._buffer + + except Exception as e: + raise DataError(e) + + def _parse_template(self, start_tag_ptr, status): + """ extract the tags list from the message received + + :param start_tag_ptr: The point in the message string where the tag list begin + :param status: The status of the message receives + """ + tags_returned = self._reply[start_tag_ptr:] + bytes_received = len(tags_returned) + + self._buffer += tags_returned + + if status == SUCCESS: + self._get_template_in_progress = False + + elif status == 0x06: + self._byte_offset += bytes_received + else: + self._status = (1, 'unknown status {0} during _parse_template'.format(status)) + logger.warning(self._status) + self._last_instance = -1 + + def _parse_fragment(self, start_ptr, status): + """ parse the fragment returned by a fragment service. + + :param start_ptr: Where the fragment start within the replay + :param status: status field used to decide if keep parsing or stop + """ + + try: + data_type = unpack_uint(self._reply[start_ptr:start_ptr+2]) + fragment_returned = self._reply[start_ptr+2:] + except Exception as e: + raise DataError(e) + + fragment_returned_length = len(fragment_returned) + idx = 0 + + while idx < fragment_returned_length: + try: + typ = I_DATA_TYPE[data_type] + if self._output_raw: + value = fragment_returned[idx:idx+DATA_FUNCTION_SIZE[typ]] + else: + value = UNPACK_DATA_FUNCTION[typ](fragment_returned[idx:idx+DATA_FUNCTION_SIZE[typ]]) + idx += DATA_FUNCTION_SIZE[typ] + except Exception as e: + raise DataError(e) + if self._output_raw: + self._tag_list += value + else: + self._tag_list.append((self._last_position, value)) + self._last_position += 1 + + if status == SUCCESS: + self._byte_offset = -1 + elif status == 0x06: + self._byte_offset += fragment_returned_length + else: + self._status = (2, '{0}: {1}'.format(SERVICE_STATUS[status], get_extended_status(self._reply, 48))) + logger.warning(self._status) + self._byte_offset = -1 + + def _parse_multiple_request_read(self, tags): + """ parse the message received from a multi request read: + + For each tag parsed, the information extracted includes the tag name, the value read and the data type. + Those information are appended to the tag list as tuple + + :return: the tag list + """ + offset = 50 + position = 50 + try: + number_of_service_replies = unpack_uint(self._reply[offset:offset+2]) + tag_list = [] + for index in range(number_of_service_replies): + position += 2 + start = offset + unpack_uint(self._reply[position:position+2]) + general_status = unpack_usint(self._reply[start+2:start+3]) + + if general_status == 0: + data_type = unpack_uint(self._reply[start+4:start+6]) + value_begin = start + 6 + value_end = value_begin + DATA_FUNCTION_SIZE[I_DATA_TYPE[data_type]] + value = self._reply[value_begin:value_end] + self._last_tag_read = (tags[index], UNPACK_DATA_FUNCTION[I_DATA_TYPE[data_type]](value), + I_DATA_TYPE[data_type]) + else: + self._last_tag_read = (tags[index], None, None) + + tag_list.append(self._last_tag_read) + + return tag_list + except Exception as e: + raise DataError(e) + + def _parse_multiple_request_write(self, tags): + """ parse the message received from a multi request writ: + + For each tag parsed, the information extracted includes the tag name and the status of the writing. + Those information are appended to the tag list as tuple + + :return: the tag list + """ + offset = 50 + position = 50 + try: + number_of_service_replies = unpack_uint(self._reply[offset:offset+2]) + tag_list = [] + for index in range(number_of_service_replies): + position += 2 + start = offset + unpack_uint(self._reply[position:position+2]) + general_status = unpack_usint(self._reply[start+2:start+3]) + + if general_status == 0: + self._last_tag_write = (tags[index] + ('GOOD',)) + else: + self._last_tag_write = (tags[index] + ('BAD',)) + + tag_list.append(self._last_tag_write) + return tag_list + except Exception as e: + raise DataError(e) + + def _check_reply(self): + """ check the replayed message for error + + """ + self._more_packets_available = False + try: + if self._reply is None: + self._status = (3, '%s without reply' % REPLAY_INFO[unpack_dint(self._message[:2])]) + return False + # Get the type of command + typ = unpack_uint(self._reply[:2]) + + # Encapsulation status check + if unpack_dint(self._reply[8:12]) != SUCCESS: + self._status = (3, "{0} reply status:{1}".format(REPLAY_INFO[typ], + SERVICE_STATUS[unpack_dint(self._reply[8:12])])) + return False + + # Command Specific Status check + if typ == unpack_uint(ENCAPSULATION_COMMAND["send_rr_data"]): + status = unpack_usint(self._reply[42:43]) + if status != SUCCESS: + self._status = (3, "send_rr_data reply:{0} - Extend status:{1}".format( + SERVICE_STATUS[status], get_extended_status(self._reply, 42))) + return False + else: + return True + elif typ == unpack_uint(ENCAPSULATION_COMMAND["send_unit_data"]): + status = unpack_usint(self._reply[48:49]) + if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Read Tag Fragmented"]: + self._parse_fragment(50, status) + return True + if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Get Instance Attributes List"]: + self._parse_instance_attribute_list(50, status) + return True + if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Get Attributes"]: + self._parse_structure_makeup_attributes(50, status) + return True + if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Read Template"] and \ + self._get_template_in_progress: + self._parse_template(50, status) + return True + if status == 0x06: + self._status = (3, "Insufficient Packet Space") + self._more_packets_available = True + elif status != SUCCESS: + self._status = (3, "send_unit_data reply:{0} - Extend status:{1}".format( + SERVICE_STATUS[status], get_extended_status(self._reply, 48))) + logger.warning(self._status) + return False + else: + return True + + return True + except Exception as e: + raise DataError(e) + + def read_tag(self, tag): + """ read tag from a connected plc + + Possible combination can be passed to this method: + - ('Counts') a single tag name + - (['ControlWord']) a list with one tag or many + - (['parts', 'ControlWord', 'Counts']) + + At the moment there is not a strong validation for the argument passed. The user should verify + the correctness of the format passed. + + :return: None is returned in case of error otherwise the tag list is returned + """ + self.clear() + multi_requests = False + if isinstance(tag, list): + multi_requests = True + + if not self._target_is_connected: + if not self.forward_open(): + self._status = (6, "Target did not connected. read_tag will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. read_tag will not be executed.") + + if multi_requests: + rp_list = [] + for t in tag: + rp = create_tag_rp(t, multi_requests=True) + if rp is None: + self._status = (6, "Cannot create tag {0} request packet. read_tag will not be executed.".format(tag)) + raise DataError("Cannot create tag {0} request packet. read_tag will not be executed.".format(tag)) + else: + rp_list.append(chr(TAG_SERVICES_REQUEST['Read Tag']) + rp + pack_uint(1)) + message_request = build_multiple_service(rp_list, Base._get_sequence()) + + else: + rp = create_tag_rp(tag) + if rp is None: + self._status = (6, "Cannot create tag {0} request packet. read_tag will not be executed.".format(tag)) + return None + else: + # Creating the Message Request Packet + message_request = [ + pack_uint(Base._get_sequence()), + chr(TAG_SERVICES_REQUEST['Read Tag']), # the Request Service + chr(len(rp) / 2), # the Request Path Size length in word + rp, # the request path + pack_uint(1) + ] + + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid, + )) is None: + raise DataError("send_unit_data returned not valid data") + + if multi_requests: + return self._parse_multiple_request_read(tag) + else: + # Get the data type + if self._status[0] == SUCCESS: + data_type = unpack_uint(self._reply[50:52]) + try: + return UNPACK_DATA_FUNCTION[I_DATA_TYPE[data_type]](self._reply[52:]), I_DATA_TYPE[data_type] + except Exception as e: + raise DataError(e) + else: + return None + + def read_array(self, tag, counts, raw=False): + """ read array of atomic data type from a connected plc + + At the moment there is not a strong validation for the argument passed. The user should verify + the correctness of the format passed. + + :param tag: the name of the tag to read + :param counts: the number of element to read + :param raw: the value should output as raw-value (hex) + :return: None is returned in case of error otherwise the tag list is returned + """ + self.clear() + if not self._target_is_connected: + if not self.forward_open(): + self._status = (7, "Target did not connected. read_tag will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. read_tag will not be executed.") + + self._byte_offset = 0 + self._last_position = 0 + self._output_raw = raw + + if self._output_raw: + self._tag_list = '' + else: + self._tag_list = [] + while self._byte_offset != -1: + rp = create_tag_rp(tag) + if rp is None: + self._status = (7, "Cannot create tag {0} request packet. read_tag will not be executed.".format(tag)) + return None + else: + # Creating the Message Request Packet + message_request = [ + pack_uint(Base._get_sequence()), + chr(TAG_SERVICES_REQUEST["Read Tag Fragmented"]), # the Request Service + chr(len(rp) / 2), # the Request Path Size length in word + rp, # the request path + pack_uint(counts), + pack_dint(self._byte_offset) + ] + + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid, + )) is None: + raise DataError("send_unit_data returned not valid data") + + return self._tag_list + + def write_tag(self, tag, value=None, typ=None): + """ write tag/tags from a connected plc + + Possible combination can be passed to this method: + - ('tag name', Value, data type) as single parameters or inside a tuple + - ([('tag name', Value, data type), ('tag name2', Value, data type)]) as array of tuples + + At the moment there is not a strong validation for the argument passed. The user should verify + the correctness of the format passed. + + The type accepted are: + - BOOL + - SINT + - INT' + - DINT + - REAL + - LINT + - BYTE + - WORD + - DWORD + - LWORD + + :param tag: tag name, or an array of tuple containing (tag name, value, data type) + :param value: the value to write or none if tag is an array of tuple or a tuple + :param typ: the type of the tag to write or none if tag is an array of tuple or a tuple + :return: None is returned in case of error otherwise the tag list is returned + """ + self.clear() # cleanup error string + multi_requests = False + if isinstance(tag, list): + multi_requests = True + + if not self._target_is_connected: + if not self.forward_open(): + self._status = (8, "Target did not connected. write_tag will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. write_tag will not be executed.") + + if multi_requests: + rp_list = [] + tag_to_remove = [] + idx = 0 + for name, value, typ in tag: + # Create the request path to wrap the tag name + rp = create_tag_rp(name, multi_requests=True) + if rp is None: + self._status = (8, "Cannot create tag{0} req. packet. write_tag will not be executed".format(tag)) + return None + else: + try: # Trying to add the rp to the request path list + val = PACK_DATA_FUNCTION[typ](value) + rp_list.append( + chr(TAG_SERVICES_REQUEST['Write Tag']) + + rp + + pack_uint(S_DATA_TYPE[typ]) + + pack_uint(1) + + val + ) + idx += 1 + except (LookupError, struct.error) as e: + self._status = (8, "Tag:{0} type:{1} removed from write list. Error:{2}.".format(name, typ, e)) + + # The tag in idx position need to be removed from the rp list because has some kind of error + tag_to_remove.append(idx) + + # Remove the tags that have not been inserted in the request path list + for position in tag_to_remove: + del tag[position] + # Create the message request + message_request = build_multiple_service(rp_list, Base._get_sequence()) + + else: + if isinstance(tag, tuple): + name, value, typ = tag + else: + name = tag + + rp = create_tag_rp(name) + if rp is None: + self._status = (8, "Cannot create tag {0} request packet. write_tag will not be executed.".format(tag)) + logger.warning(self._status) + return None + else: + # Creating the Message Request Packet + message_request = [ + pack_uint(Base._get_sequence()), + chr(TAG_SERVICES_REQUEST["Write Tag"]), # the Request Service + chr(len(rp) / 2), # the Request Path Size length in word + rp, # the request path + pack_uint(S_DATA_TYPE[typ]), # data type + pack_uint(1), # Add the number of tag to write + PACK_DATA_FUNCTION[typ](value) + ] + + ret_val = self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid, + ) + ) + + if multi_requests: + return self._parse_multiple_request_write(tag) + else: + if ret_val is None: + raise DataError("send_unit_data returned not valid data") + return ret_val + + def write_array(self, tag, values, data_type, raw=False): + """ write array of atomic data type from a connected plc + At the moment there is not a strong validation for the argument passed. The user should verify + the correctness of the format passed. + :param tag: the name of the tag to read + :param data_type: the type of tag to write + :param values: the array of values to write, if raw: the frame with bytes + :param raw: indicates that the values are given as raw values (hex) + """ + self.clear() + if not isinstance(values, list): + self._status = (9, "A list of tags must be passed to write_array.") + logger.warning(self._status) + raise DataError("A list of tags must be passed to write_array.") + + if not self._target_is_connected: + if not self.forward_open(): + self._status = (9, "Target did not connected. write_array will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. write_array will not be executed.") + + array_of_values = "" + byte_size = 0 + byte_offset = 0 + + for i, value in enumerate(values): + if raw: + array_of_values += value + else: + array_of_values += PACK_DATA_FUNCTION[data_type](value) + byte_size += DATA_FUNCTION_SIZE[data_type] + + if byte_size >= 450 or i == len(values)-1: + # create the message and send the fragment + rp = create_tag_rp(tag) + if rp is None: + self._status = (9, "Cannot create tag {0} request packet. \ + write_array will not be executed.".format(tag)) + return None + else: + # Creating the Message Request Packet + message_request = [ + pack_uint(Base._get_sequence()), + chr(TAG_SERVICES_REQUEST["Write Tag Fragmented"]), # the Request Service + chr(len(rp) / 2), # the Request Path Size length in word + rp, # the request path + pack_uint(S_DATA_TYPE[data_type]), # Data type to write + pack_uint(len(values)), # Number of elements to write + pack_dint(byte_offset), + array_of_values # Fragment of elements to write + ] + byte_offset += byte_size + + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid, + )) is None: + raise DataError("send_unit_data returned not valid data") + array_of_values = "" + byte_size = 0 + + def _get_instance_attribute_list_service(self): + """ Step 1: Finding user-created controller scope tags in a Logix5000 controller + + This service returns instance IDs for each created instance of the symbol class, along with a list + of the attribute data associated with the requested attribute + """ + try: + if not self._target_is_connected: + if not self.forward_open(): + self._status = (10, "Target did not connected. get_tag_list will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. get_tag_list will not be executed.") + + self._last_instance = 0 + + self._get_template_in_progress = True + while self._last_instance != -1: + + # Creating the Message Request Packet + + message_request = [ + pack_uint(Base._get_sequence()), + chr(TAG_SERVICES_REQUEST['Get Instance Attributes List']), # STEP 1 + # the Request Path Size length in word + chr(3), + # Request Path ( 20 6B 25 00 Instance ) + CLASS_ID["8-bit"], # Class id = 20 from spec 0x20 + CLASS_CODE["Symbol Object"], # Logical segment: Symbolic Object 0x6B + INSTANCE_ID["16-bit"], # Instance Segment: 16 Bit instance 0x25 + '\x00', + pack_uint(self._last_instance), # The instance + # Request Data + pack_uint(2), # Number of attributes to retrieve + pack_uint(1), # Attribute 1: Symbol name + pack_uint(2) # Attribute 2: Symbol type + ] + + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid, + )) is None: + raise DataError("send_unit_data returned not valid data") + + self._get_template_in_progress = False + + except Exception as e: + raise DataError(e) + + def _get_structure_makeup(self, instance_id): + """ + get the structure makeup for a specific structure + """ + if not self._target_is_connected: + if not self.forward_open(): + self._status = (10, "Target did not connected. get_tag_list will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. get_tag_list will not be executed.") + + message_request = [ + pack_uint(self._get_sequence()), + chr(TAG_SERVICES_REQUEST['Get Attributes']), + chr(3), # Request Path ( 20 6B 25 00 Instance ) + CLASS_ID["8-bit"], # Class id = 20 from spec 0x20 + CLASS_CODE["Template Object"], # Logical segment: Template Object 0x6C + INSTANCE_ID["16-bit"], # Instance Segment: 16 Bit instance 0x25 + '\x00', + pack_uint(instance_id), + pack_uint(4), # Number of attributes + pack_uint(4), # Template Object Definition Size UDINT + pack_uint(5), # Template Structure Size UDINT + pack_uint(2), # Template Member Count UINT + pack_uint(1) # Structure Handle We can use this to read and write UINT + ] + + if self.send_unit_data( + build_common_packet_format(DATA_ITEM['Connected'], + ''.join(message_request), ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid,)) is None: + raise DataError("send_unit_data returned not valid data") + + return self._buffer + + def _read_template(self, instance_id, object_definition_size): + """ get a list of the tags in the plc + + """ + if not self._target_is_connected: + if not self.forward_open(): + self._status = (10, "Target did not connected. get_tag_list will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. get_tag_list will not be executed.") + + self._byte_offset = 0 + self._buffer = "" + self._get_template_in_progress = True + + try: + while self._get_template_in_progress: + + # Creating the Message Request Packet + + message_request = [ + pack_uint(self._get_sequence()), + chr(TAG_SERVICES_REQUEST['Read Template']), + chr(3), # Request Path ( 20 6B 25 00 Instance ) + CLASS_ID["8-bit"], # Class id = 20 from spec 0x20 + CLASS_CODE["Template Object"], # Logical segment: Template Object 0x6C + INSTANCE_ID["16-bit"], # Instance Segment: 16 Bit instance 0x25 + '\x00', + pack_uint(instance_id), + pack_dint(self._byte_offset), # Offset + pack_uint(((object_definition_size * 4)-23) - self._byte_offset) + ] + + if not self.send_unit_data( + build_common_packet_format(DATA_ITEM['Connected'], ''.join(message_request), + ADDRESS_ITEM['Connection Based'], addr_data=self._target_cid,)): + raise DataError("send_unit_data returned not valid data") + + self._get_template_in_progress = False + return self._buffer + + except Exception as e: + raise DataError(e) + + def _isolating_user_tag(self): + try: + lst = self._tag_list + self._tag_list = [] + for tag in lst: + if tag['tag_name'].find(':') != -1 or tag['tag_name'].find('__') != -1: + continue + if tag['symbol_type'] & 0b0001000000000000: + continue + dimension = (tag['symbol_type'] & 0b0110000000000000) >> 13 + + if tag['symbol_type'] & 0b1000000000000000 : + template_instance_id = tag['symbol_type'] & 0b0000111111111111 + tag_type = 'struct' + data_type = 'user-created' + self._tag_list.append({'instance_id': tag['instance_id'], + 'template_instance_id': template_instance_id, + 'tag_name': tag['tag_name'], + 'dim': dimension, + 'tag_type': tag_type, + 'data_type': data_type, + 'template': {}, + 'udt': {}}) + else: + tag_type = 'atomic' + datatype = tag['symbol_type'] & 0b0000000011111111 + data_type = I_DATA_TYPE[datatype] + if datatype == 0xc1: + bit_position = (tag['symbol_type'] & 0b0000011100000000) >> 8 + self._tag_list.append({'instance_id': tag['instance_id'], + 'tag_name': tag['tag_name'], + 'dim': dimension, + 'tag_type': tag_type, + 'data_type': data_type, + 'bit_position' : bit_position}) + else: + self._tag_list.append({'instance_id': tag['instance_id'], + 'tag_name': tag['tag_name'], + 'dim': dimension, + 'tag_type': tag_type, + 'data_type': data_type}) + except Exception as e: + raise DataError(e) + + def _parse_udt_raw(self, tag): + try: + buff = self._read_template(tag['template_instance_id'], tag['template']['object_definition_size']) + member_count = tag['template']['member_count'] + names = buff.split('\00') + lst = [] + + tag['udt']['name'] = 'Not an user defined structure' + for name in names: + if len(name) > 1: + + if name.find(';') != -1: + tag['udt']['name'] = name[:name.find(';')] + elif name.find('ZZZZZZZZZZ') != -1: + continue + elif name.isalpha(): + lst.append(name) + else: + continue + tag['udt']['internal_tags'] = lst + + type_list = [] + + for i in xrange(member_count): + # skip member 1 + + if i != 0: + array_size = unpack_uint(buff[:2]) + try: + data_type = I_DATA_TYPE[unpack_uint(buff[2:4])] + except Exception: + data_type = "None" + + offset = unpack_dint(buff[4:8]) + type_list.append((array_size, data_type, offset)) + + buff = buff[8:] + + tag['udt']['data_type'] = type_list + except Exception as e: + raise DataError(e) + + def get_tag_list(self): + self._tag_list = [] + # Step 1 + self._get_instance_attribute_list_service() + + # Step 2 + self._isolating_user_tag() + + # Step 3 + for tag in self._tag_list: + if tag['tag_type'] == 'struct': + tag['template'] = self._get_structure_makeup(tag['template_instance_id']) + + for idx, tag in enumerate(self._tag_list): + # print (tag) + if tag['tag_type'] == 'struct': + self._parse_udt_raw(tag) + + # Step 4 + + return self._tag_list + + def write_string(self, tag, value, size=82): + """ + Rockwell define different string size: + STRING STRING_12 STRING_16 STRING_20 STRING_40 STRING_8 + by default we assume size 82 (STRING) + """ + if size not in string_sizes: + raise DataError("String size is incorrect") + + data_tag = ".".join((tag, "DATA")) + len_tag = ".".join((tag, "LEN")) + + # create an empty array + data_to_send = [0] * size + for idx, val in enumerate(value): + data_to_send[idx] = ord(val) + + self.write_tag(len_tag, len(value), 'DINT') + self.write_array(data_tag, data_to_send, 'SINT') + + def read_string(self, tag): + data_tag = ".".join((tag, "DATA")) + len_tag = ".".join((tag, "LEN")) + length = self.read_tag(len_tag) + values = self.read_array(data_tag, length[0]) + values = zip(*values)[1] #[val[1] for val in values] + char_array = [chr(ch) for ch in values] + return ''.join(char_array) diff --git a/Device/pycomm/ab_comm/clx.pyc b/Device/pycomm/ab_comm/clx.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b8724b4e38cdafbd95f82f5d4ecf9e008e3383a GIT binary patch literal 25189 zcmdsgYiwNSncjD1D3ZgAC{fgfwqhT9ofYLs)WxynRg{fnl6L6GlzK>omTh@5nmHtg zmzm+5GZtw}+h&tZlWw=!c3Yrm7TdHb7P}~V*#ZH2**4u`(V*z|2JDXlMYrhoM+&q> z3j`<%^hf$U&wI|9;fRvxSc?YhXg;3v-OqQv_x8N+cas0%@W4CY|KxjRm;Bd@zgO^! zegjDb|2((u+ybw1ZryWldv1G71$o|X%M~i`drxOR{LF;V-@6hm0nlrbCrHqDY(jjs|>p3 zUiUVxhg>+I4u`W22RW_ziT#*t^+)(`!oyX}n!rYkmFmrCMb@Yz8dLo|ZSS z;ujr65;{H|o)ojiOoMrKP|l%7l<@K$}#t`S$#ijW-G<{yoz7+Uyx)g zg=NA9`6|{c&lkaq9#_fhVxOz@=mM`(I{>d5ua`4r#%I3M=s@HPf~{I{@Djr^H-C2ZEh_{{7Lzr0=zYq5{qJEbVB z`1P6})XQsk!}WDPYJ}zLQng%)tM%HXe`7sF6~7rSg-t)M`{>1Auh!Q5JK=i$uD?`o z`js#)RoA1*0S&ei$Bj#8&a7ACuvv;*&2X}rbX{u2^$qJ58|X~6Qa-cXthX9bN98k> zdbzcM$wg-x8)wd4eEGuZ#>Uz6XN#x9+Udq*qq1b9EMOW-^>s|4T3hy`u=#$q97g_1 z>HQEh3u}ILqp=>cqp)&G^Ws9B_Jgog@fS+V{=7BuC(dqtx_olC8m~1=%j}@D>dWUl zt1dS2kPq}$*}clH-M!RV_s!ONT*a)j0dJJbYhlbOo-LhhKX>x>R!Vq%eAK8_#(Etv@$8PW zTHLI!Crw|zc-{wp^7Xc6=FTtpZ;H+b2FheR{E+~sxF^peiSf^K_rNc6ZdHuat2*8n z^JGK30Qsp#5#&c^MZPi@v6r)x=O_Bu$vz}es{y8{TatdUSgloKa2w_n@3fY%XI1aD z(s~reB#Pp47#HIZo1+wms9tO|>&s27UQAY7EP`u9*!RVv*k{0T#hsKqf<+Zj@w50v zoQLxcHo?8n%jO>WdX+kVO4;I_d1W(%)Y z`L-3fp)WPn^pbzok6YY26KqSKd&+;mwBEv>c)Jm{cbSP5N}S?4hAN_Zkwbm7$Bij* zxRN{im`0{afPH&-^1t@5C%-GI+U3zzu(xMF@%r`a(AilG-Y=-LeiiN7cA&E@qsJXh${<;XR1agN4IrE6Cx*HB{}PEGZpBS7LhTgLLj?H-LR)IqHd2uu*E3HvA|qHI0%Qaq|+SZRj`ZRmxYR>9m6=ZcZMsWYw{a`7{xAft{km=Ew8LaZQPvV{6k1RZ6LPL9`HmP{wT2#QWpKQT^fHn? zxr7R%?TtJ2^&%OC)X*w5!03}mTD7%W{VpVo4PR;L0g9Mk6pD3lrRKz)HP+r6O_1G6 zRRjBJtZ!pKIkygJ%luXif@!T-!5Vhnw|GxRn+>fFN{vQXtEgaRs~k3{x9D!V6qjb2 z&3aSvVE*RR)Xe;R+~$4hqL{d_XPh7nitWeRAf2yPqggc-a<5?aF}p-) zgH3@dJ-3#3&7bDAaV@Z=%QSCzhdkq9(5}I~wtvY>_y?ptm>H;*%!z$~g1?&NT|`Z) z1K=7~En!hf_xs%C+Cj3BuHn#MANUU18hhJqh#%~2h<+Oad`}`fd!oGz@rGwl_OO{G zT@Kg~gS!kt9{k9s_*;7$V#tOV?jFL_5M#Rg#B_fErn?VJS3;uAbomx#r2cVZm(mTz zA?DglGd_ZSUca*%mg8b2T%txvg)pjq5JpFLEArKYn5LKu*nF!@!^hfCdC0P?ZcHY# z5pLWGn=qxp1S0AOof%0znzvco;)+0ki1X{twE9wv12UB06HI8d2gjIj;=$8Qjw6{M zDT~PkKChlbB956cjo=05llkn40X>h32?J`+Y@@Umwi<0l6upmH(W^*YZvo6@*z3s+ zgAwJuPk{M6hwGl)z#gs#b0fx($c)ICq%QpmE{vvjQI}BALnZ{0$`$b!{0eXnc+Hiz z!BM*|Ey8%vd+e)c6@&mCCI>5|c8)p}*w-pF64)%BTN0xy_H*S{q4|KE`V9dB$H8&{ z3)ly`ku3e=re^S=OyHlyRhO3V;o19sm!^=|ThcD(OvGw$aw~W2SIYi?v>^g1-r0uq zsxK|Ubd%@>)&Te*AQGhe_4@KM3_RLYcT3G0bgO`paDw}yYj+3Sp`uQ9N~vwS+@5x~ z)c-{1NuK04(OpC-EqR(7p{&GjGtwL&nhBvGkgnSRWc+{;PQt81?@*SqRFh4zlkqUwln3v%PdHA@}+9H zUh!K*@qo@%fZbI>n!Rgb*wCD5asZ@@;(8&Oi_Owqtgdq^eeLGl)WYobx#Iln z+cVOZZ_eGgI`su>o0bLyX@aNNb6Zhw)FTODlWON!<9u3UekS zGl2=%bTA6SO3{`{Oe1)SEkBK9LNbyjlEfbB*n4S9!U}8$Sww<5(sz_;`x1>YMe74a zsUlAaD%~G;l@tx(F&~xTq}~4$^kxctU*3DlJDe!!y^w`@NY8?IEcdK8%3NHJ=Ei|Q znfgAO`xIFcpOp(rW+|5R9#|5n zhXNCXoL@wH(rL!tq!bG}ZwDy4$=?cYeEcZDf@A;`4Z7#!(0N&C zhCOT0QkN2u=ofrfDVq^cTx&@^uP+r7b}pQv3J8`}Ww67p*5s;SG+Vk7BN5|T4r_3K ztf%bfb8JKPMlYZ!yhp6Z?!l@8Qsv$??&GMPXxzewf&F5Ff{5|ARQUnQqZg65ej5Aa z8ND#;2fSyzXTTYr!PO}E!ZGlPBe}6$KRAbY1Q}z-BmNI=cJPRQ-a+FJ;St{w?wIh1 zU;3lq5xIHWI^=dL*)N3f?523mg3}q~IQ!iH{8vJpn zm)PzTre671NKA>;Pk=y<1o{5|m2yRJgxe+T0H2%dI+(}$8A`suD^g8|7BR!y*O<`8 z?WWaCJO`g==`52sn0$fBH70K|nPYOD$pjMqEP1%2CZ=KhFv1ZiU%)Gme0H@f<&5PH z=EgkH3o1JD5OX{(H6d6;pusQZxcMMokGZve*PN143Mpw)3q?@d^UjCR7(bF| zqY#wv3{exemR5Y%=5MMETmgG&bI98K zC$)h;elKmttj%$~@-f%63pnR@G{$`4u;)X3Hdh(vvO)czg@OyuZGJOHCCb+M>p8CT z(OuUWT1?kEA91Tk^%hJ~(I(=$V>{xH=_}ZU@T+_`=RsNXAmU&b;;pCp$}#9G)ViZH zNc{3jSYDHMU^WPZeyX_8;U5xIZ%cdlb{K-i63)Fw;7(n$+$df)4t|5z=@PG;v zUUmtVh9r9gDOhYai&RLeFS5<2*e|a-i>&b_c5~XFk(%Gx6UDr$x9AF1Uo>N?v>K|D zO!$Nm?Sw2A;I+h{3oBAhqT?uh9gg?e#B1VTO~LfYzXquvaS&E$=STDwScfUtL1iYQ zIfHKCimsLwbCLM;=i%W9qf@NH$Id4E=%-6uEn4qK_N;dqP~nIP{S`OrfFtQt3FD|( zdLQ8$r911P0feu!7OMs`H?Cd1Rh*rB?YaO%X*$K^#hV2stxVV=b-3U%n^H-enVY(L zWB%r~tFrK>uD|)_)wyZo@AQgGMl3X2q3pid;=pLzg4hHH7C?UOmTT&k}%IWKla@D&6)c$?)Gort2v{Q5x}H01$a7e;n%3PkBB0 zBi<2sK?>gU$nC@R5zj|SPghz{9_!KUVr|sP^|ci%0tuO71q@Q;s=zW2eh+dzuvxHV zP$l@o1eXk%pkOcu=rPfXE)aEw$*zd6829MkX`{fM1pCSedvitY(cJ-W85UgLZGD+z zOyAz77l!;B(nK*AUlH;Tl?hyy!s_2hs=#Xtap1ALwt&I_9r?*fACjFI+ybZt5{eQ9 z-5rJb41*0fNAdGEKXi*g1W*@-`sx@T22Tt8s@BqUG!z}r*+ix#Z#o9dCW4vHqxW`4 zSiBL}9-TLb6T}Q6?yyZLo6qt->84oRBcu`7^1yq>p+2sHHEPE3QxtULa2E3wJng=c z_s~bWKpt0G_9R&-UK5u24<#~=Crc*J7c9zQ$jDEK>o4Zus$*x*x=JS6U>$FtaIx>= z=LoWmk0%vI+_M-i$;4C7FK)h*>xrKi8=nUo?*|))u`AFSb3o}^HM~zO3x5-%*l^MR z#@+@?K`06BK)JL_ez{(&!Mg#b-dHcU+4zlm6ji|$P`+`eT2r8wUoO=UWCWu#N)V=) zv1D)@uhcu@s)%v%ztjH2i77cW5PMPbVWTahztjZH3_z=_>hGYwVu=ag>I&$&RuFQD_FM1iQJBm6^_Am)nawD$=2AM_^)6SEMWeSRh4Q* zPnx~`No@@J(jl}F_{U|ys}8rqGTg?MN!hV7E>p`gipZs>N;Ot3V_PBmjm=G@TYQoU znaA}VQ71^{uRIA-6=V`)L)i9&8iOrNy&}otOL-LwV$S|jrDDoL^wX@@Ek?~Pucy*G z70_W=gYbt>qfsJHC85KmnFFCfN2>yQ(p?=8oY}kjz@1Bu%9SUGYO2HV0PvL& zuYh0)ivI(^V2Qg717#Tk%5p4s(mR%?YH-Z!=@~)(A*vdAA~Su+9Z;(gv>DDHf{Ky% zPN26#xiU2!ZqH10Si_K%5T-it%5%{h%7Wa-bl#xELB0i3CJ=~peLD8r%E23yT9E#% zDm0cCuskitaL>p?)dNxlAnfFgN$gRR?S?i(G)sQ>&?`Wz4|T_q3E&zL_EZ`$pTiFBdx&$$ z@o}mt#}Wkq_D+W^e=3#bHpj2gotVk;&96E9TV!to5To2M(Z9~bXsOvOZIdCF5X)RG zx6#wb2-lxb(PMro?Bq+5bOef1aYe=sj}o_fCR7p^l*KG0O@xz5L|MG`!y3UEWGw`F zrlQk4MLr;8l%KYuiIs4x9fJ8sBpyjn(Z}KW5+y+i-N=3R0AasgL3 z0Hbr}X`}@uk;S+`$(^9i!UmH~CQT+0l8yiuDiH$uZPN;*#8wOLvhEh^;`dn8kg{A% zU-bX$WcydxZji3Gl;JbvTLJ(=fNXy!vqxSRyHD6VIShr$6n@d~KVTVx=RIf{0`h(W zmSK-;en*z!K6&_rM>34yf0>o|U){S1*XySp3fqz9A}~Qrhj==1b4Kx+x%h9zN zae0Ubm?GOZ#kLWLV624C0l%`ni8 z)!Hv?50>Tws|CbmhsTkt$2G~uhuk|rF$tTROT?R}`5tf$`6d}zU_?WE6|+U8hmWRy~vQMkcQ{GuI;$lRVMeM+CiRFymo zadHV(TN578h|v_K#J!oCo#|g#yYEb#cvRP?U=OF|=XV>M25$rdGf^t!MvdC0;ZLU4 zut3`r!Qy@i=Z+f05#SzfpDg0?oc3S6e*IdeH(1vE?A$_E7IIE>WlcX=E10?3-Pg4T zYrT4FVWz9E#p}UzSJw0{dDoPeRZO%Tyf`Q<$;LUw{QxXv=c^)=0xLc5j452I(5VeU(K52YC^f+VOBx!M{ey#YCS6-Ho$_|Wde!SmoP>OYkKKQI&gjWv z6cl?Ao%j#OD6}lJwRQ(7ObesUCxQF`HjzLRlYm_aeoxvmKeWGyO2%S(tj|Im2^1_~ zFR&}FD;*Y4i#O^x3u4^MULB45Nejfi^x^sYlM#KK4@_uRu;g(MnW=u#H=l_9mp~sM z{|yNH2+DX?!5%?{S0R&knLJu4Tw#?=0fek_ZkL!a!V4YRAk{=jR(MLg;?Azs>uars z!m*|DSuC<}8R2KaIy=e~OcjXbwxNuNs+7S^w3RhzjtAscuETe6AB;_RN@9gH9# zaU^GeL{BackfL|rx!it063^rh=ZC$)+_C%!feVF>F_N_nRSZM7J=CGUj`RSkKs|(w zFx-|<4kt5(UzF?CVd>VC$1=J~MF9%MW59_-x$Sci92QVNfN`VWFQ;w~xhx()HiU5y z2>-H>4fs#sMG(r*6l(2?2PDc=(COQ6d+$P-gK~>3Xf)rWo(DyW$KGmy7NGP&OQpUf zZ1F9aN=> zLj!;a-PqFZR!37nI+ZwXmOPalwu4RyRdC#JBxs0<=VL^O&VLh(w7;$5p=Gwxo8NZ$x5!5^ zjqmq~oEU%1MCab1lT^$4iPC}6Nu~1kBLXK>Iu%vgC8awgbhj2FRUxwa*$P@_Ce=?d z;5Wlp5HboBM-CJPyLb1fiila`5q|{GN>B*KRX{30 zLm**>DCQD>KW@y|52%44K3)NR>JUnT;~}fet6<)BfJZvnjZDMdd7+%;L5Gkx%m7hd zhGis31R@4ZW;2Vp6#gAHtqFImc+>hYl7a&h=7Bfh5qa`fDzbviuz8+%1RT%&dzP) zV=i#cpYluVbYF|@n-4wX`$_feaGx2bXjCs(L987g3rQk~Y0;+_@Q;ij2HLs)U{&gMCjCxUa z?t%(Q6CH=%gD>Isi5p8#WCbiVD`T9yV&y!>X66%V{Gt3(0a{bnuF`)x4YC9~(9P8K zX*-BBJBMR2b2uF{JN;;mYBm`8n4+xo0VlI_XqW8WIr;)>%SoK>)%NjEZHhFQ{u^YG zKa0w)HxEXaA?QTT_rX1yDGr>OTfZYpLh!uZA7xix;!`~duXloaJ`tkciy%M8*>kjRY5r(Bf4m7~SSx++9mm~8?4ROj zA5CiSM-zaRjA=^P?jMleUqN;Uy-N-kfEx}`Lhqn_94G@ec*Nte(*kfrNMW026nJ+@!7)I8@v4jZu2I#2kgM)XNXRCt?oT24 z5oCVwW!y$ocsnhufSVf36iKo-@zp-FlK3&JJPIn+4Qawc-Ql1S2w*u$6IE+f>@yMu zKURN)met>3!r(glbSMXhsZmT%f?6C2Pg)4S$H!nQc2w;mvZN{7_f$mTd`1nljv!Cr z5`-Htxe#vTdM)_NZ1Y!`e2z8gc_AK1ms0R+%qHZ&C)l4%9#Nxpe8Uh1X_3oCv#Wr` zh~`k{pf*zw4}0f<7wpGx6fi&k_TpntecoUqwEKWQu$<9{qbN!9_vg}Ueh5lRHeVIZ zEs^r?k(7TuA!X1mseylR8cb?3fOW-3D5D1(T$D$e*7qwwY#@FTn{?$walX9u%S7U* zZ-1Q>$N&q8TjtAdeF0-6xDDZ%2-4Hc-lMdaoAnvq~S*RmUMi18>VmLge&M1goaQ;bpH)~u?{3P z;(SmJoD17e>zEx773G3W@J!t}Vqg|)M-jq;#{)&Zi?0rQ;2p>&0zuycsslI~wL@`2 z?&LV&VC9#SV|LX5EDC_WIFbDO>1A_4wn4Gy`>rZw0Q-v`kSL2E!)*|7zJ9VA+k z*PLz8Z{aeK3?aB1;Y}kY95}})`I^uVd}acq0F)pzB7$EP8aXOlau^|E^9-RS~7AtBLnHbdfmryEiUDUvLWzAdnSD6ROMT~W6y|GfV zz-R8!Eu9v(!=`OQl_GH*#rpDJ+leR2=C?uvKCniipDqf%jaxku-Vq8wruHedKgT;h zm7$A-5)F2oWrIBvv4k$d0q`X~a3+2$<7LwCWpqONeFk(n;`M@V5ks6ijQhi&UVe^k zfK-bEO1MV7r%^tTJLHY$_QSQ82wrrglc}QCzm6MhUGRShTcn^v?0ZqKB8I)K&nO$; z>9~DX$Qw2gD#B=yJ7&u@OJdH zrdlE?NtHFXxn_a3+=EmU=8Qj55VUt=n+XTM!h-KG`HM`x!Q^iv=`eW6c;#{36DK9Z z?*y&jmrTCvL+~{}kUxM$ekON3cfcF#(RZg6k%(g(+8SbA;k1;3fH4Tf;+!X63pfIrKs5oNfh?#($!Bf8hlyv_JzXN%H=vEaab$#F z(B&tPLFj}&xz~3F`movjLNGh`diu9`?tGS4Ja?geeg16w`qLfPuk4ruzWa*NOZeuk ze>a2+DuPQv7uG;4iB>Ck;P|tES^rMEk z{z}VYS@_l?d7lQef;x~fC>JlV*RQcd{2uH6=UmP2U^8xU_flVSz3|L~Y0#@b?v26O zAR*3qWZU)^aRV|3)pBp@gGk()kS1BCq9&OM>KEU@-n9M8TPf>Qi6P+;1_^nN#lar@ zv*;J9IPS@H_JOO6N}_8MqWOD}R7;ek*rOa>9_o30yKXM{yO>q*TTK2Q61^%(6xo$# z>TI%fo5_77dLbWF8;TFHuMAL@*lYOvy!r>MMY)iCVe`-Mo^{GAV&mnNQnM&tzNbYW zL`&I9w&vg9nv<71Flc_3=Lk5)vtAMxO{NxbY`ykk5nnfl8cg;P5akLEGC9eF;EEl1 zo#s`*fs+r&=<8i zt7sBQ?`UtX(5L^sPQabOm|O7d}-uRd}&*WN1tR8=(s6 z|6Rajx!T~bc!!6GD6je1HZT)?)n7ii*^LIi(Q08ktdRVl9Z2kgIm3^F&%6a%%9l`V wvbR!6|34AFi#!YJVdFhNq!jSW_Wwxmv$R@7IaG!7-WY`HCvZ&X03u@kA45*D&;S4c literal 0 HcmV?d00001 diff --git a/Device/pycomm/ab_comm/slc.py b/Device/pycomm/ab_comm/slc.py new file mode 100644 index 0000000..834cd7c --- /dev/null +++ b/Device/pycomm/ab_comm/slc.py @@ -0,0 +1,574 @@ +# -*- coding: utf-8 -*- +# +# clx.py - Ethernet/IP Client for Rockwell PLCs +# +# +# Copyright (c) 2014 Agostino Ruscito +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +from pycomm.cip.cip_base import * +import re +import math +#import binascii + +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +logger = logging.getLogger(__name__) +logger.addHandler(NullHandler()) + + +def parse_tag(tag): + t = re.search(r"(?P[CT])(?P\d{1,3})" + r"(:)(?P\d{1,3})" + r"(.)(?PACC|PRE|EN|DN|TT|CU|CD|DN|OV|UN|UA)", tag, flags=re.IGNORECASE) + if t: + if (1 <= int(t.group('file_number')) <= 255) \ + and (0 <= int(t.group('element_number')) <= 255): + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': t.group('file_number'), + 'element_number': t.group('element_number'), + 'sub_element': PCCC_CT[t.group('sub_element').upper()], + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 3} + + t = re.search(r"(?P[LFBN])(?P\d{1,3})" + r"(:)(?P\d{1,3})" + r"(/(?P\d{1,2}))?", + tag, flags=re.IGNORECASE) + if t: + if t.group('sub_element') is not None: + if (1 <= int(t.group('file_number')) <= 255) \ + and (0 <= int(t.group('element_number')) <= 255) \ + and (0 <= int(t.group('sub_element')) <= 15): + + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': t.group('file_number'), + 'element_number': t.group('element_number'), + 'sub_element': t.group('sub_element'), + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 3} + else: + if (1 <= int(t.group('file_number')) <= 255) \ + and (0 <= int(t.group('element_number')) <= 255): + + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': t.group('file_number'), + 'element_number': t.group('element_number'), + 'sub_element': t.group('sub_element'), + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 2} + + t = re.search(r"(?P[IO])(:)(?P\d{1,3})" + r"(.)(?P\d{1,3})" + r"(/(?P\d{1,2}))?", tag, flags=re.IGNORECASE) + if t: + if t.group('sub_element') is not None: + if (0 <= int(t.group('file_number')) <= 255) \ + and (0 <= int(t.group('element_number')) <= 255) \ + and (0 <= int(t.group('sub_element')) <= 15): + + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': t.group('file_number'), + 'element_number': t.group('element_number'), + 'sub_element': t.group('sub_element'), + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 3} + else: + if (0 <= int(t.group('file_number')) <= 255) \ + and (0 <= int(t.group('element_number')) <= 255): + + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': t.group('file_number'), + 'element_number': t.group('element_number'), + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 2} + + t = re.search(r"(?PS)" + r"(:)(?P\d{1,3})" + r"(/(?P\d{1,2}))?", tag, flags=re.IGNORECASE) + if t: + if t.group('sub_element') is not None: + if (0 <= int(t.group('element_number')) <= 255) \ + and (0 <= int(t.group('sub_element')) <= 15): + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': '2', + 'element_number': t.group('element_number'), + 'sub_element': t.group('sub_element'), + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 3} + else: + if 0 <= int(t.group('element_number')) <= 255: + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': '2', + 'element_number': t.group('element_number'), + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 2} + + t = re.search(r"(?PB)(?P\d{1,3})" + r"(/)(?P\d{1,4})", + tag, flags=re.IGNORECASE) + if t: + if (1 <= int(t.group('file_number')) <= 255) \ + and (0 <= int(t.group('element_number')) <= 4095): + bit_position = int(t.group('element_number')) + element_number = bit_position / 16 + sub_element = bit_position - (element_number * 16) + return True, t.group(0), {'file_type': t.group('file_type').upper(), + 'file_number': t.group('file_number'), + 'element_number': element_number, + 'sub_element': sub_element, + 'read_func': '\xa2', + 'write_func': '\xab', + 'address_field': 3} + + return False, tag + + +class Driver(Base): + """ + SLC/PLC_5 Implementation + """ + def __init__(self): + super(Driver, self).__init__() + + self.__version__ = '0.1' + self._last_sequence = 0 + + def _check_reply(self): + """ + check the replayed message for error + """ + self._more_packets_available = False + try: + if self._reply is None: + self._status = (3, '%s without reply' % REPLAY_INFO[unpack_dint(self._message[:2])]) + return False + # Get the type of command + typ = unpack_uint(self._reply[:2]) + + # Encapsulation status check + if unpack_dint(self._reply[8:12]) != SUCCESS: + self._status = (3, "{0} reply status:{1}".format(REPLAY_INFO[typ], + SERVICE_STATUS[unpack_dint(self._reply[8:12])])) + return False + + # Command Specific Status check + if typ == unpack_uint(ENCAPSULATION_COMMAND["send_rr_data"]): + status = unpack_usint(self._reply[42:43]) + if status != SUCCESS: + self._status = (3, "send_rr_data reply:{0} - Extend status:{1}".format( + SERVICE_STATUS[status], get_extended_status(self._reply, 42))) + return False + else: + return True + + elif typ == unpack_uint(ENCAPSULATION_COMMAND["send_unit_data"]): + status = unpack_usint(self._reply[48:49]) + if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Read Tag Fragmented"]: + self._parse_fragment(50, status) + return True + if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Get Instance Attributes List"]: + self._parse_tag_list(50, status) + return True + if status == 0x06: + self._status = (3, "Insufficient Packet Space") + self._more_packets_available = True + elif status != SUCCESS: + self._status = (3, "send_unit_data reply:{0} - Extend status:{1}".format( + SERVICE_STATUS[status], get_extended_status(self._reply, 48))) + return False + else: + return True + + return True + except Exception as e: + raise DataError(e) + + def __queue_data_available(self, queue_number): + """ read the queue + + Possible combination can be passed to this method: + print c.read_tag('F8:0', 3) return a list of 3 registers starting from F8:0 + print c.read_tag('F8:0') return one value + + It is possible to read status bit + + :return: None is returned in case of error + """ + + # Creating the Message Request Packet + self._last_sequence = pack_uint(Base._get_sequence()) + + # PCCC_Cmd_Rd_w3_Q2 = [0x0f, 0x00, 0x30, 0x00, 0xa2, 0x6d, 0x00, 0xa5, 0x02, 0x00] + message_request = [ + self._last_sequence, + '\x4b', + '\x02', + CLASS_ID["8-bit"], + PATH["PCCC"], + '\x07', + self.attribs['vid'], + self.attribs['vsn'], + '\x0f', + '\x00', + self._last_sequence[1], + self._last_sequence[0], + '\xa2', # protected typed logical read with three address fields FNC + '\x6d', # Byte size to read = 109 + '\x00', # File Number + '\xa5', # File Type + pack_uint(queue_number) + ] + + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid,)): + + sts = int(unpack_uint(self._reply[2:4])) + if sts == 146: + return True + else: + return False + else: + raise DataError("read_queue [send_unit_data] returned not valid data") + + def __save_record(self, filename): + with open(filename, "a") as csv_file: + logger.debug("SLC __save_record read:{0}".format(self._reply[61:])) + csv_file.write(self._reply[61:]+'\n') + csv_file.close() + + def __get_queue_size(self, queue_number): + """ get queue size + """ + # Creating the Message Request Packet + self._last_sequence = pack_uint(Base._get_sequence()) + + message_request = [ + self._last_sequence, + '\x4b', + '\x02', + CLASS_ID["8-bit"], + PATH["PCCC"], + '\x07', + self.attribs['vid'], + self.attribs['vsn'], + '\x0f', + '\x00', + self._last_sequence[1], + self._last_sequence[0], + # '\x30', + # '\x00', + '\xa1', # FNC to get the queue size + '\x06', # Byte size to read = 06 + '\x00', # File Number + '\xea', # File Type ???? + '\xff', # File Type ???? + pack_uint(queue_number) + ] + + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid,)): + sts = int(unpack_uint(self._reply[65:67])) + logger.debug("SLC __get_queue_size({0}) returned {1}".format(queue_number, sts)) + return sts + else: + raise DataError("read_queue [send_unit_data] returned not valid data") + + def read_queue(self, queue_number, file_name): + """ read the queue + + """ + if not self._target_is_connected: + if not self.forward_open(): + self._status = (5, "Target did not connected. is_queue_available will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. is_queue_available will not be executed.") + + if self.__queue_data_available(queue_number): + logger.debug("SLC read_queue: Queue {0} has data".format(queue_number)) + self.__save_record(file_name) + size = self.__get_queue_size(queue_number) + if size > 0: + for i in range(0, size): + if self.__queue_data_available(queue_number): + self.__save_record(file_name) + + logger.debug("SLC read_queue: {0} record extract from queue {1}".format(size, queue_number)) + else: + logger.debug("SLC read_queue: Queue {0} has no data".format(queue_number)) + + def read_tag(self, tag, n=1): + """ read tag from a connected plc + + Possible combination can be passed to this method: + print c.read_tag('F8:0', 3) return a list of 3 registers starting from F8:0 + print c.read_tag('F8:0') return one value + + It is possible to read status bit + + :return: None is returned in case of error + """ + res = parse_tag(tag) + if not res[0]: + self._status = (1000, "Error parsing the tag passed to read_tag({0},{1})".format(tag, n)) + logger.warning(self._status) + raise DataError("Error parsing the tag passed to read_tag({0},{1})".format(tag, n)) + + bit_read = False + bit_position = 0 + sub_element = 0 + if int(res[2]['address_field'] == 3): + bit_read = True + bit_position = int(res[2]['sub_element']) + + if not self._target_is_connected: + if not self.forward_open(): + self._status = (5, "Target did not connected. read_tag will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. read_tag will not be executed.") + + data_size = PCCC_DATA_SIZE[res[2]['file_type']] + + # Creating the Message Request Packet + self._last_sequence = pack_uint(Base._get_sequence()) + + message_request = [ + self._last_sequence, + '\x4b', + '\x02', + CLASS_ID["8-bit"], + PATH["PCCC"], + '\x07', + self.attribs['vid'], + self.attribs['vsn'], + '\x0f', + '\x00', + self._last_sequence[1], + self._last_sequence[0], + res[2]['read_func'], + pack_usint(data_size * n), + pack_usint(int(res[2]['file_number'])), + PCCC_DATA_TYPE[res[2]['file_type']], + pack_usint(int(res[2]['element_number'])), + pack_usint(sub_element) + ] + + logger.debug("SLC read_tag({0},{1})".format(tag, n)) + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request), + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid,)): + sts = int(unpack_usint(self._reply[58])) + try: + if sts != 0: + sts_txt = PCCC_ERROR_CODE[sts] + self._status = (1000, "Error({0}) returned from read_tag({1},{2})".format(sts_txt, tag, n)) + logger.warning(self._status) + raise DataError("Error({0}) returned from read_tag({1},{2})".format(sts_txt, tag, n)) + + new_value = 61 + if bit_read: + if res[2]['file_type'] == 'T' or res[2]['file_type'] == 'C': + if bit_position == PCCC_CT['PRE']: + return UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']]( + self._reply[new_value+2:new_value+2+data_size]) + elif bit_position == PCCC_CT['ACC']: + return UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']]( + self._reply[new_value+4:new_value+4+data_size]) + + tag_value = UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']]( + self._reply[new_value:new_value+data_size]) + return get_bit(tag_value, bit_position) + + else: + values_list = [] + while len(self._reply[new_value:]) >= data_size: + values_list.append( + UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']](self._reply[new_value:new_value+data_size]) + ) + new_value = new_value+data_size + + if len(values_list) > 1: + return values_list + else: + return values_list[0] + + except Exception as e: + self._status = (1000, "Error({0}) parsing the data returned from read_tag({1},{2})".format(e, tag, n)) + logger.warning(self._status) + raise DataError("Error({0}) parsing the data returned from read_tag({1},{2})".format(e, tag, n)) + else: + raise DataError("send_unit_data returned not valid data") + + def write_tag(self, tag, value): + """ write tag from a connected plc + + Possible combination can be passed to this method: + c.write_tag('N7:0', [-30, 32767, -32767]) + c.write_tag('N7:0', 21) + c.read_tag('N7:0', 10) + + It is not possible to write status bit + + :return: None is returned in case of error + """ + res = parse_tag(tag) + if not res[0]: + self._status = (1000, "Error parsing the tag passed to read_tag({0},{1})".format(tag, value)) + logger.warning(self._status) + raise DataError("Error parsing the tag passed to read_tag({0},{1})".format(tag, value)) + + if isinstance(value, list) and int(res[2]['address_field'] == 3): + self._status = (1000, "Function's parameters error. read_tag({0},{1})".format(tag, value)) + logger.warning(self._status) + raise DataError("Function's parameters error. read_tag({0},{1})".format(tag, value)) + + if isinstance(value, list) and int(res[2]['address_field'] == 3): + self._status = (1000, "Function's parameters error. read_tag({0},{1})".format(tag, value)) + logger.warning(self._status) + raise DataError("Function's parameters error. read_tag({0},{1})".format(tag, value)) + + bit_field = False + bit_position = 0 + sub_element = 0 + if int(res[2]['address_field'] == 3): + bit_field = True + bit_position = int(res[2]['sub_element']) + values_list = '' + else: + values_list = '\xff\xff' + + multi_requests = False + if isinstance(value, list): + multi_requests = True + + if not self._target_is_connected: + if not self.forward_open(): + self._status = (1000, "Target did not connected. write_tag will not be executed.") + logger.warning(self._status) + raise DataError("Target did not connected. write_tag will not be executed.") + + try: + n = 0 + if multi_requests: + data_size = PCCC_DATA_SIZE[res[2]['file_type']] + for v in value: + values_list += PACK_PCCC_DATA_FUNCTION[res[2]['file_type']](v) + n += 1 + else: + n = 1 + if bit_field: + data_size = 2 + + if (res[2]['file_type'] == 'T' or res[2]['file_type'] == 'C') \ + and (bit_position == PCCC_CT['PRE'] or bit_position == PCCC_CT['ACC']): + sub_element = bit_position + values_list = '\xff\xff' + PACK_PCCC_DATA_FUNCTION[res[2]['file_type']](value) + else: + sub_element = 0 + if value > 0: + values_list = pack_uint(math.pow(2, bit_position)) + pack_uint(math.pow(2, bit_position)) + else: + values_list = pack_uint(math.pow(2, bit_position)) + pack_uint(0) + + else: + values_list += PACK_PCCC_DATA_FUNCTION[res[2]['file_type']](value) + data_size = PCCC_DATA_SIZE[res[2]['file_type']] + + except Exception as e: + self._status = (1000, "Error({0}) packing the values to write to the" + "SLC write_tag({1},{2})".format(e, tag, value)) + logger.warning(self._status) + raise DataError("Error({0}) packing the values to write to the " + "SLC write_tag({1},{2})".format(e, tag, value)) + + data_to_write = values_list + + # Creating the Message Request Packet + self._last_sequence = pack_uint(Base._get_sequence()) + + message_request = [ + self._last_sequence, + '\x4b', + '\x02', + CLASS_ID["8-bit"], + PATH["PCCC"], + '\x07', + self.attribs['vid'], + self.attribs['vsn'], + '\x0f', + '\x00', + self._last_sequence[1], + self._last_sequence[0], + res[2]['write_func'], + pack_usint(data_size * n), + pack_usint(int(res[2]['file_number'])), + PCCC_DATA_TYPE[res[2]['file_type']], + pack_usint(int(res[2]['element_number'])), + pack_usint(sub_element) + ] + + logger.debug("SLC write_tag({0},{1})".format(tag, value)) + if self.send_unit_data( + build_common_packet_format( + DATA_ITEM['Connected'], + ''.join(message_request) + data_to_write, + ADDRESS_ITEM['Connection Based'], + addr_data=self._target_cid,)): + sts = int(unpack_usint(self._reply[58])) + try: + if sts != 0: + sts_txt = PCCC_ERROR_CODE[sts] + self._status = (1000, "Error({0}) returned from SLC write_tag({1},{2})".format(sts_txt, tag, value)) + logger.warning(self._status) + raise DataError("Error({0}) returned from SLC write_tag({1},{2})".format(sts_txt, tag, value)) + + return True + except Exception as e: + self._status = (1000, "Error({0}) parsing the data returned from " + "SLC write_tag({1},{2})".format(e, tag, value)) + logger.warning(self._status) + raise DataError("Error({0}) parsing the data returned from " + "SLC write_tag({1},{2})".format(e, tag, value)) + else: + raise DataError("send_unit_data returned not valid data") diff --git a/Device/pycomm/cip/__init__.py b/Device/pycomm/cip/__init__.py new file mode 100644 index 0000000..8c1f233 --- /dev/null +++ b/Device/pycomm/cip/__init__.py @@ -0,0 +1 @@ +__author__ = 'agostino' diff --git a/Device/pycomm/cip/__init__.pyc b/Device/pycomm/cip/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..974d04f1ddaa30aa79667e0ae521a3271215a4da GIT binary patch literal 143 zcmZSn%*!Qct`wKd00oRd+5w1*xqw6p149&$WMl}|U;=VWIDkZAdVX<9W?sIZ21scM zNLhS*VrfZ6eo=h929U>qAd1C++=9yF{M=mq +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +import struct +import socket +import random + +from os import getpid +from pycomm.cip.cip_const import * +from pycomm.common import PycommError + + +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass +logger = logging.getLogger(__name__) +logger.addHandler(NullHandler()) + + +class CommError(PycommError): + pass + + +class DataError(PycommError): + pass + + +def pack_sint(n): + return struct.pack('b', n) + + +def pack_usint(n): + return struct.pack('B', n) + + +def pack_int(n): + """pack 16 bit into 2 bytes little endian""" + return struct.pack('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 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +ELEMENT_ID = { + "8-bit": '\x28', + "16-bit": '\x29', + "32-bit": '\x2a' +} + +CLASS_ID = { + "8-bit": '\x20', + "16-bit": '\x21', +} + +INSTANCE_ID = { + "8-bit": '\x24', + "16-bit": '\x25' +} + +ATTRIBUTE_ID = { + "8-bit": '\x30', + "16-bit": '\x31' +} + +# Path are combined as: +# CLASS_ID + PATHS +# For example PCCC path is CLASS_ID["8-bit"]+PATH["PCCC"] -> 0x20, 0x67, 0x24, 0x01. +PATH = { + 'Connection Manager': '\x06\x24\x01', + 'Router': '\x02\x24\x01', + 'Backplane Data Type': '\x66\x24\x01', + 'PCCC': '\x67\x24\x01', + 'DHCP Channel A': '\xa6\x24\x01\x01\x2c\x01', + 'DHCP Channel B': '\xa6\x24\x01\x02\x2c\x01' +} + +ENCAPSULATION_COMMAND = { # Volume 2: 2-3.2 Command Field UINT 2 byte + "nop": '\x00\x00', + "list_targets": '\x01\x00', + "list_services": '\x04\x00', + "list_identity": '\x63\x00', + "list_interfaces": '\x64\x00', + "register_session": '\x65\x00', + "unregister_session": '\x66\x00', + "send_rr_data": '\x6F\x00', + "send_unit_data": '\x70\x00' +} + +""" +When a tag is created, an instance of the Symbol Object (Class ID 0x6B) is created +inside the controller. + +When a UDT is created, an instance of the Template object (Class ID 0x6C) is +created to hold information about the structure makeup. +""" +CLASS_CODE = { + "Message Router": '\x02', # Volume 1: 5-1 + "Symbol Object": '\x6b', + "Template Object": '\x6c', + "Connection Manager": '\x06' # Volume 1: 3-5 +} + +CONNECTION_MANAGER_INSTANCE = { + 'Open Request': '\x01', + 'Open Format Rejected': '\x02', + 'Open Resource Rejected': '\x03', + 'Open Other Rejected': '\x04', + 'Close Request': '\x05', + 'Close Format Request': '\x06', + 'Close Other Request': '\x07', + 'Connection Timeout': '\x08' +} + +TAG_SERVICES_REQUEST = { + "Read Tag": 0x4c, + "Read Tag Fragmented": 0x52, + "Write Tag": 0x4d, + "Write Tag Fragmented": 0x53, + "Read Modify Write Tag": 0x4e, + "Multiple Service Packet": 0x0a, + "Get Instance Attributes List": 0x55, + "Get Attributes": 0x03, + "Read Template": 0x4c, +} + +TAG_SERVICES_REPLY = { + 0xcc: "Read Tag", + 0xd2: "Read Tag Fragmented", + 0xcd: "Write Tag", + 0xd3: "Write Tag Fragmented", + 0xce: "Read Modify Write Tag", + 0x8a: "Multiple Service Packet", + 0xd5: "Get Instance Attributes List", + 0x83: "Get Attributes", + 0xcc: "Read Template" +} + + +I_TAG_SERVICES_REPLY = { + "Read Tag": 0xcc, + "Read Tag Fragmented": 0xd2, + "Write Tag": 0xcd, + "Write Tag Fragmented": 0xd3, + "Read Modify Write Tag": 0xce, + "Multiple Service Packet": 0x8a, + "Get Instance Attributes List": 0xd5, + "Get Attributes": 0x83, + "Read Template": 0xcc +} + + +""" +EtherNet/IP Encapsulation Error Codes + +Standard CIP Encapsulation Error returned in the cip message header +""" +STATUS = { + 0x0000: "Success", + 0x0001: "The sender issued an invalid or unsupported encapsulation command", + 0x0002: "Insufficient memory", + 0x0003: "Poorly formed or incorrect data in the data portion", + 0x0064: "An originator used an invalid session handle when sending an encapsulation message to the target", + 0x0065: "The target received a message of invalid length", + 0x0069: "Unsupported Protocol Version" +} + +""" +MSG Error Codes: + +The following error codes have been taken from: + +Rockwell Automation Publication +1756-RM003P-EN-P - December 2014 +""" +SERVICE_STATUS = { + 0x01: "Connection failure (see extended status)", + 0x02: "Insufficient resource", + 0x03: "Invalid value", + 0x04: "IOI syntax error. A syntax error was detected decoding the Request Path (see extended status)", + 0x05: "Destination unknown, class unsupported, instance \nundefined or structure element undefined (see extended status)", + 0x06: "Insufficient Packet Space", + 0x07: "Connection lost", + 0x08: "Service not supported", + 0x09: "Error in data segment or invalid attribute value", + 0x0A: "Attribute list error", + 0x0B: "State already exist", + 0x0C: "Object state conflict", + 0x0D: "Object already exist", + 0x0E: "Attribute not settable", + 0x0F: "Permission denied", + 0x10: "Device state conflict", + 0x11: "Reply data too large", + 0x12: "Fragmentation of a primitive value", + 0x13: "Insufficient command data", + 0x14: "Attribute not supported", + 0x15: "Too much data", + 0x1A: "Bridge request too large", + 0x1B: "Bridge response too large", + 0x1C: "Attribute list shortage", + 0x1D: "Invalid attribute list", + 0x1E: "Request service error", + 0x1F: "Connection related failure (see extended status)", + 0x22: "Invalid reply received", + 0x25: "Key segment error", + 0x26: "Invalid IOI error", + 0x27: "Unexpected attribute in list", + 0x28: "DeviceNet error - invalid member ID", + 0x29: "DeviceNet error - member not settable", + 0xD1: "Module not in run state", + 0xFB: "Message port not supported", + 0xFC: "Message unsupported data type", + 0xFD: "Message uninitialized", + 0xFE: "Message timeout", + 0xff: "General Error (see extended status)" +} + +EXTEND_CODES = { + 0x01: { + 0x0100: "Connection in use", + 0x0103: "Transport not supported", + 0x0106: "Ownership conflict", + 0x0107: "Connection not found", + 0x0108: "Invalid connection type", + 0x0109: "Invalid connection size", + 0x0110: "Module not configured", + 0x0111: "EPR not supported", + 0x0114: "Wrong module", + 0x0115: "Wrong device type", + 0x0116: "Wrong revision", + 0x0118: "Invalid configuration format", + 0x011A: "Application out of connections", + 0x0203: "Connection timeout", + 0x0204: "Unconnected message timeout", + 0x0205: "Unconnected send parameter error", + 0x0206: "Message too large", + 0x0301: "No buffer memory", + 0x0302: "Bandwidth not available", + 0x0303: "No screeners available", + 0x0305: "Signature match", + 0x0311: "Port not available", + 0x0312: "Link address not available", + 0x0315: "Invalid segment type", + 0x0317: "Connection not scheduled" + }, + 0x04: { + 0x0000: "Extended status out of memory", + 0x0001: "Extended status out of instances" + }, + 0x05: { + 0x0000: "Extended status out of memory", + 0x0001: "Extended status out of instances" + }, + 0x1F: { + 0x0203: "Connection timeout" + }, + 0xff: { + 0x7: "Wrong data type", + 0x2001: "Excessive IOI", + 0x2002: "Bad parameter value", + 0x2018: "Semaphore reject", + 0x201B: "Size too small", + 0x201C: "Invalid size", + 0x2100: "Privilege failure", + 0x2101: "Invalid keyswitch position", + 0x2102: "Password invalid", + 0x2103: "No password issued", + 0x2104: "Address out of range", + 0x2105: "Access beyond end of the object", + 0x2106: "Data in use", + 0x2107: "Tag type used n request dose not match the target tag's data type", + 0x2108: "Controller in upload or download mode", + 0x2109: "Attempt to change number of array dimensions", + 0x210A: "Invalid symbol name", + 0x210B: "Symbol does not exist", + 0x210E: "Search failed", + 0x210F: "Task cannot start", + 0x2110: "Unable to write", + 0x2111: "Unable to read", + 0x2112: "Shared routine not editable", + 0x2113: "Controller in faulted mode", + 0x2114: "Run mode inhibited" + + } +} +DATA_ITEM = { + 'Connected': '\xb1\x00', + 'Unconnected': '\xb2\x00' +} + +ADDRESS_ITEM = { + 'Connection Based': '\xa1\x00', + 'Null': '\x00\x00', + 'UCMM': '\x00\x00' +} + +UCMM = { + 'Interface Handle': 0, + 'Item Count': 2, + 'Address Type ID': 0, + 'Address Length': 0, + 'Data Type ID': 0x00b2 +} + +CONNECTION_SIZE = { + 'Backplane': '\x03', # CLX + 'Direct Network': '\x02' +} + +HEADER_SIZE = 24 +EXTENDED_SYMBOL = '\x91' +BOOL_ONE = 0xff +REQUEST_SERVICE = 0 +REQUEST_PATH_SIZE = 1 +REQUEST_PATH = 2 +SUCCESS = 0 +INSUFFICIENT_PACKETS = 6 +OFFSET_MESSAGE_REQUEST = 40 + + +FORWARD_CLOSE = '\x4e' +UNCONNECTED_SEND = '\x52' +FORWARD_OPEN = '\x54' +LARGE_FORWARD_OPEN = '\x5b' +GET_CONNECTION_DATA = '\x56' +SEARCH_CONNECTION_DATA = '\x57' +GET_CONNECTION_OWNER = '\x5a' +MR_SERVICE_SIZE = 2 + +PADDING_BYTE = '\x00' +PRIORITY = '\x0a' +TIMEOUT_TICKS = '\x05' +TIMEOUT_MULTIPLIER = '\x01' +TRANSPORT_CLASS = '\xa3' + +CONNECTION_PARAMETER = { + 'PLC5': 0x4302, + 'SLC500': 0x4302, + 'CNET': 0x4320, + 'DHP': 0x4302, + 'Default': 0x43f8, +} + +""" +Atomic Data Type: + + Bit = Bool + Bit array = DWORD (32-bit boolean aray) + 8-bit integer = SINT +16-bit integer = UINT +32-bit integer = DINT + 32-bit float = REAL +64-bit integer = LINT + +From Rockwell Automation Publication 1756-PM020C-EN-P November 2012: +When reading a BOOL tag, the values returned for 0 and 1 are 0 and 0xff, respectively. +""" + +S_DATA_TYPE = { + 'BOOL': 0xc1, + 'SINT': 0xc2, # Signed 8-bit integer + 'INT': 0xc3, # Signed 16-bit integer + 'DINT': 0xc4, # Signed 32-bit integer + 'LINT': 0xc5, # Signed 64-bit integer + 'USINT': 0xc6, # Unsigned 8-bit integer + 'UINT': 0xc7, # Unsigned 16-bit integer + 'UDINT': 0xc8, # Unsigned 32-bit integer + 'ULINT': 0xc9, # Unsigned 64-bit integer + 'REAL': 0xca, # 32-bit floating point + 'LREAL': 0xcb, # 64-bit floating point + 'STIME': 0xcc, # Synchronous time + 'DATE': 0xcd, + 'TIME_OF_DAY': 0xce, + 'DATE_AND_TIME': 0xcf, + 'STRING': 0xd0, # character string (1 byte per character) + 'BYTE': 0xd1, # byte string 8-bits + 'WORD': 0xd2, # byte string 16-bits + 'DWORD': 0xd3, # byte string 32-bits + 'LWORD': 0xd4, # byte string 64-bits + 'STRING2': 0xd5, # character string (2 byte per character) + 'FTIME': 0xd6, # Duration high resolution + 'LTIME': 0xd7, # Duration long + 'ITIME': 0xd8, # Duration short + 'STRINGN': 0xd9, # character string (n byte per character) + 'SHORT_STRING': 0xda, # character string (1 byte per character, 1 byte length indicator) + 'TIME': 0xdb, # Duration in milliseconds + 'EPATH': 0xdc, # CIP Path segment + 'ENGUNIT': 0xdd, # Engineering Units + 'STRINGI': 0xde # International character string +} + +I_DATA_TYPE = { + 0xc1: 'BOOL', + 0xc2: 'SINT', # Signed 8-bit integer + 0xc3: 'INT', # Signed 16-bit integer + 0xc4: 'DINT', # Signed 32-bit integer + 0xc5: 'LINT', # Signed 64-bit integer + 0xc6: 'USINT', # Unsigned 8-bit integer + 0xc7: 'UINT', # Unsigned 16-bit integer + 0xc8: 'UDINT', # Unsigned 32-bit integer + 0xc9: 'ULINT', # Unsigned 64-bit integer + 0xca: 'REAL', # 32-bit floating point + 0xcb: 'LREAL', # 64-bit floating point + 0xcc: 'STIME', # Synchronous time + 0xcd: 'DATE', + 0xce: 'TIME_OF_DAY', + 0xcf: 'DATE_AND_TIME', + 0xd0: 'STRING', # character string (1 byte per character) + 0xd1: 'BYTE', # byte string 8-bits + 0xd2: 'WORD', # byte string 16-bits + 0xd3: 'DWORD', # byte string 32-bits + 0xd4: 'LWORD', # byte string 64-bits + 0xd5: 'STRING2', # character string (2 byte per character) + 0xd6: 'FTIME', # Duration high resolution + 0xd7: 'LTIME', # Duration long + 0xd8: 'ITIME', # Duration short + 0xd9: 'STRINGN', # character string (n byte per character) + 0xda: 'SHORT_STRING', # character string (1 byte per character, 1 byte length indicator) + 0xdb: 'TIME', # Duration in milliseconds + 0xdc: 'EPATH', # CIP Path segment + 0xdd: 'ENGUNIT', # Engineering Units + 0xde: 'STRINGI' # International character string +} + +REPLAY_INFO = { + 0x4e: 'FORWARD_CLOSE (4E,00)', + 0x52: 'UNCONNECTED_SEND (52,00)', + 0x54: 'FORWARD_OPEN (54,00)', + 0x6f: 'send_rr_data (6F,00)', + 0x70: 'send_unit_data (70,00)', + 0x00: 'nop', + 0x01: 'list_targets', + 0x04: 'list_services', + 0x63: 'list_identity', + 0x64: 'list_interfaces', + 0x65: 'register_session', + 0x66: 'unregister_session', +} + +PCCC_DATA_TYPE = { + 'N': '\x89', + 'B': '\x85', + 'T': '\x86', + 'C': '\x87', + 'S': '\x84', + 'F': '\x8a', + 'ST': '\x8d', + 'A': '\x8e', + 'R': '\x88', + 'O': '\x8b', + 'I': '\x8c' +} + +PCCC_DATA_SIZE = { + 'N': 2, + # 'L': 4, + 'B': 2, + 'T': 6, + 'C': 6, + 'S': 2, + 'F': 4, + 'ST': 84, + 'A': 2, + 'R': 6, + 'O': 2, + 'I': 2 +} + +PCCC_CT = { + 'PRE': 1, + 'ACC': 2, + 'EN': 15, + 'TT': 14, + 'DN': 13, + 'CU': 15, + 'CD': 14, + 'OV': 12, + 'UN': 11, + 'UA': 10 +} + +PCCC_ERROR_CODE = { + -2: "Not Acknowledged (NAK)", + -3: "No Reponse, Check COM Settings", + -4: "Unknown Message from DataLink Layer", + -5: "Invalid Address", + -6: "Could Not Open Com Port", + -7: "No data specified to data link layer", + -8: "No data returned from PLC", + -20: "No Data Returned", + 16: "Illegal Command or Format, Address may not exist or not enough elements in data file", + 32: "PLC Has a Problem and Will Not Communicate", + 48: "Remote Node Host is Missing, Disconnected, or Shut Down", + 64: "Host Could Not Complete Function Due To Hardware Fault", + 80: "Addressing problem or Memory Protect Rungs", + 96: "Function not allows due to command protection selection", + 112: "Processor is in Program mode", + 128: "Compatibility mode file missing or communication zone problem", + 144: "Remote node cannot buffer command", + 240: "Error code in EXT STS Byte" +} \ No newline at end of file diff --git a/Device/pycomm/cip/cip_const.pyc b/Device/pycomm/cip/cip_const.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fe3cca64475bc406bdfe2a9e28fb3ebb38ba311 GIT binary patch literal 10688 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 literal 0 HcmV?d00001 diff --git a/Device/root-CA.crt b/Device/root-CA.crt new file mode 100644 index 0000000..a6f3e92 --- /dev/null +++ b/Device/root-CA.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- diff --git a/Device/rootCA.key b/Device/rootCA.key new file mode 100644 index 0000000..ea1c6e1 --- /dev/null +++ b/Device/rootCA.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEA43N8imKnmv+NC4MfpPlF8RMFRDPZ/PpeCbO4xXpzGemBsv5N +ODpdQ+ZiKtOmJPif64vM6a/diUMnC+VyL1VMG2tmeCtLSIv+LMvV4vZzEheVPwRW +eBH5/okS5g3lkZixau8R/vAmSql5H308nCaCgTBYQUMXVGKPoD9i4sSYmzz47Hmd +2Pt8jvFT/lzacEJrIelJAReH0oAwgnWiL2oApWBClzOpcuWHq3OWrIHZ5B9JJJyH +pKNcwnzPcfybdDFOJV+T3ktfQTXq58XR/lYNMAHocV1KzcL0whINaTNM235rKXpY +WLa0IcZQey2OsqnAq7QFJGKPUVq6gKbAiK2LmwIDAQABAoIBAQCwjFXhPM6IO1CJ +3Q/VCEBH7dGqrOzJtrUDpuMHNhLdzCiGfWoG+Ranu837HCncjLflJ7C4u2+kOeG3 +FDRblUPsDKOPJ1vaRf/XWaj98PpE0tVgAsfzj1CTSGbI94R4TSN5s3QuhM3UKlQA +Iz/GnQWzrYjzr1YOhCqj4k+pYZxq8aQ8MMdsTe20ufs+fLfX/f7I5P+aZLQpZWaB +l1Ojjbi0GgvUMTOACpRpT4gknpfLhdHQZeVw72UNFX/0/+GDFFxDp0+A+XUvSOQ2 +LiSkTNdjOJwvKfVhame+pHqaMVWQToJrMrMZmiMOMLdKmMDCEw5ea1kOcILt0PwC +PaS+FyHhAoGBAPabQmM01fwYzvfa9Db2aajViqrgRUzvKyLL9ESl0+iXsvY59KVa +TIs9LkhDEH7m/2mFJflv2sR1G0CUSGXzNYa+BXt5l1FU/DPKaJMc+vRA/97y8fhE +hk1XSXpYL+/hPreUeQWy2kn1cA66pTR+CcGzwpaazlgdc5SEQArSXtZjAoGBAOwd +b9shU5lO7uDUys9GU1CkLTd/8VkKt+GLE4VwsvgB/ORDF6n1exnmt6LLhXFcxd3h +bgLfvcPkDKfYMwOEUMzZR0ISEN8wFRoRLxgT9vGE7y2yxBJbBSaC08z0yqOIug51 +kSNm4P2uqwkuT1kicE5u7nH15jeiRlUvHBqiSf9pAoGBAOqeNiAKcZdhxu8aWgQ8 +lbOyTjZaHrSeSuzVG/V/y0dbpEEMTIxQh8hlEbZgT75caR1sNv/Egl8shxv+t45/ +QCqMeMzLlsIjV7qyVKG6Dav6dzUW8EzibOACLn7+jcTsCG5CDI32ZiW9I7pvqqNx +Ujj+nCAK8kv04TSoSgHBuca/AoGBAM2jnaXl0p91JYtfCPuZLjrPoinyHksEkL24 +mNnhG53wbUaIQHXfvMUEMe9w/dmLiTEDgwKxxt5zIaqVG2j2tkCTBALBJTyc7eP0 +D2YTDUGwG3dbeHTcHRI7YyfgExR2okSxlCSXF2EZ3RBz6tugqNtGthk+prDRfhv2 +ma2App3xAoGBAK3wHxbTeBE5pgIvFpisBL6zq+ZhDyTG3tkOEZ2KcqYEHw04rZ+z +yh4TC5VekpV3YKupFt3dUNJM5G3MgpEAaWsHbHsD0hMillcpuGAh1VHRup3J5Y+y +eg+CeKlXJK5cSREeamzKfroYnj6hPe/9HKvy1L9I2DbqESs7bzau4WyR +-----END RSA PRIVATE KEY----- diff --git a/Device/rootCA.pem b/Device/rootCA.pem new file mode 100644 index 0000000..cce1aef --- /dev/null +++ b/Device/rootCA.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIUFCudUXwBqKUNreGC28n/HyRCLZowDQYJKoZIhvcNAQEL +BQAwgZAxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHTWlk +bGFuZDETMBEGA1UECgwKSGVucnkgUHVtcDETMBEGA1UECwwKQXV0b21hdGlvbjEO +MAwGA1UEAwwFSFBJb1QxJTAjBgkqhkiG9w0BCQEWFm5vcmVwbHlAaGVucnktcHVt +cC5jb20wHhcNMTkxMTIwMTYwMDE3WhcNMjIwOTA5MTYwMDE3WjCBkDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdNaWRsYW5kMRMwEQYDVQQK +DApIZW5yeSBQdW1wMRMwEQYDVQQLDApBdXRvbWF0aW9uMQ4wDAYDVQQDDAVIUElv +VDElMCMGCSqGSIb3DQEJARYWbm9yZXBseUBoZW5yeS1wdW1wLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAONzfIpip5r/jQuDH6T5RfETBUQz2fz6 +XgmzuMV6cxnpgbL+TTg6XUPmYirTpiT4n+uLzOmv3YlDJwvlci9VTBtrZngrS0iL +/izL1eL2cxIXlT8EVngR+f6JEuYN5ZGYsWrvEf7wJkqpeR99PJwmgoEwWEFDF1Ri +j6A/YuLEmJs8+Ox5ndj7fI7xU/5c2nBCayHpSQEXh9KAMIJ1oi9qAKVgQpczqXLl +h6tzlqyB2eQfSSSch6SjXMJ8z3H8m3QxTiVfk95LX0E16ufF0f5WDTAB6HFdSs3C +9MISDWkzTNt+ayl6WFi2tCHGUHstjrKpwKu0BSRij1FauoCmwIiti5sCAwEAAaNT +MFEwHQYDVR0OBBYEFPS+HjbxdMY+0FyHD8QGdKpYeXFOMB8GA1UdIwQYMBaAFPS+ +HjbxdMY+0FyHD8QGdKpYeXFOMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAK/rznXdYhm5cTJWfJn7oU1aaU3i0PDD9iL72kRqyaeKY0Be0iUDCXlB +zCnC3RVWD5RCnktU6RhxcvuOJhisOmr+nVDamk93771+D2Dc0ONCEMq6uRFjykYs +iV1V0DOYJ/G1pq9bXaKT9CGsLt0r9DKasy8+Bl/U5//MPYbunDGZO7MwwV9YZXns +BLGWsjlRRQEj2IPeIobygajhBn5KHLIfVp9iI5bg68Zpf0VScKFIzo7wej5bX5xV +hrlX48fFgM/M0Q2zGauVPAiY1aV4FctdmfstEjoaXAlkQQUsCDTdpTjIPrnLLvd1 +lqM/pJrHKTd2pLeRpFEtPWWTJt1Sff4= +-----END CERTIFICATE----- diff --git a/Device/rootCA.srl b/Device/rootCA.srl new file mode 100644 index 0000000..4b9fea9 --- /dev/null +++ b/Device/rootCA.srl @@ -0,0 +1 @@ +58D1EF99EF1B2A05A529F4605B77619D1E8D9EC6 diff --git a/Device/server.conf b/Device/server.conf new file mode 100644 index 0000000..062bf00 --- /dev/null +++ b/Device/server.conf @@ -0,0 +1,14 @@ +[ req ] +default_bits = 4096 +default_md = sha512 +default_keyfile = deviceCert.key +prompt = no +encrypt_key = no +distinguished_name = req_distinguished_name +[ req_distinguished_name ] +countryName = "US" +localityName = "Texas" +organizationName = "Henry Pump" +organizationalUnitName = "Automation" +commonName = "f52c9bed0997c8f92b41bc085c20b0eaa47fbfa8f78bb86310087a24a8721401" +emailAddress = "noreply@henry-pump.com" \ No newline at end of file diff --git a/Device/start.sh b/Device/start.sh new file mode 100644 index 0000000..4e42f8f --- /dev/null +++ b/Device/start.sh @@ -0,0 +1,39 @@ +# stop script on error +set -e + +#for M1 if no openssl then opkg update, opkg install openssl-util, opkg install coreutils-sha256sum, opkg install curl +if ! command -V curl > /dev/null 2>&1; then + printf "\nNo curl assuming no ssl tools, curl, or git\n" + opkg update + opkg install openssl-util + opkg install coreutils-sha256sum + opkg install curl + opkg install git + opkg upgrade libopenssl +fi +#for RPi +if ! command -V git > /dev/null 2>&1; then + apt-get update + apt-get install git +fi +# Check to see if root CA file exists, download if not +if [ ! -f ./root-CA.crt ]; then + printf "\nNO ROOT CERTIFICATE\n" + curl https://www.amazontrust.com/repository/AmazonRootCA1.pem > root-CA.crt +fi + +if [ ! -f ./rootCA.pem ]; then + printf "\nNO HPIoT ROOT CERTIFICATE\n" +fi + + +# install AWS Device SDK for Python if not already installed +if [ ! -d ./aws-iot-device-sdk-python ]; then + printf "\nInstalling AWS SDK...\n" + git clone git://github.com/aws/aws-iot-device-sdk-python.git + cd aws-iot-device-sdk-python + python setup.py install + cd ../ +fi + +python ./main.py -e a3641et952pm28-ats.iot.us-east-1.amazonaws.com -r root-CA.crt -p 8883 \ No newline at end of file diff --git a/Device/start.sh.old b/Device/start.sh.old new file mode 100644 index 0000000..5014137 --- /dev/null +++ b/Device/start.sh.old @@ -0,0 +1,36 @@ +# stop script on error +set -e + +# Check to see if root CA file exists, download if not +if [ ! -f ./root-CA.crt ]; then + printf "\nNO ROOT CERTIFICATE\n" + curl https://www.amazontrust.com/repository/AmazonRootCA1.pem > root-CA.crt +fi + +if [ ! -f ./rootCA.pem ]; then + printf "\nNO HPIoT ROOT CERTIFICATE\n" +fi + +if [ ! -f ./deviceCert.pem ]; then + openssl genrsa -out deviceCert.key 2048 + openssl req -config server.conf -new -key deviceCert.key -out deviceCert.pem + openssl x509 -req -in deviceCert.pem -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out deviceCert.pem -days 365 -sha256 +fi + +# install AWS Device SDK for Python if not already installed +if [ ! -d ./aws-iot-device-sdk-python ]; then + printf "\nInstalling AWS SDK...\n" + git clone https://github.com/aws/aws-iot-device-sdk-python.git + pushd aws-iot-device-sdk-python + python setup.py install + popd +fi + +if [ ! -f ./deviceCertAndCACert.pem ]; then + cat deviceCert.pem rootCA.pem > deviceCertAndCACert.pem +fi + + +# run pub/sub sample app using certificates downloaded in package +printf "\nRunning pub/sub sample application...\n" +python aws-iot-device-sdk-python/samples/basicPubSub/basicPubSub.py -e a3641et952pm28-ats.iot.us-east-1.amazonaws.com -r root-CA.crt -c deviceCertAndCACert.pem -k deviceCert.key \ No newline at end of file diff --git a/Device/utilities.py b/Device/utilities.py new file mode 100644 index 0000000..e69de29 diff --git a/Device/utilities.pyc b/Device/utilities.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0639fefacdf99e40366cbdec4da08a4e76db2185 GIT binary patch literal 1323 zcmc&z&2G~`5T3OY=clcND%2`BLlH8UTD@_I5ET(np$25PiUhQk8*jnM+M9USr9sK5 zya8w4hnL~R3otWHNuL0s?09~@nVtQ1*8RQFR%?$>hp_w!{65EJwos%1-vHjDB3KcS zIuHjghK2-maFOu>m+?_pfDGVTz(T+rV2%j_x)u#V-Z-F)KH30>tlJu@X*RU>9x7*5 zkte13oT#(QL{)MHDRe4tu!&6qgaQjQMlH+>8xF%`BTEzZv!V76rP75Ad!?S7>nlHa zEsJvIzpL`elW?W``<2ysVl!R%M>5I%ms+K=4EG1IfAIDw?8(b)D8tHTDzlk1yOWvS z#{E`Jrn4f+b$Wg_GPzh_yE-yt5O>e2-iF5zyce0VbtOs z8dMDbVtODLJ>7u;(Gs+f|31&oxz>u6qEd>7(6B66?y}5TDxSP(4O63a6hRvWr`p*> zMs(H4Cl0%nxnWJ|FS2ArA4ku+7&Nxz(1p^8WlvVvh+Y7a50FeIvPc6Ok%-`o7|R*w z@c2jcIJhRd_c)3Ddl8+91JuC(dk%b<2KHi}q5!ceYEB2Ie_hn>tWA6kZT5PigP4a7 odF~^|6B}Y%^l!)}KDprPJgoimH%>Rw#b;e9`HUYmU0KWf1Kz(9!2kdN literal 0 HcmV?d00001 diff --git a/Diagrams/Henry Pump IoT Diagrams.drawio b/Diagrams/Henry Pump IoT Diagrams.drawio new file mode 100644 index 0000000..5a4039e --- /dev/null +++ b/Diagrams/Henry Pump IoT Diagrams.drawio @@ -0,0 +1 @@ +7V1ZU9vIGv01POLSbvnRYDxhKtRwk0wy975QstS2NZHUGqkFmF9/v960dRs8ibwQgCqwWi2p1ed8ay8+sy/Tx9+KIF/f4AglZ5YRPZ7ZszPLMh3Dh3+0ZMNLfFmwKuJIVGoKPsdPSBQaorSKI1R2KhKMExLn3cIQZxkKSacsKAr80K22xEn3qXmwQkrB5zBI1NJvcUTWotT0Js2JDyhercWjfWvMT6SBrCzepFwHEX5oFdlXZ/ZlgTHhn9LHS5TQzpP9wq+bbzlbN6xAGdnlgvP//E2Kv/98+jS7uvn0P/dm7uMP5+Iu90FSiRcWjSUb2QO4Ikmcocu6g40z+2KJM3KJE1ywOjb8zulTL1ZFEMWoOZfhDNHqcZK0q4/H0INQXpICf0e9ylFQrlEkHnSPChIDHB+DBUpucRmTGGdwboEJwWmrwjSJV/QEwTmUBuIohLYguPfFmqQJHJui7YJopiWPxfvSRwZlzl90GT/SdlzkOKZ3ubqHm5XiJoBmTi9IH1eU+KPgoXRGEcbFXYLD71BBhUf2NTQYPbaKBFy/IZwiUmygijjrOSOXXyOEx/IMWfLQkHEsJGrdoqEsCwT9V/XNG4bAB0GSf0EY650wAxImDIo9UcV2veMSxX4nyqBESVER7IkrjmseW60472wZkC0ViZOYbIahi+m5fd1ieMfmi/vOlyG1C14uEbrLqSs6DGW8vooxj+65eO+UGZAyCUVsUSWLYRhjefbp+brjd8YMyJg1rko0FFvMU3N3/XeuDMgVskZFiksSDGSQVMKcgM87UShjKpwpcJVFDEPaVw/rmKDPeRDSsw/QXT08uuQwjPHlxWwbOXrEm7OfHog9kGkPD4KGpSh7U4eGY6ho2HtLbKjaXhXhXxIOx+/DYTYh4tHgUBWq/TbgGLuTkwNDVVXO2wDDd42unzE5uqKyDQUM922AMZ709JTr6xIRh0VDHUHx3gYa9RDdRvpJ9pGhUMcmxm8DCn/Sz7d48tWPBYajulMfUMYafVul+ZnlJdS3XxTwadV4+S2k4N1JF44ClfFTsKjjCxZOsIa7F2cuBSaoCEQ2T7KrZfCSoCXZGuGUAH+crb7Qg9m500XI1sRoBvtRkP15GF0FRZ3lN30NjhLb4XFU/bBrGsNliEApXsKfL2vovhI+zAISwL95gh/oURxARJeeJq4saN6G6z6gNE0dlpYOS2tvWKpu3FUWUajQfQwq0Jp/RlmJi/IVYja0LPr9QTK9G256ewLw8+XXmy8X3/KP9+Tp9+v1k+kmN7vM1qAZptpCyRkr1va8jTMQ361+d9kTXXcZuv4y99VfqkMg7Q4QLZOWR6gtYFWCQoILWQce2a52okLhHFAoHKcPMwiAFuZDSoWlisX09hoKfgsIegg2JwrcIbWZEjl5tqXDzTwobruJ558lKpg7UeYJBfNdOLcGAV2IfVMBeLInfMd/fH1yHsbZ5PvT1e23zblzcXG5ywygJhoz/nU0djW9ml3NNAHVtkBMG7UldDjkIgi/r1hbemcHgMU07S4urgqLa09UXDyZBxwcGHWyzWsYeDgAUp7ZRcpXkNpXDK3FSZ3k8pwEvV2cTMc9YBpQC5U6ueQ1jFYcAiqr6y82Q3/HgkpNTL2GsYzDS5U1PjpUau7pNYx0HB4q2z+6AlRTS69hGOTwUDlj47hAmerw4WsYJTmC96dx1A+LlBpAiVRVTLPtK5ShIiCAEjybJuPJGsFfxDK6kcjoGoBduIb/IY2VjQUtCrINoSl7+LgscAr/biE2LquCnixlBtggmEbdRXyP6qPLpCoJYmfXQbbi98DL5ZkYCbgtME35pyzKtoyPeBWH9DLAsqDZtaIcsWKIotmjSJXLt4lQDi2n8MG9aFNDnKZVBgE3m6cG4BaY4BAn7AUiVoHl6/hZ6PE1jkYKkdU0wEBR/fN81EnMEByF3y5HNRGKo4klx+N9cVS3cGNrijVsUqzyc1kTN+J1BCUbHnK027SmpWnwndMvQmFcAglKSZyHNaLTB/v3ZSxbAtHX7G64Wq0lrUt+c96sRk4YQ+D5CWBKeat5iYeYdRE8iFEU6ECXk8o2i/uKBtzH9O/Nf758kc/l7Zt++wx/r/EXJilMCPE9az97GoBQJQE9THGE0tGPJ8BeOfOVARl91OdqVLTv7ov+unUoKv0F6CloWc4PRkboZlS29DcnAqeOYBR0ZiMgRZVwBb+iYzzvNJARpS6TraWBvTctqFtbotLgUxdAI6/Y/OyeomKqIWiOS8KVQlkxQx6wkfZNFqR4diG1VgkvQj8LxUevXAQlLSKbnCmvaeMhlAGrTGL2LyaSjyW3vuz5XB1NsyDZADvKdquX7ImBOMUtM+jkEuhCH3T1CG8cCQ+A3SsNwjW/NEFBkXG1HeR5Iow7cwpu65vQKxhmQg2noA2jrspE0appSYhLwt7qnk5DGOlmlmhF5XrJXoNp+KBIz2pHhIB2Ry0hpCB8DNJFxMxTlUmfQwhxTGLhhbEWxhk0K62bCu9Z4LygVeCoKrn3FKcpimhZsnkDPovdFdixs5u4mvU+DoPLq25ljyqvvVFEae0XAsmoEYaw4a6QWsYQ8GWYSHE/oE35njx/QwteoZQSneJFnAgClaMva0Y20YAgKbFsx5rNteFcq/hIGXdh2EqLICTsMrLmlWKmHWonarHhYh/xpitmagFcYRcW0l1izxH1Lmh4V7xdh6Tritu+ZsadjtbjvTkjujVIW31x7g+DqmI8BrZQSrElOHDiktJoHRREfOZOyX1QxLgq24aGD8rWASKjZA5ONl0t1FPagp1xJtUu15QgD/eNy4yCMk5oNxcoEEZkTlMRBVhBHDFjkmWMdMZ1hIKE1SUd6eAxbsneAAW5lMUFPIBDI87mGESWm6mARxQZvVkIIS4AwtR0ghtx5VJVoBQTHlcjES8XItJmbUjiFOhGA1HjT6EQhMl6jEvCCx6ksLP7iaChBULQE/+zxiDCC4Pwclsibf6yfkaEH7IEB9FZHUXx8riZsMd7OUXsZXAmuo9Wyqp0wd86Q6w1Oc4h8CDcrHtBSgUnW5T5dov61kRemyHSWjJzbzkiNe+qtWQstLjEK/BWcE9UOtKZ4JUQ0KgpBMkAhqZI2jI2c4JS/AOXgQdUy0fFnM5GURQ4QU0Qn2MwgHGTTwp5Yqh5EjektB3oHiXNhSVaFWjFeR/iNOeieg+B/4LtdEAbI2xkucZVwswtt5IgMsxEVvVT1wFTOGGB2aOa+1E5AQ0o3Dtu2qXHBnzDMuPFvdqKbkKVNC2C93q7trDr4mmT3Lq8lFwy8DNy8funP7IPf23S3z/6N/N4san85dc6y93qcxo0yAwzLsgarzDEMFdN6UV3NkpT5yNmHU5h+hsRshEdTqcLdUEsCZjMKd11DArCJAADE8riORU5Xm1rl5e4KkL03GvxenC/FSLP1JOjzyxQeg7BAiXcALebMTgamvklp4MGKDS1EhQeFjBraMDEpbdUVzeiassZYLXX2pv9xVsqrurBXjfjJ+RSMVefgjIHx4OvDInhpjdQZ/4HdzB7pHlfQb/zCvoYkzuZoynvwJeHLkuGUfeOHPGSHDJVbe97Gi/I2Je2V2cFHEC9/LhSsHZUCs5pKXFFdOXIBdUvnZzAu+D+uOCm/xByVw92DrNu1ukqfctVBXZfO19oqaROODhpeXV2lFdvLzYcnBOWfZQVxLz1rSZ+4vfQ9idtwF6uL5zHBmDegkH9gMmvyQD/l2CA7Xj7Z4A6cYAOj9FQ+0qMNL3bkB+1IWykeKCV5S+bDkfj6+3NdMhF/m8vlPR21EFycOvISsg0rWftyssXeKbx/AW9OKRXfz9qSx3pn9WD7e8Ka5holQ6h3vFpD8PkJ40es0xfHYJ2nQNqMc2mCv0JF0OSCc55xtS2x61zs7gQsycpfwraDTuyDc4s2c8pUk5vDxHXrtchbQ9dCco/PUPCPTHPNtRR4oOGXnIISzNgtOSTFRrSef9UWJ445wtjp1DBdPLH5mR/ls2invRWTyO4ZhPdWmMjC83UHP70k1vNOwAJxm5vAoyl7lVa276hV+bqSaBbmtuDbxhWSJ9+WpZABz6EuAVyHTt+JRr4TncdsO1pFuDrFhjsjwbqEp2T9KWFe9M40s9u0vPymMyu0fzg+ddBonnHf94tfiH6349brFkHMKWzKod3ZOZj/8pw/p0jMzPcS3P8ZhyZhE9WHciDMbpRluOok14O68EcJXcIPVhs/hLXs4P/0oORKw9nj+2Ts404OoXMgcwIvJw6OI38pWv0EgGT5zVev/7YOoDGs44ywwQ9xuSv1mdOQkseNiSkB5vWwS0qYnhlqpZeHy+tk6Cl2cuFyg12tuanevXdF2g8Nn6uvn2I/Jd26vwuJn7fBlZjL+1RkMd3KzF/X/UKJtOxY27PvQ1gPSfKvluexnrWW6i17edkX5Ml5I7Fx1FcRkdxjd3nFZc0urUF3s3osqOT1Hj+rhpvMrTK+zmfS01YzunalnO+fyhfvjKlU9XnN3LmOjvsEU0KaZyyr11tE0Qv8S8qii0TXtuuPXvYVPrXWmdbtGe2JoR+r+yU9pY1D6PMHMXgYC9jugRhFNI59XO+wGdOy0uaxID+P19UJSi8sjyXpSb9/oL5gn7/LCrO4WiU06nDP59LkjuF1fpEk0SwNO54XTj8vCBdRnEL7mFVJJuLAuCi7H9pY4nuLhTLJM6/CgDp5w8vSePuvWr3Q2ZPHeXUJujcfaVmJFrvQc7Ok+rsXVXriU2r22GbxC3jaPzrpBXnqpNr023B0nWDXIP+SlXa0rG1l/WD3prWDVRcuL7fhpfLOEQjsUhxxDY9GEbKXW/clfKxunuGbhTQdvYF/VHmwZ2EsO6agj2NyM/rpe4t/wCRlqWmVBW6qCPuLacXnhHnJWr5wboFR21B3KJQOsMhduMu1W5TnIJvM09i8ALnQUhxuItYVhbTTp/L9Yd3YYKraFTer4YRaM/uBcCObs9x7U4Q9bf4DC/U6oq8j51FdWI/45vWorqTjZ9DsWJQMRrTmef7F3uNnW23v9XH2BjrvrPvwOGzun/angbQe4s23+jouWV2de/YU79maKj95s9oVEtBafQ4lYUb8EFojf8D7Zdtb9owEMc/DdL2olWeIPRlodBNYlIH2qa9mpzYJF6dHHMcHvrpd04ckhBawVamaVorgf335fxwP9+FnjtOtveSrOIPQJnoORbd9ty7nuPYnjXEL63sSmVYCZHk1BjVwoI/MSNaRs05ZVnLUAEIxVdtMYQ0ZaFqaURK2LTNliDas65IxDrCIiSiq37hVMVmF32r1t8xHsXVzLZlRhJSGRshiwmFTUNyJz13LAFU2Uq2Yyb04VXnMph89Z98yhYk+Ezn8cfZ1k+uSmfTcx7Zb0GyVL2u60Hpek1Ebs5rBhFPUfo0n+HnGwiWeRYSxSj2gh1+SEa5xEi9NaeidtVRM4onb7ogVQwRpERManUkIU8p0wuysFfbzABWKNoofmdK7QxGJFeAUqwSYUZPPAlzYhnkMmQv2LkGSCIj9pK/fmmnN9igypzzPYOEKanPxtyaK+u633duyofMvbHNtZFMEMXXbTqJgTzau9p7fwCOW61NYLnMcK2NSGOjsYhaKuJ/Bgtuh4VOhCFXgqdsvL+rOoxLSNUYBMjCxsX/qZ51FElCOavHUkg1A0suxDHzTEl4ZAfGlGTxnpc1k4rjzZ6RgIkHyLjikOJYAEpB0jC4FTzSA0pTNSKmF+JamGzzpNduYLOdqm/2q6ck2arc6JJv9TpGKx0OJidrdJYZJ5gYVvqBZBvpHHpNNpl3HQpeMHomsnoLbHsKZDdOiy/XZKlNneR8g1zcyG/+4HniWkCdS4/3n55XpCeBgAv27eIQeVYLImfYgcizj0A0vBBEww5EYyJEQMJHdDc3hacuTlgdHOsOgxwAkfRfKEjnFxrL8bx2DK3fKzQVN34bDbvyW7koi6Z5qo77rZRk1zArkM+en8cbHp9n+mv22ChX8MfLZ7/LLkQpLxitXqoe9Mvqq6ZFHJv2Pd+7aYzdFdekzG6pZrqbN8e+7drTTt7EkWXx9zcmz6OJUrLyTr0P9XpG2C1bB8XYRKJwUr7EWxfMqv0DRgf+abX5UmnV76B5m2Omk/yJFHF0rDn7kbMM78VA6HITSGxFdeFp0IpHoNqBPFp6m7wZqQPDITMJp7TIypuYK7ZYkSJVbjCMnUx9sXrYP4jckYJodSN3mBtPiBx265+OZQ6qf4C7k58=7VpbU+pIEP41Vu0+QCWZJMAjEFG29Bxr3S33PFlDMoRZkwxnMgjx129PMoHcULCIelzVKjI9Pbfuz/56mpyhcbi54Hi5uGYeCc4MzducIefMMHRT68OHlCSZpJ8LfE49pbQT3NInooSakq6oR+KSomAsEHRZFrosiogrSjLMOVuX1eYsKK+6xD6pCW5dHNSld9QTC3UKS9vJLwn1F/nKuqZ6QpwrK0G8wB5bF0To/AyNOWMiewo3YxJI4+V2ceyrp+mfYZQQmw7mvr6h3qKTTTY5Zsj2CJxE4rRTD7KpH3GwUva6vJmyv8bKGdm5RZIbk3hgW9VkXCyYzyIcnO+kI85WkUfkkhq0djpXjC1BqIPwXyJEooCCV4KBaCHCQPUeeFZlk5ituEue0TMyPbnxAh6UhS4IC4ngCSgovHe0rmbqvWwQJwEW9LEMJKzw6G/Hbqe7YRT2vJ3LRgo4Sf4foXWt8iQCc58INW7nuyHnOCmoLaVCvH8lS9+30uS1I+Ah20VlfL4lNp/HRFRGFCy6E6UwPAbtvWZMXhDhYIFHyRVzwS0s+jzozGDw3Hz2gTA+GLIlrx3rIqPmoeHNFAQXWJB1itw7MouZ+0DqIYStREAjMt6Ge+mJOYvEmAWMpzoIfidyOyOfY4+SUt/AtJyJUehzKIeJJB6QE0mXyvloEBTGWEOkjSyQx4KzB1Lomac/0OPheLEFxiPhggKFXOEZCW5YTNX0MyYECwsKw4D6skNI+IywarmwK8LLwJEnVKjSjbytrCKXxPEyM8ecbuQ+RsA2S9kZbnxJzF28js0uJxmkpq7czwia2VNZCy/pva9ccSxk5cnI5lmMqV7Ut0shZDDIo9t6x7OWgsqiQLG57OSwtGqwPDNM9/2ojGyo+EcO7w5sS7V/pG0N5W1no+ZPG0mhcUM4BbtIIKWyE4cedGDoOZJA4Ww94zX0eSzn6RaqMFj/Bc6rj/g4nFeHrv8J6Q6dmsWaHY36vbKj9bYSr/0rNULqVHBBDYHuEJptm+QaOAt1QxzBHSsE9XuIxTFLkVkhaMdwkIMaCD9iEWmRwwblLLiRwmxUp7BcdnIKM38pz7IZDci9G9DULR/FqegAp5rbiPAmbrUb3GoH0mbxEkcl/9o/V0yoBLETp4F5CAq6vtzAR2o2bb2ggnRgqKt6I7YGt2z7Z9h98NPg33Ezm0sl7s9+MyxLahlwDK3y/PtubXjy5ec6jtOhE/nXG0Fe2YFj9pwu2RB3BVsASRc6OPElwqADh/gJGGYdd11AWjoqFrJC03PyE4M0O3S2Rg3f4GVRAV8pa1foKYJNiWoAruI8pJ6Xhp/UgLeZ/ZzUdFWybAucVXTaqBGddWzmVaiTY1Ovs8lyJe6ngoADNRVmwL1TD6afemAPKpJPkIzoeTXyxcv38TUk8Kv+Fklwr78n1r1/RqvXUHUYkx1aCmgIA5JzNGus9/bFjA93yU/9S/j5I5Fu3ku1ZjfA4czD9/NVpEodrQWoatWy3xSgkF4PUKitalP+/7enSA3miE8LLegznR50Hldlgh9zNPjfVJm8JMIh82YtYrFXwaKxu8gVa0wNbGm1xpb9Ghgle1SJMkt1ZjzPcgAJhvae5AlZGBdD+X2ahE6A45i6uXhCg7Y41m6RY3uv49i3ZME8aSugJXbThH8mDxOo0o5EzBckqoqDAyHRboplm+UytzF46bu1F0e0UxQy6hlXsC0dah4WODu1of1x+/3bewAOAMSTrCBu5c0fxb5dMTxtJcVWtRxeQq/K74rQbaFkfjB026lzHo3c6vfPA+1Z3Op5it6s3w5q9abSyNc94de7J+iG9e4XhT1vszhp7Pu6IXzCG4KtWSUUIvstbwjkDq9+Xo/53fV3lkz+/obHl1qnnvJVXo74kPXOAi4MvYKLQ98/O75Sb1YYR6u5Trcb6vSvqIVCc/emXkZeu/cd0fl/5VpbV+M2EP41Oad9gOM4XB8hgS0t29INlKUvHNlWYhVZ8koySfbXd3SLL3GCSQPbPfsC0ug2M5rLN3J6g2E2/yBQnn7kCaa9MEjmvcGoF4b9g+AE/mnKwlJOPGEqSOImlYQx+YodMXDUgiRY1iYqzqkieZ0Yc8ZwrGo0JASf1adNOK2fmqMpXiGMY0RXqfckUamT4jAo6b9gMk39yf3AjWTIT3YEmaKEzyqkwUVvMBScK9vK5kNMtfK8XsJbfsweBntffv1jdjr9/c+Tq4vxnt3s8jVLliIIzNRutz60Wz8jWjh9OVnVwitQ8IIlWG8S9Abns5QoPM5RrEdnYDJAS1VGodeHZkdOnUTPWCg8r9yT4/wD5hlWYgFT3OiRuwNnhAPXnZU32j91tLR6m34dclY0Xe5cagoaTlmvUNzpip5wAnbnulyolE85Q/SipJ7XNVnOueY8d/r7Byu1cE6ECsX/i3YlL0SMN8w7cu6IxBRv2s85vBZw410JTJEiz3XH27nmj1pM9ogqrSk48miqW2OQSe3L1I/AQeWgJ+aeMExx/CRNcBE6EoFVkgmJQRbONBmxBP5GBaGJ7qoUZ1awMGAYw43uV87J1x7zqWBuuYkuhOm7FHwqUNa+vmFg4Cqqbg9SCf6Eh5wC34MR40xb2YRQ2iBJ8FfCpkA4LHu3xuj2wnVezcE7J9QEvJQkCWYrFvxOzn7Q1dnDt3L24+8kSg6OXwyT4XGL5pbEnWuuf/gt4iSeE/XZLdfthwp9NK8MjBauI3XAONNwo+I1mnZJtMBbmPuL0XfnUdUtveEE+FvaxNIIvE00vcSGf7eqvG5QBlpUpuV6glx/TtP2ACjW4cgLfDXmQ8NyUNreUifbm+NJh9zhKRAmmad9hGi9ny8qYbo6ujHLrNu44hJHXwqNIc8nnKk9aYz6DCb0w3zeC63lBWZs5nxWjx5onOpX+iMuwGYjSmSKZS2RYWNHUwIJw2S1bQRJyPO3k8QWB4ZziGYQzMLg7H4Mf6/47cvCtLD+vtL4IyLRwt1WTA8FhmsF3Qy1zU+WUMQSpphhQWJdtuFnEmOrwgmZ6slayNHovNRk3U6uRh7cQKhTpGEu3VTZKufmpSM+Y5SjRNZ5nXCtZMEzz/Tbc3JpUCBGcVrVn1HbkjGZmz6yEC7GUrMtCsY0zPIYLxEQtkWJ8gAmBkO/AygXQTjDokSYDSs34SzCZq6U+mqBCcXXbu+vbQaBcH+dtD8qptwaGr1ZBekfSP73qLJZe4erqhsMWlR3/Haq67eorpluR8Y96ll7QxF47WLPnSIUgh6W9ZXry7qzOMa5qoWtqm932KENcTRq0pvrYfWABCn0QgZpDXzrebiamLMKE4ggvjAbz0waoPHySGCB0mYmbpU7+MnyfHVjU5JCU/lzJ1Yaon/kSVTIDdJvJVTmd329XIBM3MvAcAmrYGgr4YaFMO4aBqa42bGQK7tvIWyMqM1pvgAwhgjEyENJN7KV/H9xqvQD7tvIv7L7TuTfXvh7m9MTbqI8UoW1REYUF/YQ9wJlgYBJ+RaAdHthsh7nkEOKnrGHKA6VYKmaZ1ghLDManzgWEZW85M2YuQ2PdrF25hK2WNiMmUUopZpRxAtlLoXI6iEdJFk6vROmyojMwflMWZAb+OP8seehq+FD4JwLVdVzbXI3Llb8Z4Ubg7xtGgLdIEr1SRHWEMeqXqXAcKo/WujvHiaxwY5kYkprzTOR0ix2ZuignUOdHXhcsfEd8bhDFp1NxTzLCcWl/1n7trbikK1uSrBWMy0DWG1Fs3fqTAxZJ3I2pm+HM+MhwcjS3DxhC6Qaks4Qgx31aIqF2bkNMa8XZVxEMhbE7GWhOM9JLEvlAFLnMUFWtriQylQuEDJohOIn2AZlGraxSOadU3OWU5xZO1zZsfTJ8YLFNjp/whIr34z09ynTvssTU+Hp9r0AKPmo+KMJGTWKdz1NhDbYwePYB0FNu4HW4zUHUjv3P2qF0QUme1oNJvv37d3D5PA7qTAOuuiu36K7weEOdHe5d4SiZPhwd5ox+Vs0Obhlf+8FK5p6j3drBqx/rnb0y3WwHx76fvl6bXqtz9cxhSBE4l79Bbu8v8aL8w6ftPuDXrcviv2g3R7e5wuiZ3Nj+bimDtxQQd7ZNxobjRHT8jwRk4n4xCISlxYUkk/7W6WCW64gEn+tYkXFE/1OryPzAutCZNkFBKBTkm6CRaiS0iXPLWFvo065LPEGNXijy4dPl4QCcBBFWDfQMOYTNUPCvlybfPaq5Sad+SRtktxrF/k82GGdz6zLJ7nLwlvP69aXamdFFq19P/hRU+z2eaL/+jwB3fK3PfYDVPkLqcHFvw==7VvLcpswFP0alvHIkDhh2dhJ2pmmM520TXcZGQlQI5Aq5Fe/vhKIl+MQ20kdPNXCAz6SLlf3HPQAruONk+WNgDy+ZQhTxwVo6XgTx3WHp+BCHTSyMohfIpEgyGA1cEf+YAMCg84IwlmromSMSsLbYMDSFAeyhUEh2KJdLWS0fVUOI/wEuAsgfYreEyTjAr04AzX+EZMoLq88BKYkgWVlA2QxRGzRgLwrxxsLxmRxlizHmOrolXFJ4p/fr75/Hp/4EN+L25vPlz/ASWHsepcmVRcETuXbmvYK03NIZyZepq9yVQZQsFmKsDYCHO9yEROJ7zgMdOlCaUZhsUyo+jdUp1t6ano0x0LiZYMn4/kNZgmWYqWqmNJzw8GipnDkGyxu0gfKmtDoJqps1bFRJyY8O4TqdEOoRlTq/ivfR5E+G7M0JFGJq8vURSXIK+BcYzDREUynGW/UUQ35erspZcHj7xmTuEXPSEOqOIEiIqnjfVCloPE7BXypDrkhMGUCYVFUSlmKqwIOESJpZJrrFqXdZ90PFHckJAHMHfo0MW3d0Aeu5wHfDRMX+Epf465eVYCSQkaY6cDwhVYKa4aj34FCeE4CPCyaFKQfdcd64kYVO8i5tgITXLSKOVENXiEgS8IeowFLOExXRRM1Jy7SrzOcWRoOTINyB0o9jDZviHtCH0ma5ajna+DutWOs5WZ3bkKC9dJ1nZEvTKgVjeXiHeZkVV2uuLlLrgXOYs2NWtAIdbxlKZFMbLt+0cuhahHkwyz8BYGfoV9hcbAEH5ZgTgNVF0EJX7/usvE/NjcqfiWM3mDhbdVh3fiHIi2BTK2gG+PXA+FmN+y7g+HoYjAc6GdqzXmk2cKq27rxoqzUeFiYCJPhQ0jZ4kHkz2+sqKwb2+3zY5hG+FusF8us3M642y6SnfPJOyjKyu3Y3Hj68FvYEaknbnTOL/kNftjJpCdh6YkbnewkDE1nmfP8vtiy9V+60SmaKZwhZSBfJ+am/BGw25D+ktkTN7p3t1AQuWrat3Kybuwtp0wyri9DZGaemFhB9ZbJnrjRPedVSrrYT0ndox+j9CGjGJvne2dWrb2VSU/ceEFPJJUbX3NYKVk3eurGCxN68RVLDydzK3jrxtsLXuCIZLK8gjvad91hRW/d6JMbnaKvv70KKYPSKv44ObZubK14itNIp69seGlq9X4sDFs3ttZ7/Q1641uTt5X8zm8fN75K7r32n+z33Wq/PxgM2t9VPBNXOzK8672w96vxTqvBTOSpluvvdP/JxeaMSp1tu+liB5zI/l+2i7SF3W/93YLPW53YZGQtQ1jipcYbacCZFOwRjxllKsaTPMA6AYbSNUj5G+TRnpzV/74xroCTnJFN6cZsjoWeTxQSE4Sw4vqynaR8yCzkU7ApCxmAnbOQ1d86lzwvu6lT8r2rvw== \ No newline at end of file diff --git a/Event Formats.json b/Event Formats.json new file mode 100644 index 0000000..eb29c8b --- /dev/null +++ b/Event Formats.json @@ -0,0 +1,257 @@ +///////////////event from $connect + +{ + "headers": { + "Host": "3fseaywb8b.execute-api.us-east-1.amazonaws.com", + "x-api-key": "", + "X-Forwarded-For": "", + "x-restapi": "" + }, + "multiValueHeaders": { + "Host": [ + "3fseaywb8b.execute-api.us-east-1.amazonaws.com" + ], + "x-api-key": [ + "" + ], + "X-Forwarded-For": [ + "" + ], + "x-restapi": [ + "" + ] + }, + "requestContext": { + "routeKey": "$disconnect", + "messageId": null, + "eventType": "DISCONNECT", + "extendedRequestId": "BP2ynHbkoAMF6PA=", + "requestTime": "08/Oct/2019:14:34:31 +0000", + "messageDirection": "IN", + "stage": "prototype", + "connectedAt": 1570544607717, + "requestTimeEpoch": 1570545271055, + "identity": { + "cognitoIdentityPoolId": null, + "cognitoIdentityId": null, + "principalOrgId": null, + "cognitoAuthenticationType": null, + "userArn": null, + "userAgent": null, + "accountId": null, + "caller": null, + "sourceIp": "172.85.171.82", + "accessKey": null, + "cognitoAuthenticationProvider": null, + "user": null + }, + "requestId": "BP2ynHbkoAMF6PA=", + "domainName": "3fseaywb8b.execute-api.us-east-1.amazonaws.com", + "connectionId": "BP1K-fcGIAMCK_w=", + "apiId": "3fseaywb8b" + }, + "isBase64Encoded": false +} + +{ + "headers": { + "Host": "3fseaywb8b.execute-api.us-east-1.amazonaws.com", + "Sec-WebSocket-Extensions": "permessage-deflate; client_max_window_bits", + "Sec-WebSocket-Key": "f+6+XKW6s9NvhAudLgT0jg==", + "Sec-WebSocket-Version": "13", + "X-Amzn-Trace-Id": "Root=1-5d9c9e78-4525cf6933d7050d38564f07", + "X-Forwarded-For": "172.85.171.82", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "multiValueHeaders": { + "Host": [ + "3fseaywb8b.execute-api.us-east-1.amazonaws.com" + ], + "Sec-WebSocket-Extensions": [ + "permessage-deflate; client_max_window_bits" + ], + "Sec-WebSocket-Key": [ + "f+6+XKW6s9NvhAudLgT0jg==" + ], + "Sec-WebSocket-Version": [ + "13" + ], + "X-Amzn-Trace-Id": [ + "Root=1-5d9c9e78-4525cf6933d7050d38564f07" + ], + "X-Forwarded-For": [ + "172.85.171.82" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ] + }, + "requestContext": { + "routeKey": "$connect", + "messageId": null, + "eventType": "CONNECT", + "extendedRequestId": "BP2y0FsqoAMFQTA=", + "requestTime": "08/Oct/2019:14:34:32 +0000", + "messageDirection": "IN", + "stage": "prototype", + "connectedAt": 1570545272386, + "requestTimeEpoch": 1570545272387, + "identity": { + "cognitoIdentityPoolId": null, + "cognitoIdentityId": null, + "principalOrgId": null, + "cognitoAuthenticationType": null, + "userArn": null, + "userAgent": null, + "accountId": null, + "caller": null, + "sourceIp": "172.85.171.82", + "accessKey": null, + "cognitoAuthenticationProvider": null, + "user": null + }, + "requestId": "BP2y0FsqoAMFQTA=", + "domainName": "3fseaywb8b.execute-api.us-east-1.amazonaws.com", + "connectionId": "BP2y0c3bIAMCEmA=", + "apiId": "3fseaywb8b" + }, + "isBase64Encoded": false +} + + + +////////////////////response from scan DynamoDB with 1 connection +{"Items": [ + {"connectionId": { + "S": "BQMAveEHIAMCESQ="} + } + ], + "Count": 1, + "ScannedCount": 1, + "ResponseMetadata": { + "RequestId": "T1L5LCRC3MS9VGA9IA3CKO0I03VV4KQNSO5AEMVJF66Q9ASUAAJG", + "HTTPStatusCode": 200, + "HTTPHeaders": { + "server": "Server", + "date": "Tue, 08 Oct 2019 17:14:35 GMT", + "content-type": "application/x-amz-json-1.0", + "content-length": "80", + "connection": "keep-alive", + "x-amzn-requestid": "T1L5LCRC3MS9VGA9IA3CKO0I03VV4KQNSO5AEMVJF66Q9ASUAAJG", + "x-amz-crc32": "3660802099" + }, + "RetryAttempts": 0} + } + +//////////response from scan DynamoDB with multiple connections +{ + "Items": [ + {"connectionId": {"S": "BQMAveEHIAMCESQ="}}, + {"connectionId": {"S": "BQOzHfRAIAMCKtQ="}} + ], + "Count": 2, + "ScannedCount": 2, + "ResponseMetadata": { + "RequestId": "RE2LR2J9GRFP3KVBN7B0T494UJVV4KQNSO5AEMVJF66Q9ASUAAJG", + "HTTPStatusCode": 200, + "HTTPHeaders": { + "server": "Server", + "date": "Tue, 08 Oct 2019 17:18:58 GMT", + "content-type": "application/x-amz-json-1.0", + "content-length": "122", + "connection": "keep-alive", + "x-amzn-requestid": "RE2LR2J9GRFP3KVBN7B0T494UJVV4KQNSO5AEMVJF66Q9ASUAAJG", + "x-amz-crc32": "3681010755" + }, + "RetryAttempts": 0 + } +} + +///////event in HPIoTgetData//////////// + +{ + "requestContext": { + "routeKey": "getDataByLocation", + "messageId": "BUIA2fR9IAMCIUQ=", + "eventType": "MESSAGE", + "extendedRequestId": "BUIA2HtzIAMFtpA=", + "requestTime": "09/Oct/2019:21:39:42 +0000", + "messageDirection": "IN", + "stage": "prototype", + "connectedAt": 1570657015368, + "requestTimeEpoch": 1570657182924, + "identity": { + "cognitoIdentityPoolId": None, + "cognitoIdentityId": None, + "principalOrgId": None, + "cognitoAuthenticationType": None, + "userArn": None, + "userAgent": None, + "accountId": None, + "caller": None, + "sourceIp": "172.85.171.82", + "accessKey": None, + "cognitoAuthenticationProvider": None, + "user": None + }, + "requestId": "BUIA2HtzIAMFtpA=", + "domainName": "3fseaywb8b.execute-api.us-east-1.amazonaws.com", + "connectionId": "BUHmqe6GIAMCIUQ=", + "apiId": "3fseaywb8b" + }, + "body": "{ + "action": "getDataByLocation" + }", + "isBase64Encoded": False +} + + +////////////////////Triggered DynamoDB Event +{ + "Records": [ + { + "eventID": "14ce94dd485ff5bfccb0c9207f2f76eb", + "eventName": "MODIFY", + "eventVersion": "1.1", + "eventSource": "aws:dynamodb", + "awsRegion": "us-east-1", + "dynamodb": { + "ApproximateCreationDateTime": 1570727665.0, + "Keys": { + "company": {"S": "Henry Resource"}, + "location": {"S": "Bits Prospect 1"} + }, + "NewImage": { + "current": {"N": "45.16485502585185"}, + "field": {"S": "Bits Prospect"}, + "plugin": {"S": "advvfdipp"}, + "intake_pressure": {"N": "18.29554873573639"}, + "volume_flow": {"N": "93.11446243262526"}, + "company": {"S": "Henry Resource"}, + "location": {"S": "Bits Prospect 1"}, + "frequency": {"N": "31.970980161939234"}, + "timestamp": {"S": "2019-10-10T12:14:25.633636"} + }, + "OldImage": { + "current": {"N": "1.169778266486432"}, + "field": {"S": "Bits Prospect"}, + "plugin": {"S": "advvfdipp"}, + "intake_pressure": {"N": "84.61898713772457"}, + "volume_flow": {"N": "83.99508013885942"}, + "company": {"S": "Henry Resource"}, + "location": {"S": "Bits Prospect 1"}, + "frequency": {"N": "79.86823770952265"}, + "timestamp": {"S": "2019-09-27T10:02:15.795247"} + }, + "SequenceNumber": "60024900000000034271005325", + "SizeBytes": 426, + "StreamViewType": "NEW_AND_OLD_IMAGES" + }, + "eventSourceARN": "arn:aws:dynamodb:us-east-1:860246592755:table/HPIoTData/stream/2019-10-10T17:09:17.797" + } + ] + } diff --git a/Lambdas/HPIoT-Core-To-DDB-ad8c7c21-125e-4177-80a2-fe869216131c.zip b/Lambdas/HPIoT-Core-To-DDB-ad8c7c21-125e-4177-80a2-fe869216131c.zip new file mode 100644 index 0000000000000000000000000000000000000000..64373d59ef75fe46a176555a7fce6aa3162453a9 GIT binary patch literal 1071 zcmWIWW@h1HU|`^2ct3f*|GBw0^j9)7FeGv^FbDxfa}sltQWE3SO7oISGV}BF3M!|D zMd#l(6RG>Y{(*(aBnJ17mzKU}d6D=b=1Rt^t=X5v&kJb0ym3`+Vw1<&i%oyN%La*i z^=&SzGOW~-Ki?}qS9IwLk)Od_cBgNZ>P)GyydA#C;IvD~gTu8y^er1Q|8!ty`i9KJ?Ehm)q==W4jH}(np7hK$0CBx#g zQmZ?g_0p-0txx8q%$Xr@OXKVGw}CQkM^3sP`ZB>H%-kv=`>QqYtD2%Fv8?L-)iO2; z@*ji(r}UVgKlt_4`bDWmkAn>7HQbIq(-|`LyU2}ay>4vZjZbG6G_f1mK8)_W@w`d1 zKjG%NRmSV~DKbejo!hkepnOk_!^d3?YL_pCX4ExZ_jS5@!}%@4&(fJjtbxlG6y$&1 zlJjK?PqDH3`vsirPvWbtSU*-fTJ#5(!dsW&^b+gCAPdwgP6Q(?*` zrllIi&sZv=xN<5(!Ye)YYlNP9@afajIHv5rkFO;x#e~+}Wu5hV>mCNRt4I0mv~Soq zDc}BK@osu*>++S$SgO=ye?5EmtZj|mdb8~Z<^MdK_)GWYyu|)%vx9C4>OH&YC-PTz z!iV59CA)9rW}a8tu~gb(9ru>2uh04F-!FHSys_}|O}lJg<4X^2_#Kyf@1Lyq=h>50 zug_a0PI%_FGi*z4*}WsoMV#>mXHK?ZBd_hgNfYPEP9!-DNR<*CU_1 zN`HOkRAgPOuPBLW_q%&}n{DIfxWh?CGJj87WvJU+C|x+a@twi0%f6LTM=t-m#r<$P zlf1vG((7k>?yj82MP~{B6LX53jDn7hGXNh65D%;*8$tZX0|Mj&(m(l>#{0s{j8d1?4Q literal 0 HcmV?d00001 diff --git a/Lambdas/HPIoTConnect-d3e57d2b-a312-42c9-a50c-730acabd0f17.zip b/Lambdas/HPIoTConnect-d3e57d2b-a312-42c9-a50c-730acabd0f17.zip new file mode 100644 index 0000000000000000000000000000000000000000..9b6e4677cad2dbd898a70417dd40fb0c7b1579e1 GIT binary patch literal 550 zcmWIWW@h1HU|`^2cv73^zx2|AwF?*-7^IjP7=(bLIf=PRDT(oErFqFEnfZBo1(l^i zf!VhW1nRD@7id+IZqmFRt-!CmM#o^6)9)~+32QemPx8F?a*t`tpYL;1tY30nZoY80 z_WRxC{+seRJU*GS>Axv?=X^c#zHXwdMva&*+w^{4hZPUjHa6yb2t2nUH~-+}@FNXQ zXLv%_F3#O{aQimxTMd4f-R_Fn{%O0H&7K-_`nJ>Ywl_i+9f9RCD~vWXoI0zt;#I@G z=P?^aR-ahu60S4j?%}`vK^vH!gdb9TeUZxKnJ>b(Snt$S-)T)Z zJLo)FcK1mM?*}`oPB})c+UZc{w)Ux~?ZvIoomOMVy>{yFyJj(unTU5MsYmc8WK{rt%Z z=JR)B_C}tRoo=?$F3@-WtH1t}th{zy+P_`yl(*E@UWN61^(%imH=X3+=2PT*Q(HA* za@Uf~p4$nN{O7-Wch0!Q?Th%5AKU@nj7)OOxMLI;sbH|A5kz6eZ-6%|8%Tx`2pxd* K1z>7mU;qHe)b)%2 literal 0 HcmV?d00001 diff --git a/Lambdas/HPIoTDisconnect-d8964309-3c8f-49e8-ab4a-bf87b36b4263.zip b/Lambdas/HPIoTDisconnect-d8964309-3c8f-49e8-ab4a-bf87b36b4263.zip new file mode 100644 index 0000000000000000000000000000000000000000..4846877e2c8e5d8723892e5a0c24f53ff4f6365a GIT binary patch literal 468 zcmWIWW@h1HU|`^2*f80{pRbDJlOH1kLmm?YgAhO56&&hv%hEu*XdA_S7Vjx+HGP1<;2%CaKSvvQ6hah5Xc@`+S}atIj=M24{*%;Xp;L-K}_z|`_~Pd8vZtQm03R#iPkvyaO?S1TR7xbWfjyN z+$A$NUi*#+Q_r^tT>>|ke%Kfpcv$0|NkZlg9)A literal 0 HcmV?d00001 diff --git a/Lambdas/HPIoTWSAuthorizer-f69b226a-412b-4db7-9193-6afdddbb002c.zip b/Lambdas/HPIoTWSAuthorizer-f69b226a-412b-4db7-9193-6afdddbb002c.zip new file mode 100644 index 0000000000000000000000000000000000000000..54aaa203ef1fea771c1bb17ab2e064939fef90d8 GIT binary patch literal 184794 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

ydZ9^pzQCLYSMgZ>59!xAH=m6< zrI8O)G}H)Ebkjy*mYgdyF!s>|%8a(1C}lB+%Qr<xcjY5lF}1W+|i;uS8gK>U>H?kiN(AlWwBOPag?qM&rP5U z;U2hlf35^mr>RE*++aGYqTvK*#4Lei_V&}A(GMa`nv8nojX$)(ITWc6TumY3U?-Vu zXnkvk`xLIEUk!v$FIo7j-jGme&ntE9ToE?or%RBe_Y`6fBM?kY+b=J}v|u<<4MBO) zGjtPUs9|#vOuG0F#h& z3qS^dJqP!HiL#C)i3}T#eZm9yqD_h~>QIBE#)ViF$T7v6PkE~~Ja8DgFtlYBOc)UF zW;T8aSiAut$4p33Tkl5fF+=hX2#^LQ_(71e9m6()+CdO*aylw%Ipg>amImVmhZRz7z}LP}#8cQ=0tp-VI6?v^rn!GQ;U^FFI_KzVCYzu4>T0I*vx-S>`z zUnpX(Ad3DrK^Fa5hl)Az0>KXg#y%8|$FM6hUGk5QUFc4RQv zaX1=*q~!M=F}pfMq%txtA9)6Sy`J~$%k#^7KO#luEf*|3-MoOG^K-d)FH&c4TZ^t> z29%AtXfydlWvmL_Q3KyknTGvf(Wp{-Q|jU84s4?Yp{ED}*_?R&i@*t;N*np9nAjTR z7p{Se>_)-dUh;B9+IrtW%du&MA5;9-)pe%m?#4GLCeL(-o%}EMt`Rks5n(ivr5Qu( z8>;YgJp;mBsX(|xGdJgZH+J{ZPSGdXg*b-;3~_f6cO=x0V?)!DNsF-FrHplTDb2#V zO*K$*8kQYZ=xpk|_4ZE%%dIU#~8^Ifksx{pj4TN z`#~d~Ks_A_p2=dn_Yp#>5@ zEU!(xZ)s#GPd@$R)$iWyn{c1p+`WKJ=XUuT`_eQfr91VRTxuz}qTb5YbIuXJxjNEC zAR>RM+MRAMNdDwAww#f1i!?j&=}!2G!Lc{SWdeww0CQ*vD zpxEpVet$OeZThs0E{SMK7Z=n+r_XjrxAY4x0*Ni1m>cS5R9Zg+PoqW20d}KFP+{^& zt}zc;eMjX7H50$hIY08-p&y(hOvx9>RFwr;6h&yz1s(7y!Vnp;9^r5;>(19$LZeI~ zOP3*=tTK6pJ6>%?OhxqH5i}R830xy0^MlTT{6hU`d$F0lboM$XeF@;O^smGbwd(5T z^3k%qFbQ?W@AGUH$}w6o?yf$wSnZ#OHo?1nsUP%{FtFzE$MeK4=w7zbBTI$7hc^3L zrt|m@xuBNns@S-TW#gwcveP!95y3;@!-1W~4Hp@$r9{w^ z=Px^_)x}5X(7O_eHc}t3L=0N3MvByMk~(g+Nf7idB#Y}4^7%Q{r0n&o4K$7Ac&!WG z-)*45WX=p;6Tl~tdXM{v3_X=;NVb@b*XKL^Eu;Dy`!~6{hv8S+W~@?4RXs!vPY3tL z(0w>r&#Bi=TE{vZa02fU!bX*CJxKI+-$5bvrZyv*ns;8Ll*Z)^&G zbeztLcIO5@bQN|DB-fLq zOO)`#2!pnliJU0Csq1&GrbL1+VJVMo?-$Qt7H_&F%}k=SGD3^%3i+ju_Z)<6z8a?! zT~1h@kTr-p3xpiN)-zz`h%n6SD3O7B(MW~8nTrttr}zCKp~joI*Y_yYjY{47R!pMu-ydq2sJdE9KbfE^Bk zS+HO|lRl03ks*A8|KG5LFF)3H01XIeO8^K6{lA5hy_=n}nX{{_a=#JicRuwXCf$%-QtYCGZ^R{S}(CHS4U3oI0jc5K?o zn_E?i0*!~4k820GC3wkkK>16_c_y zA!k28MJK8rsh2lGvObEN8gs8v^0pWW`K@{^om6`SG!^(JRtj^0#-n=1{528 zJMV7hm638mdR_Mx--Ws!<5^v%uZ zx706;G+d6QJ`_*#5uBra4zd_uG>5*z6~Mt~qUCLS&B!{ZB4|B#kv(f8c1R|{@Nn3z zJg7N|Gcf(eUN~{wES+hZgrYP~1Pj1sSa&f}fD`d8TmP&;Wyk|=h+nG>W}sXETSaSU zq>@bMv_e%_Ls~ST;)EJX0vQ>5Uih9ElNc5`5tVAsrKMuyYQQd1z1V08g0&2N$qkvl4u?3&n?;vsS-Tt5tO z+?cU(Ky>2BPphA@h>J-Z3I}`P3H1Ai6(LG>aX)mujx0(ciK_A~96(_8bO+K&{C&Qv zlO*-gPLO^Xce~=L@LY6M9ab${tb8?|Il#pXUcAl+s$ZWW8Fv};yN-X6c3+$9)sk)> zQX}X5xNAh9y!|%k_A{f?sC?k zkgP&rPuyyRu=jaBO`RVI`!PsCjsixDTs@JTaOSY`hRkqaZNNT%X9$?EM0UyCPFhTw zm!BX2yprx3d{TE<_$?$rH=6T+I4N{Lg#RVr+aCW_?x|H{B@TCdX|`K<6Nu4(Wv`K zvR$6j$Y89Xe6gq3sfa4?Kpy9-o*naxu=ne_y8V8~^|s+CjB~X}r zQ3*|P>l<)fIi=MVZrpVOHr(VD-+QK!0$1a|Oam-;P%7?dtCH>4w#cuwA*-5-x1>o~ z2K9QmCC!`tqTBX?C%7i~-xzik}b_pwfUb9rD4c*9|hMRzM*#*6CP zZ*#H0`)z4Br?ws6PQhmG#YMsUM^YI_hKCM$Z2N98D9=s9$ZTn#>^fWH&eV9ym54n=wo4wG>X|y5Z2jR1iujJg84LPu|VTpri- zCW5vZ6La^~*;C&4t}0)rB(GO7^H0d=qQBck3VD7whA`3&Djjv+ zBp+g{masj$pY3fot%GcG0cl((unX_|{K_L>Ink03?x^a+5Xs~k`PbVx&C}dv4ppXM z3LP^syA-YMYAYDWYl0H=W!$0Uv+%6oFw5n)#g`*5&gJ#8YX|`jQMS=$PUsO-w{rl zD1sq_z-?ji8@c(Rz@|&7G7k8mtNuAi%YlK#p`W>5q&~c?zH%CQyOi{VAR6U`n^f44 zx1WeB0k%xwwR!B(L8x|Y3-b^_`spTxLh~~dE;g>vSL*6n%!q#Qot%3u;VPKlu#%ZG zbTw)n9Urj`0~KSgnwsajk^d+BZ{H3fS}yhmJ_dAxkIqs z4oV4pG-_o1?45^Y<1K6AcpXN0eNuv2830{Wx-+7A^Hldpu=s7;tXalEcifn^Jjq^bjSRJt z6pkD5NMzhW+!|7R?jaH3H@uE{`lzQYR}zjBdnMO{7qNe5JATxQ%*m#Xv1fi5uzE=j z7eLdzUepa>%9%D_rI~Pu481LwajhxCNjwxg6c@H zB%9KiCEp{i^jZ;@M@ydqYTC!94 zRe&Wco26n{n386R=wL5fUU3LEB%`ttAu+c`5hnXsR^kk_pN3l6jiNhz z0c|0}lgZN*R@^;T4ctbKP2Be$ZT&oj#GK_^U3e!!U$s-g!-m#b{N0)A+q&^SQ`jbc z93RIu)J2={QHBapHLaaD!2s@|J7j2BMHp~`Ki@zBi|t^z5yZi3bwlVgh~cd|tS-e} zu;4IwYO%K%%^=E$_6I+6nU_M+6qAg~)61%&`$l#{osG7WV#E z*L1P?KO;}!C)GS0A9BIIuFX{p?1H4$SOH*l0)B{*P69wzZrs>c_nmyO$yzBRdn?Uh zyqnh93_;mJBgM_@Zf_BBq*oF$!LFg$tE`W)f8b*?&J!XB828FFWENq%7v$x*+IlLI zb>}1N7mmQ52(Vxe8RS6PzZq>dCy8BZsXn3%0EoU+-S#){o`3bSkNljz4v1~S-5RIW zTKd=iyyZQ;%#WJ~Bp|l{66gg(%_H_ax<}zT{3&>q-rjiIp`X4_kapC0A+6uE$G^S3FNog&!`ePDfP;<#Wavd`Y7 zlLO_!^^1s@ocgxD??yiFJZarZ1hsJ6rC&-iW-qv-zzeC9OVKu!#i-bQzyxgEG1Nqo zB$=ibRYih|p+)k@Pp30pQi`b?PkbB1-DsC58Vj`k*5^rju`HOXSJE4+*UdfwgM|H| ziX9Y7(xIkWRCNT1<~Cm#MkF|_)y%M38k$5ASh~HZd6?o!kXeNE1TYueoDIkJoMOVR z&8KF>o5M~76-6Sty5iuQ`hEzd*gUKena*aT~8!#;-sVGV|-;SiGUhisPqZOD=Vj{%D4 zb;VgbS^L`{^2T2E5=Tn%b?tY;dy-0h>u45I+)i1bt*2#LGTf{F2C9#IPXTyIYW#wO znwU7k@c6^A7Hp1so0(GYebkaG8~-5VCQ6SmoQ5AR}+@$O`k2II7jx0;u;X`XHj5Bsh`mb8+UMh_o+{WZ_{!Y{sIAJ@Z5X+<5%Enbruq_vl%%!RO_<`DXY0(*R#XizLn7(d6f6a`qtqZ2i-35 z)_F?9mbX(MeH0cvnFI|AP<}3`u#MewWik>iX4rdZ?jCK-tA-YpX+gT(i+)RjCrUaH z2hBjcD%`-n>nUvpZ=^kT7Vj<}7`Abaq?k-` zj}#xGm-kiuT7^a(Qv91yi-0@@!~!~oH^|i5YDmCj9JPZUP*4*SjE)6n9Ht5^Q-OG#8pG-Q&~3m#t9qO`nEDS%X^u#eD%}B^tvvG$ zT2che5StEOW>cmY}c-oJ|BPeoAf zAU}N z9S5&a7V$aw4cUv@C>bAvAEIs3_moIX=&IntWoXRP5gFa$6hq}B#*N#j1R<{i5reVk z2HHfi4|K~-a=vD7wI0f;4s@AZo2-tv!P?4*hz@%N+lxz}U)0!5>g?nbad7@jdK+W! z`I!hMD=KjAK76?n+Rt-8C@{wim2jG`?D9M_!SlY9k?og19^ zUJFXyDucS?Rv3EzR<>*k*2}gL=u4P|_>6&XrRsO-+%_lYe(U{*u*$%c582VbOLL@_ zv1mnZ_2aS(pzKgG_B;LXAoSf{Kvs!3^HK^TE?C~Ov;5fj1+FLjzIn5*vWtdLls-7= zR8}`jK!@we4^EVZlwLm!s?UZdgx=97rv`ePi`>YK0r@F|^l9|Z8l80WwGdYX$_)ye z*tY3OwVCR>eXfZZ;JKdE#k8jM^M->wX0SfDttGduvgiVa*4=Kfo_c%9NNr~he{k)x zMrgG1F>#Qyrr~WjwNu;|=8zjc95B)6J)p_+B)9C_?B8^?*8HLx$nzOC%Q`x-RWSp< zGZ=mN05NGW>x#L_K6)B{Jh#8peQ+m|j}Wvm)%`K&#IbE^ATap7vaaeB+H9l6+;2PF z*L{e4pGk&LJ9u%v0wo)B!@`pgx89?#rlCZJ2bqtajBWrI?)bcmiK4dG^_qYCo(>dCo4-mX&ZuTz0tDG69YwC_>#0GuYP z3c4V*Ph!R7?8N%;qaOVeo=s-B9;34r8=H-Y12N0MCMWz1k8x7*yD{DHm4Ml*T*0M6 zgD?KO^%8g{h~`1Gg45PQ9$V(hMw>c)gY#w0^js^VKn$3=i&%<#krbP#*t_)QrUgd3 zt7jCc3z6EFfd6ZHR@P~$h=TzEb^q(_LHcjg)7jjFgPW84pWm6QvHQ>Og!5lD2ul8A zQBiL;shvEsdc+{R@NDLz)lz16T12*SKoW%`-R|uDu?zW)WM^TOm7Na;@_GvlCiH9c za4-EAr=z=*e?1&fK&zUva$~sku=A^Y51i#(lRv6>T)=2=>$&U z=Ent=lqyz2XQgq?bMM*EGjF^H=LS2Ie~HSKGly!9CX10;4JrdiqssEKT(yfl3zR>} zG{RZJiE!|N;~*?ZzO=Z}G}NY!TaN|Uk}^A3>B9%@81TQ-7=_B$5}C~-~0WKzy* zBc78?=v~l=Ru)iwo08HB8RAOtYC?VZSPnB5ThpI4Z;MpvGA(w?tlF7!E$W^mnL2aU zx7l$T%r3XQq^A%Q3^18XI%PP_>BGQhZaef(Icsl9Fid^zWDJIV8!p6jq?tQR1tPiJ z1ZyLsuq8`{+(4X=x}PvXEOl$-9qxXj9PNIR9NvBG&=)`|4+5qF6Vwn42C>TkD^$BO zH$oUH97uDpxE3!l{0}n}xL&r1o%Hg&Cp76I%#}iFmp0jrZwh@H4P0_B*T%-i*UpcX ztI33oHQo^)bk=P-gAZMA~aWKm` z%Xou2o(`H&`byxM5EcP~@d}8Vnn>!Zs7DDF0exYo(KKg&9hH^#U-?Q)>m*$fYv;27 zYop*xL5{afPgo-(diQ&N%S`hX5&cBApjM=wXhz@&d9xoxCnCd zZn3+Pp6~YzYJDswgd1t03BvjrUQ>3<;}a8MhmS2KoOZDle+&1HRC<{e2lEKx zN$j%*)l0WFwte<1oy|4V6SBZ>ju2ZG^Zeec#|e(Z6uh_-HBY`6|L>C%jo#8-_>WLN z&+xw+Yh0{6|2;P~fPe8y8}fhR74=fp^LS;GG8aPo0|hgk`1M9|brlBbML5VpB4}pu zN-$IH)w7?SZScNys&)CvJ1x)4@8_Ul6vURzD@4GEifq9e$@CgSh;xIfG7qNQpEmP# z4rMy|HOoJmw=OfDEEW!%SMF6$(RwA>eiZ4n(_Q6*GrKw6UhqFN>m^b>cg&U( z#ZNHhk|a8^C1ib4!x|*0jr=<1eDlWFjp7twvY2#$J6mesQdOj83)};XGdY*c-`033 zo0mZ-NKY_Q>G%G z!R-ny$%c0rd_*ZTrlC{<3F3F|@!oCMTD2vqL6=7e;B`Q)>V}Zk7maQ_>9C*Zrd#H` zF(rUETLxs`mgTwfI%X7T=OFrk&^slPcx2$wQGl+cl$vE91b$Ubl@iBh&4Sx9j^mPX zHaU?R(kvhN=vyF^N^g{u2`&rW0+)gZ1w>N2Sm)9#o3HBM|IVt~5eg2HVd->>HwmEDtj3>p5<>+($a zKr})-aHG|u65V%fZSRh&xQ+7>ca~gdAuy{zd{7XaCJBqZH;AQr39xq6KeTFVM=c&6 zk^|m^eZlq1ch+3*d3(yy9$u@Q1AR?Zo%)V9jTbw9H~iLI=AwPr zsF};RhjxV7bAN$v>vopeun^`ls`d?e!YdJ5;>)-nMhzEUv>ou|=IA*OiJ^pAK_C;r zKvnFR{^H`fdb`;MLR}D2e2L^=_}?JRQIv~jwryIEv&Zww5(l;^uxe`h97lWiB3CZM zi1vgL=zrh_99_lF6Xt7P{xKKx>^k%bJ5#T3Jq4;!=PaY)1LpAD!S;EH@8-X# zTfLmJ)Z!Wrgm_0xXj2&jG-?^*=sJx#{q1$#PlR2&VbJw!LPW<9-KG{x@>ru}ERh2& zVCA=K)iK3_i{(L{`6^$GP@>|fur^knZ1ZetS^*Dz9J%p$6?sMvNi-6R9fLHu3r;Rn zPu#=cJ>uZ0S^2Jrhw3>c_rIShG7h|-*}=o+w@0p1W;h)o3gk!J`affAlHK3Q+jWCn zMDKKcpO2&hiON*FIh_R+ug$?Dhn2E@@;D|liFh8{o9vVO(!)IVk)bZ0>dYScj%vnP znfU^@hvFFOvJ+kCTK?@54Uvs=f3-Y74t@{LH4r95#oovNu?wJAOF<`IU=iqF3v`QX z>ECZm>UcFY!QAW<`=oxL7w?B?Vy+&<&o?LyP|#a z+9;Q~my=Yh?FPFy2-jFkn!?zFSt>aixAoTePUg2nssg8E1&zAG-x3ZX2|=RQeYz0^ zUa4bq7VHC%kD=?KM;hc{Y;w`xC|Lq_aNGWVvY)Ky zu8qrU-CGYIJo5ZUZ_93D2$K9^3LW>lYHA-t8+&5e(c%S`||IGWDcOQyr(l*m1bU1lR=nvSjJb6p)U4eQ|l1apW;YN9sy8lguI{ zbYf(dyVYqgtBBeVeI8PEfWn%tyL$eNdcZ;EO-|g=RRZfUb38&-2Zm&PTai% zI45j|dbqDCihSvWgBRP3+s~{H&}qKmFgDcOn$rW^VYjzb|KV? zc%USNx6jSMeH8ekcc=ye1QKM~sOlz!oXx3Z5?83TTzF^M-#q8-W#5lcDC6URY?EX=L=lHr64BI4; zx7FG{B8N>N7~hU}qfa@IWtO$W+sb}714PB3EL%06J5>@^CVFpq%t~By#1Qv~YV*jt z-PKm9!z;ILZG<)_N9kdQwm_*F=y>9rxXM3D`PpKuUV{}hA-qJ5=8#!waWb4L#N;zp75a2GEyddeKKxe9do4_xcZCB|JWiOz zA8CeCxnhy4RqDZHmsAL^7v%`k>SkS0$n|JdDASxJ&OuvUw4kXMZ>+(A7^(?}^4{-S z_1FaOJ!ONIIZ9M8<58cK3iNo8|74M@s@XPxb=0j{O6hZ(OP3UkqiNc+m6hW&Q#YD7 z1H6iF-$)fngo`~>Mam!)JIp{$fDQrCaI6KDczJaBMw?%4OM0PqJoKNyb3B^b5s{0b0LT{LZduy;brkfg40%x>r=r2}ClLF%2HOTgK@7k1v~ z-w+Z4&-9u3dCeGjseid((IyT;J0>?LQs(!u=Plp~%$!DU=?qSr&BC*HGuomx`ih8T zv9H3WfQ~u1Joo|6KELUZ<$Dm#;D=9tk$Ab@l2BpVGz`gtZ^AwB7sA`9bCDOMPdp2G z?OM(m;W9MdEQXlkup^wjOsPh=$h(OLgI+c7htVakT3jj2)Y+N-hVT*AZhztbnAp*) zYrL2B4_Y-i^(4L+KcSXRZ_cCqQg~oD^&e*$T>rPxj-hLHkIiY2HkVb`hR&LAJookZ z_KQ1yu@JA-{CrOgQn1AhCyAzRk2i#USB{~E^pd|*uHpn?4oIq0PqV02*3^T)MMXAb zn$&SULFmz*`fc3?5Z_wQkBX&4-cK!s^;(7YTocEVvcRZpDlM91 z&r%gwYFFd=M^0^euRT56B*g~jiEMD|>8-(2#yD0jfP0%D zP{{Rk%*wz3R|}4?ew}$tJoRXnGoxndkUhW^XIo;5$JLA|SC_+XP_ut3-qfdotHe7? z{u)R~XZ)}{O2Ud+!?l0so_el-MX*V%i*H!&Xtc43&2p-bTNF<$7LN&@6%`@lQ3V!`MIqEh=-CpQ@wy)o zfuB}s5@nD{Zu|l`maxCT8*b{gGhEib_O+4 z77Ijin=Al_E32oC*07J?J#zsyE;%^gcQuIocm{i=!zy7x`F0Eqj!}w@+vL4 zcB|v`qKc{CWeeH&YFnoZNK2ovPlDrT;A_Q)GB)8!{p_Zp9>LN}${QGRLou6kmYk#H z$Qj;`bJx;&SaDeNi4ZQ#NfxkWb}67^xG~~tPezt2v=kS66K#{E&_QOY&J3M$M|4=E zL4PZ0JhmkzFc@d12yi`Y{77vqM@cY-uz=H!F87mr14k*vNd?X^ts@Lh%V{21L(PkN zqaJAlbwNUkyxY@>ffT{S@ZPuaOsO;wCs0oZvZ(iFm;YZ^2 zu{b9FvwOGR`@L=T1^GW(_CLo}VH{qFUH_VbS^q&6{-!c5BGnY%w8q ze`vxTAu-xwTD01wi748^1QEzsIslVy9yUkPaVI?wem&ujJ8RwWSS6X$-u9=ROlOz9 zIl4l$SK^v`jexh(+qT#2N!rko8wq@Hg{fH8p*PlvCq#l*lec2T<%$m8^R^6Fxk7A4 zpQ1a0s%RVHj(|^sfdtW+!xBXfU;3H4eNck{y6jV0e59uMy2RQh>+2n_W_7J<9?O;0 ztknmrg|=@jtCt~E8R%=36!+7I^g`N)4=$FcQ(CkWVNz&yz;y;ay6rH;+YLwh6oY&2 zgjVqtws>>eYZ#~YiVs~Nz+}r`Y-;BdB%u1)yQ#*Il04vP|FMLm=Rp{^|E;jqi2rl= zht~f}kj}fZNa@a-**d~_g}v!nl)!=Tki#*>Da{#Srb$vIC?GYe(PXaZ-e*OjnbpED zXx0lWL-g3cZMyB6qtROX47LfQBBpHcUau%EbH&U$c#QM$LGxptCQG{tk%J}j1XvAg zs%JT6<203#xjJ>~P>h;hYLxUUSFzcgef_8az~cT=PnuZgX{0A1j!>Gik|3YjaTi&jMVVwX};J{7$YXjjUf1%3>eDoDJpkn{3Cy_ zo4vuAgZ(gWrTy8*pmBf0J02T0c!LK}(Drshcds6qFjgJDH+;|#ifSlSU-`xR^D zBp4?5M?yF7R*d2#k=~}nXfE#rJsj7`#DC$Ui05SV9ZPMZMlY;w>#xQt(ho+03ET%^ z%ywH<#!ydM9!w|O7(=7|*QBQbH_KfA3WM~0@Lt#>ZfDcIS`j8kGBe#xPUol~xsW$S&^G_fgL1OzQ?#?9jL1C7w$lo;d~F9_sRa(T+~ zI$KNyYxl3%MZS$0wBG3!na6V^R*LLI;V`)+j^mHD)#!{Ur49ED7GKf*=tIpAVnCC! ze3)SnQ9y9%sp2a{`AsQTu%1@=0I!fiRm}VK36r*1=)_3R7Iq*(#Weph-{wP?5084! z{hqYZ=ZiO4kCq%p-;1lc%;x%+f4YLHWtXek+tA11r}jH|6(UI`)CYW$s0siMr5gsB6?LKPgpVcLN6O8JQXO~RAW z>rX!ww1(T;Wg|5Cv=gg|jwU^)a8`YgblOklCo>v`+xa)AbPk-4z(JC$*ihtv3ju9> zqu0xww>xuJ0hzm7drJYCuiMN2VwNc*=fX**Ne?RU0 zT`gsB zh8xS0gv>)Z-cRR5?X`Hp?%@|5JG=IWJ@GpG5wox(&3x+T%Jz1y~J@3w8*wr$(CZQHhOTe~@Z&b{-^`DdQ$A)lgZWqldBRz!HY zZvKQHykh<5rX5R5V|c>>04R<5pEK?My=m>-|93Xz70<8#4|~Jz7ggPZqq>7xdJ){D z&*k<6@r=~Y6seEBNu>@6EsC%Jswi^#vHs-8r7jyBQWphTdZCLFFLA^CStk}g0L`GD z;K`#g5*b1EYV0aXds#VDrz7C4&&@XsDTTrMpGwBL8rY`;To|@ zk`H?xSEh~OLrT9^s6K)UDSt@$v0MGXv{a4y}5QlK;ajL2>;N9m!_cT((9CU`AVnd?lW z{dU$v?qecjxu%xHJO2_Sx8PjnhsNHQK+#-p1@|f7UQf@D`8N7iOi$Ac!+$o6D7PX^ z?$!pFcQ-HZ%dlJ8SU`Bs+^$%itb+V+7W5StHD3x4hzGug-4Cd z+i{&~#m#hagfq^bVa^C+Q3amH^Q{T!^R&0-Wlf`KtLMo9BHxTWf@4UYAPB@!LY}JCgZf4K*zT)SeO?=j^@Wolxm~^@s+mVR!TMui zj^GUjz2wgl+?K)bVGi=3EBX8KEen4|Af)W;F$590`yZ*x*ycIG`H>=&f{hb&q=vCY zrLo85R*c6fWhxt;vh2^LggJ%d5(@3g<_-Vg~!AXgDuOQ_=6B(akZs^fqqm-Uck5|p$v+%)CXhb>} z6V|AM+7Xt&neL9F^ccs~`k|`l?k7l43U3Brrp%yqo8b@29MI(z-gd)f& zGD#C8603#JL_m`p?Y_WIdIs;4z>ANHBKeF%RaY1<3Zm1|qvYm?6c(yJNc`@3p2d&F zsdzccH)}KSg|;Sef+B>M$SU_Nk9A74AY^Ajr^RWoAkAuu_tc>@YF5P14|PA~&>UzA%J`-P zBU&BStjrMh*k?s>`O6{RSP3-@7Iw-T3q5(+U=$Y<3%SZ*HYvY}YD0*Z^36XM7tKmS z-k<7M27y#d4yXwic>QMu@t_b(;Q>7em(#FrJ%s)fS43YH`4+ld13X5l0BC|JoODPRzaO~<|%fV-Zi4$rc`#1D0;1!)QM zED==hBOF8$6lI4`g|8_Lu*zK0n~V@rNIgNQ57d6^I3a`&d;djh&czH}AGS)bAfLM0o4F0!Q-%IbI^@ z9(Esf*7sLn&`F8eh6NZjw2hpuq@=WaF+HNnDj=Tzg#ES8wtghfZzEW?^`ZRb1LYBl ztq1N4wIaEz@+hlFUIfODgXoRvX*Aq_MYpJqJJgE%k!8&g)C*)7PzG5@ZBj4h@9?VY>Ta*M zXpL@sCj4)>&%+_hzx(%}wP>Abbm~Er4$ZRRx|DJKE}z#96y0p}_`_N%LDupgD~y%- zaJAl~8PZJEEjvc#?K|0zH-q*c#H&I%e6mP|ZE!;iUf)eMoWn8CNe%ecw<2Ase-)`2 z23-r>m6nd=Nfyl*(bH&Lbu9**<#7b)19XxI*`{7?u*fGQIo6;!NaBx2uA5%Ii4^56 z`D(+d!|A)l`0+z@s75tI7q%fbpf#xw0(_eB1{hUW2*b zWdP+kil@)dp)IDI$-l!ge0JS~bm6@!xrWr#rjt3wF2|8{%oKF|-6N zHtJZGK&#O$vw{EFTy(C}El@wzzZ`PFuM4e?s{omCL4;H zAioz?s(o6FTKr+Jp83wx$>42yPZn`27JWX?Cf62L`YP-3m>Ng{X-<}!$P4Z-9qf(z zSTN``2v^ejqf{T(DAm(2x=%@Y<8n5lnPt^&qm_<>;InYcIZ0)0=wwS&w!iJSUu@i(;HQrmVC@ry!SpcPV2rDIBa}&QRxKuN*&X$j<{E);{2S>JE2mrI`dX?h;oA z4#|;Q14(oI#W1{_A#DEgmme;WVU59I>u(I+@7qUFX!9sV#5pifEm$YqcV{ zq-HF%l|4DlE{5j(dy86NS4N;hy=VwB!cYGiC$hRrN^&iFxnlS2hdLdg#Iv2ukb_4~)7zjWm9qiX8q@;iUWqq-(Gt@5 zLh&4!s=VB}7uUG}LBD}HW|Ci^eEHXT4w^XPzKM_m0em7OH3By;bVraQf6B83g%e1& ze8)ObK=W6$#_yP{hzy_#JBO-V6>Mgty_@^I8?#Cc{bonjB0;*QJgNC@R0M+sFl@gA zAe^<~IhT!9$`l~Ecjb_lm-H@TJ-j1Nmobr?;;f!yO!M@ZS>8w=g}S6V<^46Yq`|gw zooD>@S9a1%^Mev%@ff4m^qCcY;0GO(Rz*npT|z%H_-~SU!B51q=TMeZMaWh#Cv59a zYqEK=bC`Y$mW81@*bAuA04 zHfcWAU&L5mIrvsM0d+CEmf})!f7lk#>)>!8mClvF=31@QS~i|zq`KMeR59-h5^W}g z`qnN9CNh|$e?rUQ^exZb^>CQQ%AD<8RS~_zqbk@~$fcruaDHhSEi7>?WeH&fHkx)s zaH`W#U3~Emc1BU9Rpbp=f9yY~5bKY}7=bfZ>`!=Km^S*t*1OU7uEzZt&@aT0_(q(6 zlc(8C{+6VlF)@-`g}Z{Do*{uUSb+eaw0Youx>|kF413t{dEk6igVPvWS=qo(Z9wb2 z@qU74kUTm72+g~Lp%e$-`@Z`-!{VU?d>?#eDnDB6q?sn*_AHXwvpok7t9_@le}0nQ zc96gky*sdTckeY~W6wLowj=T#)H`^CJ`0xM!>#zX(3$uTM8{EQ+55LWR6tZ?iL^{) zydub))%O3~!0sCZZGDDptu&}*fQW_aRlW2@%}R1n>#TT{OQqim1Av?cq^9MOrraVh z&`8*|Mq0bO9Pqp7S>BtUY395Z8F&~#zpVp-C8TJ##puWHopZ{G?%$C0{0j!LYX1>& zs?G~nMK$Xa1+hUsj6vU{%ttH)jHT*Rpbe(0y5Q@7V)mhh)y-yLqm^2mXv8rrgMXIn=^TX$F2_b; zIII7P1Cgeg>RTV_(oG;ob@RYZc?v`@Y!IcP4+5Z$uE&Q&#)|ABi{`G;@)TxW0y6T` z-H(_~4V2=J-3#dCz7b*wkPh}9qMfJn~LxPb^}r; zG^Swo;-kZ_t^FGYw$3Bgv&f*I*@(O^T>{Lq~DoHMcGv$dO;3~D0DbqANABej392BP0i1*k|8iF&_9*b z8XvXXwCXwNmV9tSP$2YGa3Qf~)+;Fu?FdgrOlo_s|Ftjo;g!Z9?nm6qUbnwkfUy@o ztj5nIXn&^{++A&x>`PIMALQ)(>XjCccvwJo|NWfiLbwU64qXGT zXtS0s+@2!r@7LxFg$}<6;R%Va>pPphBp3|nKqod0F~q5t1mff(4$xI+wq zS%DciJPW=VAg&yq7PgnCCB|Z)Di9&$29dG5##!oCt?&(!V>H?ly)M1+JQPv16A$sV z6P+=6OIWP{+ZH@ZJGQAVd;XSV06t%401K5R9bi3QAiT9`v+dF3uQjzT8F?%0FiZBu zpawHIpY}0Cp}}gD+7O$gHi9Jo?gQeZ2)xCHa6yUnuP0XK?JDC+DKZP}X|l6I^4#=8 zCX$}lF?rH{4JT@O`-OzAWDe!R3Ez}O=Tl3^dQa=mi{ zN+vP1DWdUQDNoQx_6-YJU318e z$wPFl$xf;~1bhrMt>m~wz*cFrwnjZCOB3v7(}C@F>HVw4y+9)sN2@{ggr_JBDn?x* zQO826eQL=k8T2Yft-otqE5B>S6zGy6^oqQ!nY ze?`fX^p)fC1wNn*1+v6O8*@E|Ix{Ro(Yn>v_Ltc>LHZ5Rj-#-trv*^pvX&MdHl8NR zxzqAHrFW!Qiz`Jg$(g4qaM@gyXXPU+Nm**uyIu9^G{~)~awlxn`4)AN=7I?79~e9S zmq{xZXfKL!3kA^+39x@wEtS%Vbhq$j!zuMlEEPQ8mHx6-uRC!!o{!B-Z<}#PsvJnn z67L7qTjNso!TzsM;Z0* z)1s}xKo(vER6D!6lHB5)Y8H_eU|+8cwha*jQt0mjY8o-<>&cvcPue&m-6rsU_4yhj zy*KY@yF;O2G_$@QA}l$a-@&D@!TMadt^>&5gqIBvf@c2H zh`2WoK_@gO7@02h5DSK-Eyu`|UN!|F0t%R8e$)6k^($FK9HiG^ zY?ST~!7S^ShTo^jn}P>)`Iki1ks_lphV%B2&lLN&l)9m3QZPkrsKf_)>gEsO?=`a+ z#wX$hFDr!x_aLe8r0KfR2CHe}wqb{v?a8!WyX}vJMA~&WIcUs0q@MgI(0!6u;SLK( zN)|=$*puclK2DfNk8fHP8_ak>JzNd}=k_9#P^IoT(}l|jvYL25!2IN`&T|{Gu5Ryn zc<^oat*_gr<=n7Lm^TPZ1TQG^TnfwhhEi&}`K)y?X=zlV5`6kfO2K0n^AgGCG!O;# zO%3(yWqDliSIp%6!aPkI_GKtIEHe6pYju7^-U3_xPU};!4cjW5ump^EhC+fUA-K)o z(VA6WheBsp^ZOaKeInQ2)R0G(!)r6=!)}mX+88%OMB4Wm~PjPj<3*UHhfl>bn3Dk8)@dtq}T1XumhwUMto52UX$ghbhjXu-u91e;7xs zOj@>Kj?)JQ`fPc-K6-K+$Gae%=qGrh>L6PN_=W{q`|MHOh#U9>3@l*_wA6PJK*Ylu z`K~JQBdfm>{=5cHPc*tnie62u=7{8G41KWKzDe<1q|FdO>|bdP7iiEfP|=QAH|n1qTD&@RtZ#6n_)6gQ$Ly3eUV3WV%N_7 zPLX;E%EaQx?(H3goC#&v|8L(LU3CqdbZKs&7V zeZmGx;j|FfZk(ENR*ufONTw}(%FfFRR$uRTjyHP6ML_SXNA$pF-%ic-@%N*ElNm_M zE)py0s!usb$y+FM-#X5&q3<}gt(2&rq$85-!F$htCcjGaKow@~s`4+-i*(DCp9>%6 zu-p@ze+hRf`B#>E5#ivd_;KyrWN6PB#x7RcC_uxgDck4eD}J#sD$@7QvG#ZjktkgE z2NlR{KW?9m9W)tG0iG}%EbH%koe_dXJTsj8QvluV$ z395YFjmiGU^h>KvC)V@jbL&n=^LPw2F3woNGZm&Q zZ@L!OC8w?1J-4-+zDB-wj z+aefW_AlO@?ia;ZHkI*nWF&XBW&v7cc9B@=_crvYI7or5R!8Mw%h+(B;;O(T>*>oS9gxBh)PHFEwtZW&c6$JbB#Bl;RbpFnVBV zl&AsLIJ-y;YJkJJ)7_DU(mV3kLIo~VaSF31r?=UmT^#5u)>)WL3zF0)785JFg{2lO z-flk~{TX@pK*zJToV4eWX`SS+Iqw7TG%=Os*M{&E?*s<0DU>4K0DBcFSMv+T2Dwg$ zQTuNF_kH>-5%U*dN9@}`i3w)fQumY}o&$2$W+948a4^fn7Kx5XV8aaVD1xVTo$MQR z$MfL`FSEnTt2gqNJK1k~`JR|hu)(WQhoJTI^>EqzXmnaN-=$akM<(I5a+)%jZTHLR z&Hl00dFgs+zZLJZtA<@0!_jdTmz_uUS#a;$kf)Qo%z@8xZaa{5F^w(wfPw}{r^wO_ z@j>Zf3a0VCh;qjwu$);coN;!VvmhkKfh3l)dXZ+Km zx`k1ABMhWlW-7#Hy2ZlLu;&f?=#?1<(6VVNSuuVNiImL_R>Fu~~@araT#Qg_Laf9>$jL4QRWEehuh zWq@=d>wpo0XG^WYXER43PkqjS`|9I(MXF&fQR57D5&=+wWh~427*0(=`E1N1UD3s@ z%712aeFaAymMk(>vyMaQN*^$id_k;6RRO$p@t~uW4Ekjj5~LT9^NG=R5%YITg0O05 z(iYXKF;Jq;PXx?=U~+;5FQ?;@GQ`K~LN6Xoc=bKb_^Rf2tF8hGXeIazc~rQsEPgyY z-;+V0qIe6xa`k`ANZ2RS5|wp2{ZA4hST@KC)wG2QG-B_t8&*X@5I`_y}nf?&{hJXKRWv(`rG}1 z6K$z+4+~Nh%pdVo5Wi0x+*fmm{*k0U9~2c^hd`Mw#!pZVWL;y}(q%mj_sQ%hR6)y#L;DB%Ega3x`!zu1r zF(p;=uzrt7Zhn-zFnDye64SIgxh(K|4teWUf~<7L$M0s@{91NYtZ>>OvVZ^jh6XK6 z6?pJ5!;w&tEHk6g%B~h_PC!xn`GkVbjpQq*eI8hot~VuYC$*lnEYlpD!aV(?=@cI_vDc7VXW?fH36{ScB=#5Q21!sY( z*$5nILa?Vv)Z$_MD)>&9s*oyG&hjbKFR(_q+EztR5)Q6^xGG`Gx622T0~fI^;U3M=C|?J6G{B?6udp_j(M&0vzZ#Ja zBSVbpoUYslCZ7=jqII}dHfofUDd7&Ur^v>2pUrwoNmUeF>sQ)NNOFzegq1L2Tzndw zkuc1<;Hla|$ac{A8=Nb#TzsbnN(&9z&3OwlKN#FJ=^;4ak?nS_QbOxcuY_`rFd(jV z{4XkIOaYUv!kfBiO$90T4%c9{Q@Le9j#%BY2HLG@&0GO9jFtr%TOA29eYc`I0cAHR z&tJq(iWbywSvi$rL9$CUA$pu8G`S%&Mgu~s&j*ss*qarOH==&(?`_-*BPsOqF+16{ zma57|cdV`(lzYIPjT;<$W@QDTlGdHP8g4$e*{|E;Og(__(y|@+Zos>Cv5}0Aq}@~` z@P4=LDB56`^N2_!H4DLo&|R*Rj{#D`ELd{R|8;`|W_ zbzxa6FMFpL13=Mqei%%8NmLV(6;UqwF7+Kov>rAX^o#DFt>9te%s!g!4#+F0`9VmE zIjE8Qod|B$EarQGO?<;fU>FD^`b%>rYzA{77yK2iJSx#L$Vh$^u@-v1VVO})^3~`e z=x6Whd*!ZbHqD5=_Nf&i76jnYHF&ODJ zRxkDvC%GkJLi5}&appLv-N0PD`4538&7RmCxLTmtC-YBiDYxe-N+v4HiAQk+4t@Ov zr7TxC0p%=QO&|j47PiIFcjnD23py~(j;b#p!&g8jvM<(H;E`$-!o@3kH{l17% z8^8@jAHE+4|8z^E(HvE|sz~ znVl>uG^~Y3?xnZALHF3mQ0go{WUFXfpaF@KO60pyZv_r^XmJJNkJDt~^4!=}0I!`1fEHLk-r<7)FgeOh&jx#Go4e9nV9Q+og+Kvu|{5HCM zhkpQ+%AX%)!MX_IM_o@3sv$_}B@;5aDy!rDJZ(rkw-&{I1GW#!jyGvY9F)KKmwZHR zYhr#X=D{Wx)uiTS2P12XT<)-QUffCyZ0TY9Dca*?gKIsQqUjWT5qxR^GblNtsMm*>S7-r&5Ke!9l_=2Q4SODKYO_NO6R+iBsT<`bU)0AI zVmlWhaa*uCrR>=_y?xsmK>qCdcC2-pQtP)AoLF&Ensu0-k-}ufI-#o4zFUb+3w~b1 z*0{X(xxrKa&@F`S7YjjM+7hObj>k2R;)guDltjipT%C?WK+(s*`Q~E!;KyE0Uk!rh zZ=@G}8Zcz77aZrvFI6-(@Y)R9$$x*tZG9kz^WKMDAB-!kr_F06_uAbr<%;T6Du%>d z91?A_^dbF;+EH7D`;S0uj2Twfo*b#&&ytw=;F7})+x%2!yh3`gPg5oH z>M6Jpir1YuuHEObATqL`Wp0N1?YN?HfxMt?yn4D2x=;ac0++ zf3Id%%9hRsCfo8KApjXKI{K>l$7jI@P12TVIRA~8n~W@OJ-)av+_vJZn9Fs0pWurf zEJLD{g!(VUNo-=ZL9uhFo71w}4!Pf^4J&%=h6TGmd7Zs!p7HuJDR+d%D|8vMHm@l; zh3uW)w85*~L0|j}XuH^b^A9T>Cxv3rO=Y-96x;iC?JR z24C*f<)vAp7S#Cijlc2RU0pngKK(cL#y=BSb4VP-3PpgxBW~F;$3|(J{AzFUmOFKa zi0vSIP}WncLi&orLb)!i&HRTEQkDZx8&2`C>|n=@O-zcw44A*r z_&5sDN)K2mDi8cb>mSL>$upH#Te)2{*sQq=4S&;HZ(XzBdqz}~omK|inDZaLh8Xv4 zVs*FD6igfP>}wBGR-M?xde+}6DD#)2bRchrB<*P;Ga`jDY-lrg7HT7jql_xvI!H*o zPHt9yeC)@&3y@-SxCJzsvwNOox+^NGGj+76=fPGU!N^u;Koc6UfDrwNvBbEC>+-ojS{2ESh#-Dft+l+dhyt<*Y%-tPV~ zK2-R!Nwdq{C*FL6kb5qwR{DVgqr|Xe()IEURh7RpG##AMvem1KXv6O5B9SBSRyP2P z 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 z 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Ð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 b`R8t;*Ag&*qk=$kz&~^#FI3$9LIwIicAo`} literal 0 HcmV?d00001 diff --git a/Lambdas/HPIoTgetDashboardData-6e76fe04-8523-46f3-aa65-2c1bd257135d.zip b/Lambdas/HPIoTgetDashboardData-6e76fe04-8523-46f3-aa65-2c1bd257135d.zip new file mode 100644 index 0000000000000000000000000000000000000000..17ad1ab5ba0b9e204a71a3f958d3e06a73d6e740 GIT binary patch literal 1130 zcmWIWW@h1HU|`^2=q<_fpRT)T;uB^DhCogR1|gtmPGW9SN@9FkX%OP3h6UYR%p~9bsN(?S^V)uM`8|SL8t-phT-U!y`4itOG3I2`tFt6L4UWe% zes({()%*8X{TAsAoiDfV{=TjAY1VbSz2;3Pxr!6A=SJFaxb6HLaPZW>%<$PE&U>YV zB?W#z);?q^ekhNkF zy|OROA>}ismYAP1+-TUd$xbQ7)$GtLv(sJE=C4?hrIN_aVZ5!=ffg5$RvC{-C(76EaK%AFPqC^yN=j#?6^EveeD{{*SQ8a zw}eD+FO+_6d-CzE7n62=bQZNQ`!_?4L-iiN*uLxqTC$;f_RO1aMQ1$|m6>Ok{zcy= zRx|Jm-*M{`vV4+$Uv&EvZgs7n)5=&NR(;>cu~pAvZRy8Dw$DzMtQJUGw<>j|!)ZT5 zjT)c7h1I)v+}Hc~EzZJEHI+v{psvyPW9KW2xH@=?r`?TC z-1U?#I%~7+GUbpwW_^>!w2&ozS=~`@E`N{Y`@ZC%$h(L9vMYS8ghg#ER~Kfy5YBV` zD6!e{ZG8Le-FPPP1RN--0@ywk1<~DwQGfPRGZiDR!3q|;@9WkH7mt|#p z^zVcxPl}8rh3$7)O7>J5l?0S>$+I`{dt{nt8~u9MzWV8UQQ?KArXM`ac}0IHnQFL3 z+Nde43VXz+Z5=B9Q9U_o?)-UiYfLVjef;UIkbGpq+(zM$^H#M?A+slM?lJo!uessr z2hUu;=+=8@mbG5cS^q{Wda~i+kGJo3DNbIPRQ>C7MVsQQipJj`CRE<=yRDM4_DK8r z6GGot9AG@2we0fq^O2!HY$dfTHmrYmCI5DXVgF4BZrR&*`fph0%~ rJKO)W26!_v$uZ+D6@Uc;7%XW7QJ7^!fHx}}NQMyz9e}h53y22*r&#vz literal 0 HcmV?d00001 diff --git a/Lambdas/HPIoTgetData-35e8720b-7195-449e-aa91-16a0c0597cbd.zip b/Lambdas/HPIoTgetData-35e8720b-7195-449e-aa91-16a0c0597cbd.zip new file mode 100644 index 0000000000000000000000000000000000000000..373af646e93ede49c858a391269315be9c559e59 GIT binary patch literal 671 zcmWIWW@h1HU|`^2_)-_{Uo-P&t zZ}uGrp1r@rd6*BHS)ALZ7$8=2YgRh$euSBt@OV2SSy(9pB6TaQC z^sJht{?fDbwxsu?c4Mm*>bnh6@|v4X-)2lZmeh4#wJb#X?U6ZKGqbLIIT)2Zy}x(m zs;F>B1L;i0b$aG*@~^b4ByKaMJ`BC`KtIQ1i^T4&JGu@`4bk`OKIeGUPoiHZ!*$z- zWulj+8;a>Bys~)ma*=9!_5Y9AGAvyDiyF5DOt5bXBikrU0a6!xy<&Pbv%kF5g)uyQ5WL|&f&qkA6_NpBoGn9?jg-o2jxGb5; zd#+!e%GCp_BtlQDT8o1ymM{G!(u&wbu5J(YdPtm=cx z_cIgczMOR4B1QlCvFrMucE|Jw%L*61D(9O2%u;Uowq?OP?(An!|8VE*9;q(@EgxN{ zUy0U@b8>gsdt0LQVbq0Kf7*~c{;;~CF|7rp${Q@w0~UN_=a=6rS03hrcH}q zn`>_Qa66--NK?D$a^yNU=l0L*p7F+fd9Q4}^J(5wySlxbieG1@%REgf+UL`|^uEUy z%bC$r&mPbGnBL!KcKPqAz4mL0r`=KiXJHioZU6h1UtLZg`*-ed+16PP>;t?RndF#p hCnaEN0)r)uAPO^K1$eWvfn*qg&;dw$0+S&F0{{rIF;)No literal 0 HcmV?d00001 diff --git a/Lambdas/Websocket Authorizer/ecdsa/__init__.py b/Lambdas/Websocket Authorizer/ecdsa/__init__.py new file mode 100644 index 0000000..5c2c3e7 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/__init__.py @@ -0,0 +1,17 @@ +__all__ = ["curves", "der", "ecdsa", "ellipticcurve", "keys", "numbertheory", + "test_pyecdsa", "util", "six"] +from .keys import SigningKey, VerifyingKey, BadSignatureError, BadDigestError,\ + MalformedPointError +from .curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1 +from .der import UnexpectedDER + +_hush_pyflakes = [SigningKey, VerifyingKey, BadSignatureError, BadDigestError, + MalformedPointError, UnexpectedDER, + NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1] +del _hush_pyflakes + +# This code comes from http://github.com/warner/python-ecdsa + +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions diff --git a/Lambdas/Websocket Authorizer/ecdsa/_version.py b/Lambdas/Websocket Authorizer/ecdsa/_version.py new file mode 100644 index 0000000..7a66192 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/_version.py @@ -0,0 +1,11 @@ + +# This file was generated by 'versioneer.py' (0.12) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. + +version_version = '0.13.3' +version_full = '7add2213c992f51267eed8288b560f3f4108a28d' +def get_versions(default={}, verbose=False): + return {'version': version_version, 'full': version_full} + diff --git a/Lambdas/Websocket Authorizer/ecdsa/curves.py b/Lambdas/Websocket Authorizer/ecdsa/curves.py new file mode 100644 index 0000000..a361da7 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/curves.py @@ -0,0 +1,46 @@ +from __future__ import division + +from . import der, ecdsa + +class UnknownCurveError(Exception): + pass + +def orderlen(order): + return (1+len("%x"%order))//2 # bytes + +# the NIST curves +class Curve: + def __init__(self, name, curve, generator, oid, openssl_name=None): + self.name = name + self.openssl_name = openssl_name # maybe None + self.curve = curve + self.generator = generator + self.order = generator.order() + self.baselen = orderlen(self.order) + self.verifying_key_length = 2*self.baselen + self.signature_length = 2*self.baselen + self.oid = oid + self.encoded_oid = der.encode_oid(*oid) + +NIST192p = Curve("NIST192p", ecdsa.curve_192, ecdsa.generator_192, + (1, 2, 840, 10045, 3, 1, 1), "prime192v1") +NIST224p = Curve("NIST224p", ecdsa.curve_224, ecdsa.generator_224, + (1, 3, 132, 0, 33), "secp224r1") +NIST256p = Curve("NIST256p", ecdsa.curve_256, ecdsa.generator_256, + (1, 2, 840, 10045, 3, 1, 7), "prime256v1") +NIST384p = Curve("NIST384p", ecdsa.curve_384, ecdsa.generator_384, + (1, 3, 132, 0, 34), "secp384r1") +NIST521p = Curve("NIST521p", ecdsa.curve_521, ecdsa.generator_521, + (1, 3, 132, 0, 35), "secp521r1") +SECP256k1 = Curve("SECP256k1", ecdsa.curve_secp256k1, ecdsa.generator_secp256k1, + (1, 3, 132, 0, 10), "secp256k1") + +curves = [NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1] + +def find_curve(oid_curve): + for c in curves: + if c.oid == oid_curve: + return c + raise UnknownCurveError("I don't know about the curve with oid %s." + "I only know about these: %s" % + (oid_curve, [c.name for c in curves])) diff --git a/Lambdas/Websocket Authorizer/ecdsa/der.py b/Lambdas/Websocket Authorizer/ecdsa/der.py new file mode 100644 index 0000000..200f00c --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/der.py @@ -0,0 +1,231 @@ +from __future__ import division + +import binascii +import base64 +from .six import int2byte, b, integer_types, text_type + +class UnexpectedDER(Exception): + pass + +def encode_constructed(tag, value): + return int2byte(0xa0+tag) + encode_length(len(value)) + value +def encode_integer(r): + assert r >= 0 # can't support negative numbers yet + h = ("%x" % r).encode() + if len(h) % 2: + h = b("0") + h + s = binascii.unhexlify(h) + num = s[0] if isinstance(s[0], integer_types) else ord(s[0]) + if num <= 0x7f: + return b("\x02") + int2byte(len(s)) + s + else: + # DER integers are two's complement, so if the first byte is + # 0x80-0xff then we need an extra 0x00 byte to prevent it from + # looking negative. + return b("\x02") + int2byte(len(s)+1) + b("\x00") + s + +def encode_bitstring(s): + return b("\x03") + encode_length(len(s)) + s +def encode_octet_string(s): + return b("\x04") + encode_length(len(s)) + s +def encode_oid(first, second, *pieces): + assert first <= 2 + assert second <= 39 + encoded_pieces = [int2byte(40*first+second)] + [encode_number(p) + for p in pieces] + body = b('').join(encoded_pieces) + return b('\x06') + encode_length(len(body)) + body +def encode_sequence(*encoded_pieces): + total_len = sum([len(p) for p in encoded_pieces]) + return b('\x30') + encode_length(total_len) + b('').join(encoded_pieces) +def encode_number(n): + b128_digits = [] + while n: + b128_digits.insert(0, (n & 0x7f) | 0x80) + n = n >> 7 + if not b128_digits: + b128_digits.append(0) + b128_digits[-1] &= 0x7f + return b('').join([int2byte(d) for d in b128_digits]) + +def remove_constructed(string): + s0 = string[0] if isinstance(string[0], integer_types) else ord(string[0]) + if (s0 & 0xe0) != 0xa0: + raise UnexpectedDER("wanted constructed tag (0xa0-0xbf), got 0x%02x" + % s0) + tag = s0 & 0x1f + length, llen = read_length(string[1:]) + body = string[1+llen:1+llen+length] + rest = string[1+llen+length:] + return tag, body, rest + +def remove_sequence(string): + if not string: + raise UnexpectedDER("Empty string does not encode a sequence") + if not string.startswith(b("\x30")): + n = string[0] if isinstance(string[0], integer_types) else \ + ord(string[0]) + raise UnexpectedDER("wanted type 'sequence' (0x30), got 0x%02x" % n) + length, lengthlength = read_length(string[1:]) + if length > len(string) - 1 - lengthlength: + raise UnexpectedDER("Length longer than the provided buffer") + endseq = 1+lengthlength+length + return string[1+lengthlength:endseq], string[endseq:] + +def remove_octet_string(string): + if not string.startswith(b("\x04")): + n = string[0] if isinstance(string[0], integer_types) else ord(string[0]) + raise UnexpectedDER("wanted octetstring (0x04), got 0x%02x" % n) + length, llen = read_length(string[1:]) + body = string[1+llen:1+llen+length] + rest = string[1+llen+length:] + return body, rest + +def remove_object(string): + if not string.startswith(b("\x06")): + n = string[0] if isinstance(string[0], integer_types) else ord(string[0]) + raise UnexpectedDER("wanted object (0x06), got 0x%02x" % n) + length, lengthlength = read_length(string[1:]) + body = string[1+lengthlength:1+lengthlength+length] + rest = string[1+lengthlength+length:] + numbers = [] + while body: + n, ll = read_number(body) + numbers.append(n) + body = body[ll:] + n0 = numbers.pop(0) + first = n0//40 + second = n0-(40*first) + numbers.insert(0, first) + numbers.insert(1, second) + return tuple(numbers), rest + +def remove_integer(string): + if not string: + raise UnexpectedDER("Empty string is an invalid encoding of an " + "integer") + if not string.startswith(b("\x02")): + n = string[0] if isinstance(string[0], integer_types) \ + else ord(string[0]) + raise UnexpectedDER("wanted type 'integer' (0x02), got 0x%02x" % n) + length, llen = read_length(string[1:]) + if length > len(string) - 1 - llen: + raise UnexpectedDER("Length longer than provided buffer") + if length == 0: + raise UnexpectedDER("0-byte long encoding of integer") + numberbytes = string[1+llen:1+llen+length] + rest = string[1+llen+length:] + msb = numberbytes[0] if isinstance(numberbytes[0], integer_types) \ + else ord(numberbytes[0]) + if not msb < 0x80: + raise UnexpectedDER("Negative integers are not supported") + # check if the encoding is the minimal one (DER requirement) + if length > 1 and not msb: + # leading zero byte is allowed if the integer would have been + # considered a negative number otherwise + smsb = numberbytes[1] if isinstance(numberbytes[1], integer_types) \ + else ord(numberbytes[1]) + if smsb < 0x80: + raise UnexpectedDER("Invalid encoding of integer, unnecessary " + "zero padding bytes") + return int(binascii.hexlify(numberbytes), 16), rest + +def read_number(string): + number = 0 + llen = 0 + # base-128 big endian, with b7 set in all but the last byte + while True: + if llen > len(string): + raise UnexpectedDER("ran out of length bytes") + number = number << 7 + d = string[llen] if isinstance(string[llen], integer_types) else ord(string[llen]) + number += (d & 0x7f) + llen += 1 + if not d & 0x80: + break + return number, llen + +def encode_length(l): + assert l >= 0 + if l < 0x80: + return int2byte(l) + s = ("%x" % l).encode() + if len(s)%2: + s = b("0")+s + s = binascii.unhexlify(s) + llen = len(s) + return int2byte(0x80|llen) + s + +def read_length(string): + if not string: + raise UnexpectedDER("Empty string can't encode valid length value") + num = string[0] if isinstance(string[0], integer_types) else ord(string[0]) + if not (num & 0x80): + # short form + return (num & 0x7f), 1 + # else long-form: b0&0x7f is number of additional base256 length bytes, + # big-endian + llen = num & 0x7f + if not llen: + raise UnexpectedDER("Invalid length encoding, length of length is 0") + if llen > len(string)-1: + raise UnexpectedDER("Length of length longer than provided buffer") + # verify that the encoding is minimal possible (DER requirement) + msb = string[1] if isinstance(string[1], integer_types) else ord(string[1]) + if not msb or llen == 1 and msb < 0x80: + raise UnexpectedDER("Not minimal encoding of length") + return int(binascii.hexlify(string[1:1+llen]), 16), 1+llen + +def remove_bitstring(string): + num = string[0] if isinstance(string[0], integer_types) else ord(string[0]) + if not string.startswith(b("\x03")): + raise UnexpectedDER("wanted bitstring (0x03), got 0x%02x" % num) + length, llen = read_length(string[1:]) + body = string[1+llen:1+llen+length] + rest = string[1+llen+length:] + return body, rest + +# SEQUENCE([1, STRING(secexp), cont[0], OBJECT(curvename), cont[1], BINTSTRING) + + +# signatures: (from RFC3279) +# ansi-X9-62 OBJECT IDENTIFIER ::= { +# iso(1) member-body(2) us(840) 10045 } +# +# id-ecSigType OBJECT IDENTIFIER ::= { +# ansi-X9-62 signatures(4) } +# ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { +# id-ecSigType 1 } +## so 1,2,840,10045,4,1 +## so 0x42, .. .. + +# Ecdsa-Sig-Value ::= SEQUENCE { +# r INTEGER, +# s INTEGER } + +# id-public-key-type OBJECT IDENTIFIER ::= { ansi-X9.62 2 } +# +# id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 } + +# I think the secp224r1 identifier is (t=06,l=05,v=2b81040021) +# secp224r1 OBJECT IDENTIFIER ::= { +# iso(1) identified-organization(3) certicom(132) curve(0) 33 } +# and the secp384r1 is (t=06,l=05,v=2b81040022) +# secp384r1 OBJECT IDENTIFIER ::= { +# iso(1) identified-organization(3) certicom(132) curve(0) 34 } + +def unpem(pem): + if isinstance(pem, text_type): + pem = pem.encode() + + d = b("").join([l.strip() for l in pem.split(b("\n")) + if l and not l.startswith(b("-----"))]) + return base64.b64decode(d) +def topem(der, name): + b64 = base64.b64encode(der) + lines = [("-----BEGIN %s-----\n" % name).encode()] + lines.extend([b64[start:start+64]+b("\n") + for start in range(0, len(b64), 64)]) + lines.append(("-----END %s-----\n" % name).encode()) + return b("").join(lines) + diff --git a/Lambdas/Websocket Authorizer/ecdsa/ecdsa.py b/Lambdas/Websocket Authorizer/ecdsa/ecdsa.py new file mode 100644 index 0000000..4eb2d39 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/ecdsa.py @@ -0,0 +1,576 @@ +#! /usr/bin/env python + +""" +Implementation of Elliptic-Curve Digital Signatures. + +Classes and methods for elliptic-curve signatures: +private keys, public keys, signatures, +NIST prime-modulus curves with modulus lengths of +192, 224, 256, 384, and 521 bits. + +Example: + + # (In real-life applications, you would probably want to + # protect against defects in SystemRandom.) + from random import SystemRandom + randrange = SystemRandom().randrange + + # Generate a public/private key pair using the NIST Curve P-192: + + g = generator_192 + n = g.order() + secret = randrange( 1, n ) + pubkey = Public_key( g, g * secret ) + privkey = Private_key( pubkey, secret ) + + # Signing a hash value: + + hash = randrange( 1, n ) + signature = privkey.sign( hash, randrange( 1, n ) ) + + # Verifying a signature for a hash value: + + if pubkey.verifies( hash, signature ): + print_("Demo verification succeeded.") + else: + print_("*** Demo verification failed.") + + # Verification fails if the hash value is modified: + + if pubkey.verifies( hash-1, signature ): + print_("**** Demo verification failed to reject tampered hash.") + else: + print_("Demo verification correctly rejected tampered hash.") + +Version of 2009.05.16. + +Revision history: + 2005.12.31 - Initial version. + 2008.11.25 - Substantial revisions introducing new classes. + 2009.05.16 - Warn against using random.randrange in real applications. + 2009.05.17 - Use random.SystemRandom by default. + +Written in 2005 by Peter Pearson and placed in the public domain. +""" + +from .six import int2byte, b, print_ +from . import ellipticcurve +from . import numbertheory +import random + + + +class Signature( object ): + """ECDSA signature. + """ + def __init__( self, r, s ): + self.r = r + self.s = s + + + +class Public_key( object ): + """Public key for ECDSA. + """ + + def __init__( self, generator, point ): + """generator is the Point that generates the group, + point is the Point that defines the public key. + """ + + self.curve = generator.curve() + self.generator = generator + self.point = point + n = generator.order() + if not n: + raise RuntimeError("Generator point must have order.") + if not n * point == ellipticcurve.INFINITY: + raise RuntimeError("Generator point order is bad.") + if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y(): + raise RuntimeError("Generator point has x or y out of range.") + + + def verifies( self, hash, signature ): + """Verify that signature is a valid signature of hash. + Return True if the signature is valid. + """ + + # From X9.62 J.3.1. + + G = self.generator + n = G.order() + r = signature.r + s = signature.s + if r < 1 or r > n-1: return False + if s < 1 or s > n-1: return False + c = numbertheory.inverse_mod( s, n ) + u1 = ( hash * c ) % n + u2 = ( r * c ) % n + xy = u1 * G + u2 * self.point + v = xy.x() % n + return v == r + + + +class Private_key( object ): + """Private key for ECDSA. + """ + + def __init__( self, public_key, secret_multiplier ): + """public_key is of class Public_key; + secret_multiplier is a large integer. + """ + + self.public_key = public_key + self.secret_multiplier = secret_multiplier + + def sign( self, hash, random_k ): + """Return a signature for the provided hash, using the provided + random nonce. It is absolutely vital that random_k be an unpredictable + number in the range [1, self.public_key.point.order()-1]. If + an attacker can guess random_k, he can compute our private key from a + single signature. Also, if an attacker knows a few high-order + bits (or a few low-order bits) of random_k, he can compute our private + key from many signatures. The generation of nonces with adequate + cryptographic strength is very difficult and far beyond the scope + of this comment. + + May raise RuntimeError, in which case retrying with a new + random value k is in order. + """ + + G = self.public_key.generator + n = G.order() + k = random_k % n + p1 = k * G + r = p1.x() + if r == 0: raise RuntimeError("amazingly unlucky random number r") + s = ( numbertheory.inverse_mod( k, n ) * \ + ( hash + ( self.secret_multiplier * r ) % n ) ) % n + if s == 0: raise RuntimeError("amazingly unlucky random number s") + return Signature( r, s ) + + + +def int_to_string( x ): + """Convert integer x into a string of bytes, as per X9.62.""" + assert x >= 0 + if x == 0: return b('\0') + result = [] + while x: + ordinal = x & 0xFF + result.append(int2byte(ordinal)) + x >>= 8 + + result.reverse() + return b('').join(result) + + +def string_to_int( s ): + """Convert a string of bytes into an integer, as per X9.62.""" + result = 0 + for c in s: + if not isinstance(c, int): c = ord( c ) + result = 256 * result + c + return result + + +def digest_integer( m ): + """Convert an integer into a string of bytes, compute + its SHA-1 hash, and convert the result to an integer.""" + # + # I don't expect this function to be used much. I wrote + # it in order to be able to duplicate the examples + # in ECDSAVS. + # + from hashlib import sha1 + return string_to_int( sha1( int_to_string( m ) ).digest() ) + + +def point_is_valid( generator, x, y ): + """Is (x,y) a valid public key based on the specified generator?""" + + # These are the tests specified in X9.62. + + n = generator.order() + curve = generator.curve() + if x < 0 or n <= x or y < 0 or n <= y: + return False + if not curve.contains_point( x, y ): + return False + if not n*ellipticcurve.Point( curve, x, y ) == \ + ellipticcurve.INFINITY: + return False + return True + + + +# NIST Curve P-192: +_p = 6277101735386680763835789423207666416083908700390324961279 +_r = 6277101735386680763835789423176059013767194773182842284081 +# s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L +# c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65L +_b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1 +_Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012 +_Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 + +curve_192 = ellipticcurve.CurveFp( _p, -3, _b ) +generator_192 = ellipticcurve.Point( curve_192, _Gx, _Gy, _r ) + + +# NIST Curve P-224: +_p = 26959946667150639794667015087019630673557916260026308143510066298881 +_r = 26959946667150639794667015087019625940457807714424391721682722368061 +# s = 0xbd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5L +# c = 0x5b056c7e11dd68f40469ee7f3c7a7d74f7d121116506d031218291fbL +_b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4 +_Gx =0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21 +_Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34 + +curve_224 = ellipticcurve.CurveFp( _p, -3, _b ) +generator_224 = ellipticcurve.Point( curve_224, _Gx, _Gy, _r ) + +# NIST Curve P-256: +_p = 115792089210356248762697446949407573530086143415290314195533631308867097853951 +_r = 115792089210356248762697446949407573529996955224135760342422259061068512044369 +# s = 0xc49d360886e704936a6678e1139d26b7819f7e90L +# c = 0x7efba1662985be9403cb055c75d4f7e0ce8d84a9c5114abcaf3177680104fa0dL +_b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b +_Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 +_Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 + +curve_256 = ellipticcurve.CurveFp( _p, -3, _b ) +generator_256 = ellipticcurve.Point( curve_256, _Gx, _Gy, _r ) + +# NIST Curve P-384: +_p = 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319 +_r = 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643 +# s = 0xa335926aa319a27a1d00896a6773a4827acdac73L +# c = 0x79d1e655f868f02fff48dcdee14151ddb80643c1406d0ca10dfe6fc52009540a495e8042ea5f744f6e184667cc722483L +_b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef +_Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7 +_Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f + +curve_384 = ellipticcurve.CurveFp( _p, -3, _b ) +generator_384 = ellipticcurve.Point( curve_384, _Gx, _Gy, _r ) + +# NIST Curve P-521: +_p = 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151 +_r = 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449 +# s = 0xd09e8800291cb85396cc6717393284aaa0da64baL +# c = 0x0b48bfa5f420a34949539d2bdfc264eeeeb077688e44fbf0ad8f6d0edb37bd6b533281000518e19f1b9ffbe0fe9ed8a3c2200b8f875e523868c70c1e5bf55bad637L +_b = 0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00 +_Gx = 0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66 +_Gy = 0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650 + +curve_521 = ellipticcurve.CurveFp( _p, -3, _b ) +generator_521 = ellipticcurve.Point( curve_521, _Gx, _Gy, _r ) + +# Certicom secp256-k1 +_a = 0x0000000000000000000000000000000000000000000000000000000000000000 +_b = 0x0000000000000000000000000000000000000000000000000000000000000007 +_p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f +_Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 +_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 +_r = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 + +curve_secp256k1 = ellipticcurve.CurveFp( _p, _a, _b) +generator_secp256k1 = ellipticcurve.Point( curve_secp256k1, _Gx, _Gy, _r) + + + +def __main__(): + class TestFailure(Exception): pass + + def test_point_validity( generator, x, y, expected ): + """generator defines the curve; is (x,y) a point on + this curve? "expected" is True if the right answer is Yes.""" + if point_is_valid( generator, x, y ) == expected: + print_("Point validity tested as expected.") + else: + raise TestFailure("*** Point validity test gave wrong result.") + + def test_signature_validity( Msg, Qx, Qy, R, S, expected ): + """Msg = message, Qx and Qy represent the base point on + elliptic curve c192, R and S are the signature, and + "expected" is True iff the signature is expected to be valid.""" + pubk = Public_key( generator_192, + ellipticcurve.Point( curve_192, Qx, Qy ) ) + got = pubk.verifies( digest_integer( Msg ), Signature( R, S ) ) + if got == expected: + print_("Signature tested as expected: got %s, expected %s." % \ + ( got, expected )) + else: + raise TestFailure("*** Signature test failed: got %s, expected %s." % \ + ( got, expected )) + + print_("NIST Curve P-192:") + + p192 = generator_192 + + # From X9.62: + + d = 651056770906015076056810763456358567190100156695615665659 + Q = d * p192 + if Q.x() != 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5: + raise TestFailure("*** p192 * d came out wrong.") + else: + print_("p192 * d came out right.") + + k = 6140507067065001063065065565667405560006161556565665656654 + R = k * p192 + if R.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD \ + or R.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835: + raise TestFailure("*** k * p192 came out wrong.") + else: + print_("k * p192 came out right.") + + u1 = 2563697409189434185194736134579731015366492496392189760599 + u2 = 6266643813348617967186477710235785849136406323338782220568 + temp = u1 * p192 + u2 * Q + if temp.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD \ + or temp.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835: + raise TestFailure("*** u1 * p192 + u2 * Q came out wrong.") + else: + print_("u1 * p192 + u2 * Q came out right.") + + e = 968236873715988614170569073515315707566766479517 + pubk = Public_key( generator_192, generator_192 * d ) + privk = Private_key( pubk, d ) + sig = privk.sign( e, k ) + r, s = sig.r, sig.s + if r != 3342403536405981729393488334694600415596881826869351677613 \ + or s != 5735822328888155254683894997897571951568553642892029982342: + raise TestFailure("*** r or s came out wrong.") + else: + print_("r and s came out right.") + + valid = pubk.verifies( e, sig ) + if valid: print_("Signature verified OK.") + else: raise TestFailure("*** Signature failed verification.") + + valid = pubk.verifies( e-1, sig ) + if not valid: print_("Forgery was correctly rejected.") + else: raise TestFailure("*** Forgery was erroneously accepted.") + + print_("Testing point validity, as per ECDSAVS.pdf B.2.2:") + + test_point_validity( \ + p192, \ + 0xcd6d0f029a023e9aaca429615b8f577abee685d8257cc83a, \ + 0x00019c410987680e9fb6c0b6ecc01d9a2647c8bae27721bacdfc, \ + False ) + + test_point_validity( + p192, \ + 0x00017f2fce203639e9eaf9fb50b81fc32776b30e3b02af16c73b, \ + 0x95da95c5e72dd48e229d4748d4eee658a9a54111b23b2adb, \ + False ) + + test_point_validity( + p192, \ + 0x4f77f8bc7fccbadd5760f4938746d5f253ee2168c1cf2792, \ + 0x000147156ff824d131629739817edb197717c41aab5c2a70f0f6, \ + False ) + + test_point_validity( + p192, \ + 0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6, \ + 0x8804dc7a7c4c7f8b5d437f5156f3312ca7d6de8a0e11867f, \ + True ) + + test_point_validity( + p192, \ + 0xcdf56c1aa3d8afc53c521adf3ffb96734a6a630a4a5b5a70, \ + 0x97c1c44a5fb229007b5ec5d25f7413d170068ffd023caa4e, \ + True ) + + test_point_validity( + p192, \ + 0x89009c0dc361c81e99280c8e91df578df88cdf4b0cdedced, \ + 0x27be44a529b7513e727251f128b34262a0fd4d8ec82377b9, \ + True ) + + test_point_validity( + p192, \ + 0x6a223d00bd22c52833409a163e057e5b5da1def2a197dd15, \ + 0x7b482604199367f1f303f9ef627f922f97023e90eae08abf, \ + True ) + + test_point_validity( + p192, \ + 0x6dccbde75c0948c98dab32ea0bc59fe125cf0fb1a3798eda, \ + 0x0001171a3e0fa60cf3096f4e116b556198de430e1fbd330c8835, \ + False ) + + test_point_validity( + p192, \ + 0xd266b39e1f491fc4acbbbc7d098430931cfa66d55015af12, \ + 0x193782eb909e391a3148b7764e6b234aa94e48d30a16dbb2, \ + False ) + + test_point_validity( + p192, \ + 0x9d6ddbcd439baa0c6b80a654091680e462a7d1d3f1ffeb43, \ + 0x6ad8efc4d133ccf167c44eb4691c80abffb9f82b932b8caa, \ + False ) + + test_point_validity( + p192, \ + 0x146479d944e6bda87e5b35818aa666a4c998a71f4e95edbc, \ + 0xa86d6fe62bc8fbd88139693f842635f687f132255858e7f6, \ + False ) + + test_point_validity( + p192, \ + 0xe594d4a598046f3598243f50fd2c7bd7d380edb055802253, \ + 0x509014c0c4d6b536e3ca750ec09066af39b4c8616a53a923, \ + False ) + + print_("Trying signature-verification tests from ECDSAVS.pdf B.2.4:") + print_("P-192:") + Msg = 0x84ce72aa8699df436059f052ac51b6398d2511e49631bcb7e71f89c499b9ee425dfbc13a5f6d408471b054f2655617cbbaf7937b7c80cd8865cf02c8487d30d2b0fbd8b2c4e102e16d828374bbc47b93852f212d5043c3ea720f086178ff798cc4f63f787b9c2e419efa033e7644ea7936f54462dc21a6c4580725f7f0e7d158 + Qx = 0xd9dbfb332aa8e5ff091e8ce535857c37c73f6250ffb2e7ac + Qy = 0x282102e364feded3ad15ddf968f88d8321aa268dd483ebc4 + R = 0x64dca58a20787c488d11d6dd96313f1b766f2d8efe122916 + S = 0x1ecba28141e84ab4ecad92f56720e2cc83eb3d22dec72479 + test_signature_validity( Msg, Qx, Qy, R, S, True ) + + Msg = 0x94bb5bacd5f8ea765810024db87f4224ad71362a3c28284b2b9f39fab86db12e8beb94aae899768229be8fdb6c4f12f28912bb604703a79ccff769c1607f5a91450f30ba0460d359d9126cbd6296be6d9c4bb96c0ee74cbb44197c207f6db326ab6f5a659113a9034e54be7b041ced9dcf6458d7fb9cbfb2744d999f7dfd63f4 + Qx = 0x3e53ef8d3112af3285c0e74842090712cd324832d4277ae7 + Qy = 0xcc75f8952d30aec2cbb719fc6aa9934590b5d0ff5a83adb7 + R = 0x8285261607283ba18f335026130bab31840dcfd9c3e555af + S = 0x356d89e1b04541afc9704a45e9c535ce4a50929e33d7e06c + test_signature_validity( Msg, Qx, Qy, R, S, True ) + + Msg = 0xf6227a8eeb34afed1621dcc89a91d72ea212cb2f476839d9b4243c66877911b37b4ad6f4448792a7bbba76c63bdd63414b6facab7dc71c3396a73bd7ee14cdd41a659c61c99b779cecf07bc51ab391aa3252386242b9853ea7da67fd768d303f1b9b513d401565b6f1eb722dfdb96b519fe4f9bd5de67ae131e64b40e78c42dd + Qx = 0x16335dbe95f8e8254a4e04575d736befb258b8657f773cb7 + Qy = 0x421b13379c59bc9dce38a1099ca79bbd06d647c7f6242336 + R = 0x4141bd5d64ea36c5b0bd21ef28c02da216ed9d04522b1e91 + S = 0x159a6aa852bcc579e821b7bb0994c0861fb08280c38daa09 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x16b5f93afd0d02246f662761ed8e0dd9504681ed02a253006eb36736b563097ba39f81c8e1bce7a16c1339e345efabbc6baa3efb0612948ae51103382a8ee8bc448e3ef71e9f6f7a9676694831d7f5dd0db5446f179bcb737d4a526367a447bfe2c857521c7f40b6d7d7e01a180d92431fb0bbd29c04a0c420a57b3ed26ccd8a + Qx = 0xfd14cdf1607f5efb7b1793037b15bdf4baa6f7c16341ab0b + Qy = 0x83fa0795cc6c4795b9016dac928fd6bac32f3229a96312c4 + R = 0x8dfdb832951e0167c5d762a473c0416c5c15bc1195667dc1 + S = 0x1720288a2dc13fa1ec78f763f8fe2ff7354a7e6fdde44520 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x08a2024b61b79d260e3bb43ef15659aec89e5b560199bc82cf7c65c77d39192e03b9a895d766655105edd9188242b91fbde4167f7862d4ddd61e5d4ab55196683d4f13ceb90d87aea6e07eb50a874e33086c4a7cb0273a8e1c4408f4b846bceae1ebaac1b2b2ea851a9b09de322efe34cebe601653efd6ddc876ce8c2f2072fb + Qx = 0x674f941dc1a1f8b763c9334d726172d527b90ca324db8828 + Qy = 0x65adfa32e8b236cb33a3e84cf59bfb9417ae7e8ede57a7ff + R = 0x9508b9fdd7daf0d8126f9e2bc5a35e4c6d800b5b804d7796 + S = 0x36f2bf6b21b987c77b53bb801b3435a577e3d493744bfab0 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x1843aba74b0789d4ac6b0b8923848023a644a7b70afa23b1191829bbe4397ce15b629bf21a8838298653ed0c19222b95fa4f7390d1b4c844d96e645537e0aae98afb5c0ac3bd0e4c37f8daaff25556c64e98c319c52687c904c4de7240a1cc55cd9756b7edaef184e6e23b385726e9ffcba8001b8f574987c1a3fedaaa83ca6d + Qx = 0x10ecca1aad7220b56a62008b35170bfd5e35885c4014a19f + Qy = 0x04eb61984c6c12ade3bc47f3c629ece7aa0a033b9948d686 + R = 0x82bfa4e82c0dfe9274169b86694e76ce993fd83b5c60f325 + S = 0xa97685676c59a65dbde002fe9d613431fb183e8006d05633 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x5a478f4084ddd1a7fea038aa9732a822106385797d02311aeef4d0264f824f698df7a48cfb6b578cf3da416bc0799425bb491be5b5ecc37995b85b03420a98f2c4dc5c31a69a379e9e322fbe706bbcaf0f77175e05cbb4fa162e0da82010a278461e3e974d137bc746d1880d6eb02aa95216014b37480d84b87f717bb13f76e1 + Qx = 0x6636653cb5b894ca65c448277b29da3ad101c4c2300f7c04 + Qy = 0xfdf1cbb3fc3fd6a4f890b59e554544175fa77dbdbeb656c1 + R = 0xeac2ddecddfb79931a9c3d49c08de0645c783a24cb365e1c + S = 0x3549fee3cfa7e5f93bc47d92d8ba100e881a2a93c22f8d50 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0xc598774259a058fa65212ac57eaa4f52240e629ef4c310722088292d1d4af6c39b49ce06ba77e4247b20637174d0bd67c9723feb57b5ead232b47ea452d5d7a089f17c00b8b6767e434a5e16c231ba0efa718a340bf41d67ea2d295812ff1b9277daacb8bc27b50ea5e6443bcf95ef4e9f5468fe78485236313d53d1c68f6ba2 + Qx = 0xa82bd718d01d354001148cd5f69b9ebf38ff6f21898f8aaa + Qy = 0xe67ceede07fc2ebfafd62462a51e4b6c6b3d5b537b7caf3e + R = 0x4d292486c620c3de20856e57d3bb72fcde4a73ad26376955 + S = 0xa85289591a6081d5728825520e62ff1c64f94235c04c7f95 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0xca98ed9db081a07b7557f24ced6c7b9891269a95d2026747add9e9eb80638a961cf9c71a1b9f2c29744180bd4c3d3db60f2243c5c0b7cc8a8d40a3f9a7fc910250f2187136ee6413ffc67f1a25e1c4c204fa9635312252ac0e0481d89b6d53808f0c496ba87631803f6c572c1f61fa049737fdacce4adff757afed4f05beb658 + Qx = 0x7d3b016b57758b160c4fca73d48df07ae3b6b30225126c2f + Qy = 0x4af3790d9775742bde46f8da876711be1b65244b2b39e7ec + R = 0x95f778f5f656511a5ab49a5d69ddd0929563c29cbc3a9e62 + S = 0x75c87fc358c251b4c83d2dd979faad496b539f9f2ee7a289 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x31dd9a54c8338bea06b87eca813d555ad1850fac9742ef0bbe40dad400e10288acc9c11ea7dac79eb16378ebea9490e09536099f1b993e2653cd50240014c90a9c987f64545abc6a536b9bd2435eb5e911fdfde2f13be96ea36ad38df4ae9ea387b29cced599af777338af2794820c9cce43b51d2112380a35802ab7e396c97a + Qx = 0x9362f28c4ef96453d8a2f849f21e881cd7566887da8beb4a + Qy = 0xe64d26d8d74c48a024ae85d982ee74cd16046f4ee5333905 + R = 0xf3923476a296c88287e8de914b0b324ad5a963319a4fe73b + S = 0xf0baeed7624ed00d15244d8ba2aede085517dbdec8ac65f5 + test_signature_validity( Msg, Qx, Qy, R, S, True ) + + Msg = 0xb2b94e4432267c92f9fdb9dc6040c95ffa477652761290d3c7de312283f6450d89cc4aabe748554dfb6056b2d8e99c7aeaad9cdddebdee9dbc099839562d9064e68e7bb5f3a6bba0749ca9a538181fc785553a4000785d73cc207922f63e8ce1112768cb1de7b673aed83a1e4a74592f1268d8e2a4e9e63d414b5d442bd0456d + Qx = 0xcc6fc032a846aaac25533eb033522824f94e670fa997ecef + Qy = 0xe25463ef77a029eccda8b294fd63dd694e38d223d30862f1 + R = 0x066b1d07f3a40e679b620eda7f550842a35c18b80c5ebe06 + S = 0xa0b0fb201e8f2df65e2c4508ef303bdc90d934016f16b2dc + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x4366fcadf10d30d086911de30143da6f579527036937007b337f7282460eae5678b15cccda853193ea5fc4bc0a6b9d7a31128f27e1214988592827520b214eed5052f7775b750b0c6b15f145453ba3fee24a085d65287e10509eb5d5f602c440341376b95c24e5c4727d4b859bfe1483d20538acdd92c7997fa9c614f0f839d7 + Qx = 0x955c908fe900a996f7e2089bee2f6376830f76a19135e753 + Qy = 0xba0c42a91d3847de4a592a46dc3fdaf45a7cc709b90de520 + R = 0x1f58ad77fc04c782815a1405b0925e72095d906cbf52a668 + S = 0xf2e93758b3af75edf784f05a6761c9b9a6043c66b845b599 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x543f8af57d750e33aa8565e0cae92bfa7a1ff78833093421c2942cadf9986670a5ff3244c02a8225e790fbf30ea84c74720abf99cfd10d02d34377c3d3b41269bea763384f372bb786b5846f58932defa68023136cd571863b304886e95e52e7877f445b9364b3f06f3c28da12707673fecb4b8071de06b6e0a3c87da160cef3 + Qx = 0x31f7fa05576d78a949b24812d4383107a9a45bb5fccdd835 + Qy = 0x8dc0eb65994a90f02b5e19bd18b32d61150746c09107e76b + R = 0xbe26d59e4e883dde7c286614a767b31e49ad88789d3a78ff + S = 0x8762ca831c1ce42df77893c9b03119428e7a9b819b619068 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0xd2e8454143ce281e609a9d748014dcebb9d0bc53adb02443a6aac2ffe6cb009f387c346ecb051791404f79e902ee333ad65e5c8cb38dc0d1d39a8dc90add5023572720e5b94b190d43dd0d7873397504c0c7aef2727e628eb6a74411f2e400c65670716cb4a815dc91cbbfeb7cfe8c929e93184c938af2c078584da045e8f8d1 + Qx = 0x66aa8edbbdb5cf8e28ceb51b5bda891cae2df84819fe25c0 + Qy = 0x0c6bc2f69030a7ce58d4a00e3b3349844784a13b8936f8da + R = 0xa4661e69b1734f4a71b788410a464b71e7ffe42334484f23 + S = 0x738421cf5e049159d69c57a915143e226cac8355e149afe9 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + Msg = 0x6660717144040f3e2f95a4e25b08a7079c702a8b29babad5a19a87654bc5c5afa261512a11b998a4fb36b5d8fe8bd942792ff0324b108120de86d63f65855e5461184fc96a0a8ffd2ce6d5dfb0230cbbdd98f8543e361b3205f5da3d500fdc8bac6db377d75ebef3cb8f4d1ff738071ad0938917889250b41dd1d98896ca06fb + Qx = 0xbcfacf45139b6f5f690a4c35a5fffa498794136a2353fc77 + Qy = 0x6f4a6c906316a6afc6d98fe1f0399d056f128fe0270b0f22 + R = 0x9db679a3dafe48f7ccad122933acfe9da0970b71c94c21c1 + S = 0x984c2db99827576c0a41a5da41e07d8cc768bc82f18c9da9 + test_signature_validity( Msg, Qx, Qy, R, S, False ) + + + + print_("Testing the example code:") + + # Building a public/private key pair from the NIST Curve P-192: + + g = generator_192 + n = g.order() + + # (random.SystemRandom is supposed to provide + # crypto-quality random numbers, but as Debian recently + # illustrated, a systems programmer can accidentally + # demolish this security, so in serious applications + # further precautions are appropriate.) + + randrange = random.SystemRandom().randrange + + secret = randrange( 1, n ) + pubkey = Public_key( g, g * secret ) + privkey = Private_key( pubkey, secret ) + + # Signing a hash value: + + hash = randrange( 1, n ) + signature = privkey.sign( hash, randrange( 1, n ) ) + + # Verifying a signature for a hash value: + + if pubkey.verifies( hash, signature ): + print_("Demo verification succeeded.") + else: + raise TestFailure("*** Demo verification failed.") + + if pubkey.verifies( hash-1, signature ): + raise TestFailure( "**** Demo verification failed to reject tampered hash.") + else: + print_("Demo verification correctly rejected tampered hash.") + +if __name__ == "__main__": + __main__() diff --git a/Lambdas/Websocket Authorizer/ecdsa/ellipticcurve.py b/Lambdas/Websocket Authorizer/ecdsa/ellipticcurve.py new file mode 100644 index 0000000..390bb35 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/ellipticcurve.py @@ -0,0 +1,293 @@ +#! /usr/bin/env python +# +# Implementation of elliptic curves, for cryptographic applications. +# +# This module doesn't provide any way to choose a random elliptic +# curve, nor to verify that an elliptic curve was chosen randomly, +# because one can simply use NIST's standard curves. +# +# Notes from X9.62-1998 (draft): +# Nomenclature: +# - Q is a public key. +# The "Elliptic Curve Domain Parameters" include: +# - q is the "field size", which in our case equals p. +# - p is a big prime. +# - G is a point of prime order (5.1.1.1). +# - n is the order of G (5.1.1.1). +# Public-key validation (5.2.2): +# - Verify that Q is not the point at infinity. +# - Verify that X_Q and Y_Q are in [0,p-1]. +# - Verify that Q is on the curve. +# - Verify that nQ is the point at infinity. +# Signature generation (5.3): +# - Pick random k from [1,n-1]. +# Signature checking (5.4.2): +# - Verify that r and s are in [1,n-1]. +# +# Version of 2008.11.25. +# +# Revision history: +# 2005.12.31 - Initial version. +# 2008.11.25 - Change CurveFp.is_on to contains_point. +# +# Written in 2005 by Peter Pearson and placed in the public domain. + +from __future__ import division + +from .six import print_ +from . import numbertheory + +class CurveFp( object ): + """Elliptic Curve over the field of integers modulo a prime.""" + def __init__( self, p, a, b ): + """The curve of points satisfying y^2 = x^3 + a*x + b (mod p).""" + self.__p = p + self.__a = a + self.__b = b + + def p( self ): + return self.__p + + def a( self ): + return self.__a + + def b( self ): + return self.__b + + def contains_point( self, x, y ): + """Is the point (x,y) on this curve?""" + return ( y * y - ( x * x * x + self.__a * x + self.__b ) ) % self.__p == 0 + + + +class Point( object ): + """A point on an elliptic curve. Altering x and y is forbidding, + but they can be read by the x() and y() methods.""" + def __init__( self, curve, x, y, order = None ): + """curve, x, y, order; order (optional) is the order of this point.""" + self.__curve = curve + self.__x = x + self.__y = y + self.__order = order + # self.curve is allowed to be None only for INFINITY: + if self.__curve: assert self.__curve.contains_point( x, y ) + if order: assert self * order == INFINITY + + def __eq__( self, other ): + """Return True if the points are identical, False otherwise.""" + if self.__curve == other.__curve \ + and self.__x == other.__x \ + and self.__y == other.__y: + return True + else: + return False + + def __add__( self, other ): + """Add one point to another point.""" + + # X9.62 B.3: + + if other == INFINITY: return self + if self == INFINITY: return other + assert self.__curve == other.__curve + if self.__x == other.__x: + if ( self.__y + other.__y ) % self.__curve.p() == 0: + return INFINITY + else: + return self.double() + + p = self.__curve.p() + + l = ( ( other.__y - self.__y ) * \ + numbertheory.inverse_mod( other.__x - self.__x, p ) ) % p + + x3 = ( l * l - self.__x - other.__x ) % p + y3 = ( l * ( self.__x - x3 ) - self.__y ) % p + + return Point( self.__curve, x3, y3 ) + + def __mul__( self, other ): + """Multiply a point by an integer.""" + + def leftmost_bit( x ): + assert x > 0 + result = 1 + while result <= x: result = 2 * result + return result // 2 + + e = other + if self.__order: e = e % self.__order + if e == 0: return INFINITY + if self == INFINITY: return INFINITY + assert e > 0 + + # From X9.62 D.3.2: + + e3 = 3 * e + negative_self = Point( self.__curve, self.__x, -self.__y, self.__order ) + i = leftmost_bit( e3 ) // 2 + result = self + # print_("Multiplying %s by %d (e3 = %d):" % ( self, other, e3 )) + while i > 1: + result = result.double() + if ( e3 & i ) != 0 and ( e & i ) == 0: result = result + self + if ( e3 & i ) == 0 and ( e & i ) != 0: result = result + negative_self + # print_(". . . i = %d, result = %s" % ( i, result )) + i = i // 2 + + return result + + def __rmul__( self, other ): + """Multiply a point by an integer.""" + + return self * other + + def __str__( self ): + if self == INFINITY: return "infinity" + return "(%d,%d)" % ( self.__x, self.__y ) + + def double( self ): + """Return a new point that is twice the old.""" + + if self == INFINITY: + return INFINITY + + # X9.62 B.3: + + p = self.__curve.p() + a = self.__curve.a() + + l = ( ( 3 * self.__x * self.__x + a ) * \ + numbertheory.inverse_mod( 2 * self.__y, p ) ) % p + + x3 = ( l * l - 2 * self.__x ) % p + y3 = ( l * ( self.__x - x3 ) - self.__y ) % p + + return Point( self.__curve, x3, y3 ) + + def x( self ): + return self.__x + + def y( self ): + return self.__y + + def curve( self ): + return self.__curve + + def order( self ): + return self.__order + + +# This one point is the Point At Infinity for all purposes: +INFINITY = Point( None, None, None ) + +def __main__(): + + class FailedTest(Exception): pass + def test_add( c, x1, y1, x2, y2, x3, y3 ): + """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" + p1 = Point( c, x1, y1 ) + p2 = Point( c, x2, y2 ) + p3 = p1 + p2 + print_("%s + %s = %s" % ( p1, p2, p3 ), end=' ') + if p3.x() != x3 or p3.y() != y3: + raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 )) + else: + print_(" Good.") + + def test_double( c, x1, y1, x3, y3 ): + """We expect that on curve c, 2*(x1,y1) = (x3, y3).""" + p1 = Point( c, x1, y1 ) + p3 = p1.double() + print_("%s doubled = %s" % ( p1, p3 ), end=' ') + if p3.x() != x3 or p3.y() != y3: + raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 )) + else: + print_(" Good.") + + def test_double_infinity( c ): + """We expect that on curve c, 2*INFINITY = INFINITY.""" + p1 = INFINITY + p3 = p1.double() + print_("%s doubled = %s" % ( p1, p3 ), end=' ') + if p3.x() != INFINITY.x() or p3.y() != INFINITY.y(): + raise FailedTest("Failure: should give (%d,%d)." % ( INFINITY.x(), INFINITY.y() )) + else: + print_(" Good.") + + def test_multiply( c, x1, y1, m, x3, y3 ): + """We expect that on curve c, m*(x1,y1) = (x3,y3).""" + p1 = Point( c, x1, y1 ) + p3 = p1 * m + print_("%s * %d = %s" % ( p1, m, p3 ), end=' ') + if p3.x() != x3 or p3.y() != y3: + raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 )) + else: + print_(" Good.") + + + # A few tests from X9.62 B.3: + + c = CurveFp( 23, 1, 1 ) + test_add( c, 3, 10, 9, 7, 17, 20 ) + test_double( c, 3, 10, 7, 12 ) + test_add( c, 3, 10, 3, 10, 7, 12 ) # (Should just invoke double.) + test_multiply( c, 3, 10, 2, 7, 12 ) + + test_double_infinity(c) + + # From X9.62 I.1 (p. 96): + + g = Point( c, 13, 7, 7 ) + + check = INFINITY + for i in range( 7 + 1 ): + p = ( i % 7 ) * g + print_("%s * %d = %s, expected %s . . ." % ( g, i, p, check ), end=' ') + if p == check: + print_(" Good.") + else: + raise FailedTest("Bad.") + check = check + g + + # NIST Curve P-192: + p = 6277101735386680763835789423207666416083908700390324961279 + r = 6277101735386680763835789423176059013767194773182842284081 + #s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L + c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65 + b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1 + Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012 + Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 + + c192 = CurveFp( p, -3, b ) + p192 = Point( c192, Gx, Gy, r ) + + # Checking against some sample computations presented + # in X9.62: + + d = 651056770906015076056810763456358567190100156695615665659 + Q = d * p192 + if Q.x() != 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5: + raise FailedTest("p192 * d came out wrong.") + else: + print_("p192 * d came out right.") + + k = 6140507067065001063065065565667405560006161556565665656654 + R = k * p192 + if R.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD \ + or R.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835: + raise FailedTest("k * p192 came out wrong.") + else: + print_("k * p192 came out right.") + + u1 = 2563697409189434185194736134579731015366492496392189760599 + u2 = 6266643813348617967186477710235785849136406323338782220568 + temp = u1 * p192 + u2 * Q + if temp.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD \ + or temp.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835: + raise FailedTest("u1 * p192 + u2 * Q came out wrong.") + else: + print_("u1 * p192 + u2 * Q came out right.") + +if __name__ == "__main__": + __main__() diff --git a/Lambdas/Websocket Authorizer/ecdsa/keys.py b/Lambdas/Websocket Authorizer/ecdsa/keys.py new file mode 100644 index 0000000..4519817 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/keys.py @@ -0,0 +1,307 @@ +import binascii + +from . import ecdsa +from . import der +from . import rfc6979 +from . import ellipticcurve +from .curves import NIST192p, find_curve +from .util import string_to_number, number_to_string, randrange +from .util import sigencode_string, sigdecode_string +from .util import oid_ecPublicKey, encoded_oid_ecPublicKey, MalformedSignature +from .six import PY3, b +from hashlib import sha1 + +class BadSignatureError(Exception): + pass +class BadDigestError(Exception): + pass + + +class MalformedPointError(AssertionError): + pass + + +class VerifyingKey: + def __init__(self, _error__please_use_generate=None): + if not _error__please_use_generate: + raise TypeError("Please use SigningKey.generate() to construct me") + + @classmethod + def from_public_point(klass, point, curve=NIST192p, hashfunc=sha1): + self = klass(_error__please_use_generate=True) + self.curve = curve + self.default_hashfunc = hashfunc + self.pubkey = ecdsa.Public_key(curve.generator, point) + self.pubkey.order = curve.order + return self + + @classmethod + def from_string(klass, string, curve=NIST192p, hashfunc=sha1, + validate_point=True): + order = curve.order + if len(string) != curve.verifying_key_length: + raise MalformedPointError( + "Malformed encoding of public point. Expected string {0} bytes" + " long, received {1} bytes long string".format( + curve.verifying_key_length, len(string))) + xs = string[:curve.baselen] + ys = string[curve.baselen:] + if len(xs) != curve.baselen: + raise MalformedPointError("Unexpected length of encoded x") + if len(ys) != curve.baselen: + raise MalformedPointError("Unexpected length of encoded y") + x = string_to_number(xs) + y = string_to_number(ys) + if validate_point and not ecdsa.point_is_valid(curve.generator, x, y): + raise MalformedPointError("Point does not lie on the curve") + point = ellipticcurve.Point(curve.curve, x, y, order) + return klass.from_public_point(point, curve, hashfunc) + + @classmethod + def from_pem(klass, string): + return klass.from_der(der.unpem(string)) + + @classmethod + def from_der(klass, string): + # [[oid_ecPublicKey,oid_curve], point_str_bitstring] + s1,empty = der.remove_sequence(string) + if empty != b(""): + raise der.UnexpectedDER("trailing junk after DER pubkey: %s" % + binascii.hexlify(empty)) + s2,point_str_bitstring = der.remove_sequence(s1) + # s2 = oid_ecPublicKey,oid_curve + oid_pk, rest = der.remove_object(s2) + oid_curve, empty = der.remove_object(rest) + if empty != b(""): + raise der.UnexpectedDER("trailing junk after DER pubkey objects: %s" % + binascii.hexlify(empty)) + if oid_pk != oid_ecPublicKey: + raise der.UnexpectedDER( + "Unexpected OID in encoding, received {0}, expected {1}" + .format(oid_pk, oid_ecPublicKey)) + curve = find_curve(oid_curve) + point_str, empty = der.remove_bitstring(point_str_bitstring) + if empty != b(""): + raise der.UnexpectedDER("trailing junk after pubkey pointstring: %s" % + binascii.hexlify(empty)) + if not point_str.startswith(b("\x00\x04")): + raise der.UnexpectedDER( + "Unsupported or invalid encoding of pubcli key") + return klass.from_string(point_str[2:], curve) + + def to_string(self): + # VerifyingKey.from_string(vk.to_string()) == vk as long as the + # curves are the same: the curve itself is not included in the + # serialized form + order = self.pubkey.order + x_str = number_to_string(self.pubkey.point.x(), order) + y_str = number_to_string(self.pubkey.point.y(), order) + return x_str + y_str + + def to_pem(self): + return der.topem(self.to_der(), "PUBLIC KEY") + + def to_der(self): + order = self.pubkey.order + x_str = number_to_string(self.pubkey.point.x(), order) + y_str = number_to_string(self.pubkey.point.y(), order) + point_str = b("\x00\x04") + x_str + y_str + return der.encode_sequence(der.encode_sequence(encoded_oid_ecPublicKey, + self.curve.encoded_oid), + der.encode_bitstring(point_str)) + + def verify(self, signature, data, hashfunc=None, sigdecode=sigdecode_string): + hashfunc = hashfunc or self.default_hashfunc + digest = hashfunc(data).digest() + return self.verify_digest(signature, digest, sigdecode) + + def verify_digest(self, signature, digest, sigdecode=sigdecode_string): + if len(digest) > self.curve.baselen: + raise BadDigestError("this curve (%s) is too short " + "for your digest (%d)" % (self.curve.name, + 8*len(digest))) + number = string_to_number(digest) + try: + r, s = sigdecode(signature, self.pubkey.order) + except (der.UnexpectedDER, MalformedSignature) as e: + raise BadSignatureError("Malformed formatting of signature", e) + sig = ecdsa.Signature(r, s) + if self.pubkey.verifies(number, sig): + return True + raise BadSignatureError("Signature verification failed") + +class SigningKey: + def __init__(self, _error__please_use_generate=None): + if not _error__please_use_generate: + raise TypeError("Please use SigningKey.generate() to construct me") + + @classmethod + def generate(klass, curve=NIST192p, entropy=None, hashfunc=sha1): + secexp = randrange(curve.order, entropy) + return klass.from_secret_exponent(secexp, curve, hashfunc) + + # to create a signing key from a short (arbitrary-length) seed, convert + # that seed into an integer with something like + # secexp=util.randrange_from_seed__X(seed, curve.order), and then pass + # that integer into SigningKey.from_secret_exponent(secexp, curve) + + @classmethod + def from_secret_exponent(klass, secexp, curve=NIST192p, hashfunc=sha1): + self = klass(_error__please_use_generate=True) + self.curve = curve + self.default_hashfunc = hashfunc + self.baselen = curve.baselen + n = curve.order + if not 1 <= secexp < n: + raise MalformedPointError( + "Invalid value for secexp, expected integer between 1 and {0}" + .format(n)) + pubkey_point = curve.generator*secexp + pubkey = ecdsa.Public_key(curve.generator, pubkey_point) + pubkey.order = n + self.verifying_key = VerifyingKey.from_public_point(pubkey_point, curve, + hashfunc) + self.privkey = ecdsa.Private_key(pubkey, secexp) + self.privkey.order = n + return self + + @classmethod + def from_string(klass, string, curve=NIST192p, hashfunc=sha1): + if len(string) != curve.baselen: + raise MalformedPointError( + "Invalid length of private key, received {0}, expected {1}" + .format(len(string), curve.baselen)) + secexp = string_to_number(string) + return klass.from_secret_exponent(secexp, curve, hashfunc) + + @classmethod + def from_pem(klass, string, hashfunc=sha1): + # the privkey pem file has two sections: "EC PARAMETERS" and "EC + # PRIVATE KEY". The first is redundant. + if PY3 and isinstance(string, str): + string = string.encode() + privkey_pem = string[string.index(b("-----BEGIN EC PRIVATE KEY-----")):] + return klass.from_der(der.unpem(privkey_pem), hashfunc) + @classmethod + def from_der(klass, string, hashfunc=sha1): + # SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1), + # cont[1],bitstring]) + s, empty = der.remove_sequence(string) + if empty != b(""): + raise der.UnexpectedDER("trailing junk after DER privkey: %s" % + binascii.hexlify(empty)) + one, s = der.remove_integer(s) + if one != 1: + raise der.UnexpectedDER("expected '1' at start of DER privkey," + " got %d" % one) + privkey_str, s = der.remove_octet_string(s) + tag, curve_oid_str, s = der.remove_constructed(s) + if tag != 0: + raise der.UnexpectedDER("expected tag 0 in DER privkey," + " got %d" % tag) + curve_oid, empty = der.remove_object(curve_oid_str) + if empty != b(""): + raise der.UnexpectedDER("trailing junk after DER privkey " + "curve_oid: %s" % binascii.hexlify(empty)) + curve = find_curve(curve_oid) + + # we don't actually care about the following fields + # + #tag, pubkey_bitstring, s = der.remove_constructed(s) + #if tag != 1: + # raise der.UnexpectedDER("expected tag 1 in DER privkey, got %d" + # % tag) + #pubkey_str = der.remove_bitstring(pubkey_bitstring) + #if empty != "": + # raise der.UnexpectedDER("trailing junk after DER privkey " + # "pubkeystr: %s" % binascii.hexlify(empty)) + + # our from_string method likes fixed-length privkey strings + if len(privkey_str) < curve.baselen: + privkey_str = b("\x00")*(curve.baselen-len(privkey_str)) + privkey_str + return klass.from_string(privkey_str, curve, hashfunc) + + def to_string(self): + secexp = self.privkey.secret_multiplier + s = number_to_string(secexp, self.privkey.order) + return s + + def to_pem(self): + # TODO: "BEGIN ECPARAMETERS" + return der.topem(self.to_der(), "EC PRIVATE KEY") + + def to_der(self): + # SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1), + # cont[1],bitstring]) + encoded_vk = b("\x00\x04") + self.get_verifying_key().to_string() + return der.encode_sequence(der.encode_integer(1), + der.encode_octet_string(self.to_string()), + der.encode_constructed(0, self.curve.encoded_oid), + der.encode_constructed(1, der.encode_bitstring(encoded_vk)), + ) + + def get_verifying_key(self): + return self.verifying_key + + def sign_deterministic(self, data, hashfunc=None, sigencode=sigencode_string): + hashfunc = hashfunc or self.default_hashfunc + digest = hashfunc(data).digest() + + return self.sign_digest_deterministic(digest, hashfunc=hashfunc, sigencode=sigencode) + + def sign_digest_deterministic(self, digest, hashfunc=None, sigencode=sigencode_string): + """ + Calculates 'k' from data itself, removing the need for strong + random generator and producing deterministic (reproducible) signatures. + See RFC 6979 for more details. + """ + secexp = self.privkey.secret_multiplier + k = rfc6979.generate_k( + self.curve.generator.order(), secexp, hashfunc, digest) + + return self.sign_digest(digest, sigencode=sigencode, k=k) + + def sign(self, data, entropy=None, hashfunc=None, sigencode=sigencode_string, k=None): + """ + hashfunc= should behave like hashlib.sha1 . The output length of the + hash (in bytes) must not be longer than the length of the curve order + (rounded up to the nearest byte), so using SHA256 with nist256p is + ok, but SHA256 with nist192p is not. (In the 2**-96ish unlikely event + of a hash output larger than the curve order, the hash will + effectively be wrapped mod n). + + Use hashfunc=hashlib.sha1 to match openssl's -ecdsa-with-SHA1 mode, + or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256. + """ + + hashfunc = hashfunc or self.default_hashfunc + h = hashfunc(data).digest() + return self.sign_digest(h, entropy, sigencode, k) + + def sign_digest(self, digest, entropy=None, sigencode=sigencode_string, k=None): + if len(digest) > self.curve.baselen: + raise BadDigestError("this curve (%s) is too short " + "for your digest (%d)" % (self.curve.name, + 8*len(digest))) + number = string_to_number(digest) + r, s = self.sign_number(number, entropy, k) + return sigencode(r, s, self.privkey.order) + + def sign_number(self, number, entropy=None, k=None): + # returns a pair of numbers + order = self.privkey.order + # privkey.sign() may raise RuntimeError in the amazingly unlikely + # (2**-192) event that r=0 or s=0, because that would leak the key. + # We could re-try with a different 'k', but we couldn't test that + # code, so I choose to allow the signature to fail instead. + + # If k is set, it is used directly. In other cases + # it is generated using entropy function + if k is not None: + _k = k + else: + _k = randrange(order, entropy) + + assert 1 <= _k < order + sig = self.privkey.sign(number, _k) + return sig.r, sig.s diff --git a/Lambdas/Websocket Authorizer/ecdsa/numbertheory.py b/Lambdas/Websocket Authorizer/ecdsa/numbertheory.py new file mode 100644 index 0000000..7ace0dc --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/numbertheory.py @@ -0,0 +1,613 @@ +#! /usr/bin/env python +# +# Provide some simple capabilities from number theory. +# +# Version of 2008.11.14. +# +# Written in 2005 and 2006 by Peter Pearson and placed in the public domain. +# Revision history: +# 2008.11.14: Use pow( base, exponent, modulus ) for modular_exp. +# Make gcd and lcm accept arbitrarly many arguments. + +from __future__ import division + +from .six import print_, integer_types +from .six.moves import reduce + +import math + + +class Error( Exception ): + """Base class for exceptions in this module.""" + pass + +class SquareRootError( Error ): + pass + +class NegativeExponentError( Error ): + pass + + +def modular_exp( base, exponent, modulus ): + "Raise base to exponent, reducing by modulus" + if exponent < 0: + raise NegativeExponentError( "Negative exponents (%d) not allowed" \ + % exponent ) + return pow( base, exponent, modulus ) +# result = 1L +# x = exponent +# b = base + 0L +# while x > 0: +# if x % 2 > 0: result = (result * b) % modulus +# x = x // 2 +# b = ( b * b ) % modulus +# return result + + +def polynomial_reduce_mod( poly, polymod, p ): + """Reduce poly by polymod, integer arithmetic modulo p. + + Polynomials are represented as lists of coefficients + of increasing powers of x.""" + + # This module has been tested only by extensive use + # in calculating modular square roots. + + # Just to make this easy, require a monic polynomial: + assert polymod[-1] == 1 + + assert len( polymod ) > 1 + + while len( poly ) >= len( polymod ): + if poly[-1] != 0: + for i in range( 2, len( polymod ) + 1 ): + poly[-i] = ( poly[-i] - poly[-1] * polymod[-i] ) % p + poly = poly[0:-1] + + return poly + + + +def polynomial_multiply_mod( m1, m2, polymod, p ): + """Polynomial multiplication modulo a polynomial over ints mod p. + + Polynomials are represented as lists of coefficients + of increasing powers of x.""" + + # This is just a seat-of-the-pants implementation. + + # This module has been tested only by extensive use + # in calculating modular square roots. + + # Initialize the product to zero: + + prod = ( len( m1 ) + len( m2 ) - 1 ) * [0] + + # Add together all the cross-terms: + + for i in range( len( m1 ) ): + for j in range( len( m2 ) ): + prod[i+j] = ( prod[i+j] + m1[i] * m2[j] ) % p + + return polynomial_reduce_mod( prod, polymod, p ) + + +def polynomial_exp_mod( base, exponent, polymod, p ): + """Polynomial exponentiation modulo a polynomial over ints mod p. + + Polynomials are represented as lists of coefficients + of increasing powers of x.""" + + # Based on the Handbook of Applied Cryptography, algorithm 2.227. + + # This module has been tested only by extensive use + # in calculating modular square roots. + + assert exponent < p + + if exponent == 0: return [ 1 ] + + G = base + k = exponent + if k%2 == 1: s = G + else: s = [ 1 ] + + while k > 1: + k = k // 2 + G = polynomial_multiply_mod( G, G, polymod, p ) + if k%2 == 1: s = polynomial_multiply_mod( G, s, polymod, p ) + + return s + + + +def jacobi( a, n ): + """Jacobi symbol""" + + # Based on the Handbook of Applied Cryptography (HAC), algorithm 2.149. + + # This function has been tested by comparison with a small + # table printed in HAC, and by extensive use in calculating + # modular square roots. + + assert n >= 3 + assert n%2 == 1 + a = a % n + if a == 0: return 0 + if a == 1: return 1 + a1, e = a, 0 + while a1%2 == 0: + a1, e = a1//2, e+1 + if e%2 == 0 or n%8 == 1 or n%8 == 7: s = 1 + else: s = -1 + if a1 == 1: return s + if n%4 == 3 and a1%4 == 3: s = -s + return s * jacobi( n % a1, a1 ) + + + +def square_root_mod_prime( a, p ): + """Modular square root of a, mod p, p prime.""" + + # Based on the Handbook of Applied Cryptography, algorithms 3.34 to 3.39. + + # This module has been tested for all values in [0,p-1] for + # every prime p from 3 to 1229. + + assert 0 <= a < p + assert 1 < p + + if a == 0: return 0 + if p == 2: return a + + jac = jacobi( a, p ) + if jac == -1: raise SquareRootError( "%d has no square root modulo %d" \ + % ( a, p ) ) + + if p % 4 == 3: return modular_exp( a, (p+1)//4, p ) + + if p % 8 == 5: + d = modular_exp( a, (p-1)//4, p ) + if d == 1: return modular_exp( a, (p+3)//8, p ) + if d == p-1: return ( 2 * a * modular_exp( 4*a, (p-5)//8, p ) ) % p + raise RuntimeError("Shouldn't get here.") + + for b in range( 2, p ): + if jacobi( b*b-4*a, p ) == -1: + f = ( a, -b, 1 ) + ff = polynomial_exp_mod( ( 0, 1 ), (p+1)//2, f, p ) + assert ff[1] == 0 + return ff[0] + raise RuntimeError("No b found.") + + + +def inverse_mod( a, m ): + """Inverse of a mod m.""" + + if a < 0 or m <= a: a = a % m + + # From Ferguson and Schneier, roughly: + + c, d = a, m + uc, vc, ud, vd = 1, 0, 0, 1 + while c != 0: + q, c, d = divmod( d, c ) + ( c, ) + uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc + + # At this point, d is the GCD, and ud*a+vd*m = d. + # If d == 1, this means that ud is a inverse. + + assert d == 1 + if ud > 0: return ud + else: return ud + m + + +def gcd2(a, b): + """Greatest common divisor using Euclid's algorithm.""" + while a: + a, b = b%a, a + return b + + +def gcd( *a ): + """Greatest common divisor. + + Usage: gcd( [ 2, 4, 6 ] ) + or: gcd( 2, 4, 6 ) + """ + + if len( a ) > 1: return reduce( gcd2, a ) + if hasattr( a[0], "__iter__" ): return reduce( gcd2, a[0] ) + return a[0] + + +def lcm2(a,b): + """Least common multiple of two integers.""" + + return (a*b)//gcd(a,b) + + +def lcm( *a ): + """Least common multiple. + + Usage: lcm( [ 3, 4, 5 ] ) + or: lcm( 3, 4, 5 ) + """ + + if len( a ) > 1: return reduce( lcm2, a ) + if hasattr( a[0], "__iter__" ): return reduce( lcm2, a[0] ) + return a[0] + + + +def factorization( n ): + """Decompose n into a list of (prime,exponent) pairs.""" + + assert isinstance( n, integer_types ) + + if n < 2: return [] + + result = [] + d = 2 + + # Test the small primes: + + for d in smallprimes: + if d > n: break + q, r = divmod( n, d ) + if r == 0: + count = 1 + while d <= n: + n = q + q, r = divmod( n, d ) + if r != 0: break + count = count + 1 + result.append( ( d, count ) ) + + # If n is still greater than the last of our small primes, + # it may require further work: + + if n > smallprimes[-1]: + if is_prime( n ): # If what's left is prime, it's easy: + result.append( ( n, 1 ) ) + else: # Ugh. Search stupidly for a divisor: + d = smallprimes[-1] + while 1: + d = d + 2 # Try the next divisor. + q, r = divmod( n, d ) + if q < d: break # n < d*d means we're done, n = 1 or prime. + if r == 0: # d divides n. How many times? + count = 1 + n = q + while d <= n: # As long as d might still divide n, + q, r = divmod( n, d ) # see if it does. + if r != 0: break + n = q # It does. Reduce n, increase count. + count = count + 1 + result.append( ( d, count ) ) + if n > 1: result.append( ( n, 1 ) ) + + return result + + + +def phi( n ): + """Return the Euler totient function of n.""" + + assert isinstance( n, integer_types ) + + if n < 3: return 1 + + result = 1 + ff = factorization( n ) + for f in ff: + e = f[1] + if e > 1: + result = result * f[0] ** (e-1) * ( f[0] - 1 ) + else: + result = result * ( f[0] - 1 ) + return result + + +def carmichael( n ): + """Return Carmichael function of n. + + Carmichael(n) is the smallest integer x such that + m**x = 1 mod n for all m relatively prime to n. + """ + + return carmichael_of_factorized( factorization( n ) ) + + +def carmichael_of_factorized( f_list ): + """Return the Carmichael function of a number that is + represented as a list of (prime,exponent) pairs. + """ + + if len( f_list ) < 1: return 1 + + result = carmichael_of_ppower( f_list[0] ) + for i in range( 1, len( f_list ) ): + result = lcm( result, carmichael_of_ppower( f_list[i] ) ) + + return result + +def carmichael_of_ppower( pp ): + """Carmichael function of the given power of the given prime. + """ + + p, a = pp + if p == 2 and a > 2: return 2**(a-2) + else: return (p-1) * p**(a-1) + + + +def order_mod( x, m ): + """Return the order of x in the multiplicative group mod m. + """ + + # Warning: this implementation is not very clever, and will + # take a long time if m is very large. + + if m <= 1: return 0 + + assert gcd( x, m ) == 1 + + z = x + result = 1 + while z != 1: + z = ( z * x ) % m + result = result + 1 + return result + + +def largest_factor_relatively_prime( a, b ): + """Return the largest factor of a relatively prime to b. + """ + + while 1: + d = gcd( a, b ) + if d <= 1: break + b = d + while 1: + q, r = divmod( a, d ) + if r > 0: + break + a = q + return a + + +def kinda_order_mod( x, m ): + """Return the order of x in the multiplicative group mod m', + where m' is the largest factor of m relatively prime to x. + """ + + return order_mod( x, largest_factor_relatively_prime( m, x ) ) + + +def is_prime( n ): + """Return True if x is prime, False otherwise. + + We use the Miller-Rabin test, as given in Menezes et al. p. 138. + This test is not exact: there are composite values n for which + it returns True. + + In testing the odd numbers from 10000001 to 19999999, + about 66 composites got past the first test, + 5 got past the second test, and none got past the third. + Since factors of 2, 3, 5, 7, and 11 were detected during + preliminary screening, the number of numbers tested by + Miller-Rabin was (19999999 - 10000001)*(2/3)*(4/5)*(6/7) + = 4.57 million. + """ + + # (This is used to study the risk of false positives:) + global miller_rabin_test_count + + miller_rabin_test_count = 0 + + if n <= smallprimes[-1]: + if n in smallprimes: return True + else: return False + + if gcd( n, 2*3*5*7*11 ) != 1: return False + + # Choose a number of iterations sufficient to reduce the + # probability of accepting a composite below 2**-80 + # (from Menezes et al. Table 4.4): + + t = 40 + n_bits = 1 + int( math.log( n, 2 ) ) + for k, tt in ( ( 100, 27 ), + ( 150, 18 ), + ( 200, 15 ), + ( 250, 12 ), + ( 300, 9 ), + ( 350, 8 ), + ( 400, 7 ), + ( 450, 6 ), + ( 550, 5 ), + ( 650, 4 ), + ( 850, 3 ), + ( 1300, 2 ), + ): + if n_bits < k: break + t = tt + + # Run the test t times: + + s = 0 + r = n - 1 + while ( r % 2 ) == 0: + s = s + 1 + r = r // 2 + for i in range( t ): + a = smallprimes[ i ] + y = modular_exp( a, r, n ) + if y != 1 and y != n-1: + j = 1 + while j <= s - 1 and y != n - 1: + y = modular_exp( y, 2, n ) + if y == 1: + miller_rabin_test_count = i + 1 + return False + j = j + 1 + if y != n-1: + miller_rabin_test_count = i + 1 + return False + return True + + +def next_prime( starting_value ): + "Return the smallest prime larger than the starting value." + + if starting_value < 2: return 2 + result = ( starting_value + 1 ) | 1 + while not is_prime( result ): result = result + 2 + return result + + +smallprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, + 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, + 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, + 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, + 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, + 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, + 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, + 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, + 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, + 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, + 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, + 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, + 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, + 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, + 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229] + +miller_rabin_test_count = 0 + +def __main__(): + + # Making sure locally defined exceptions work: + # p = modular_exp( 2, -2, 3 ) + # p = square_root_mod_prime( 2, 3 ) + + + print_("Testing gcd...") + assert gcd( 3*5*7, 3*5*11, 3*5*13 ) == 3*5 + assert gcd( [ 3*5*7, 3*5*11, 3*5*13 ] ) == 3*5 + assert gcd( 3 ) == 3 + + print_("Testing lcm...") + assert lcm( 3, 5*3, 7*3 ) == 3*5*7 + assert lcm( [ 3, 5*3, 7*3 ] ) == 3*5*7 + assert lcm( 3 ) == 3 + + print_("Testing next_prime...") + bigprimes = ( 999671, + 999683, + 999721, + 999727, + 999749, + 999763, + 999769, + 999773, + 999809, + 999853, + 999863, + 999883, + 999907, + 999917, + 999931, + 999953, + 999959, + 999961, + 999979, + 999983 ) + + for i in range( len( bigprimes ) - 1 ): + assert next_prime( bigprimes[i] ) == bigprimes[ i+1 ] + + error_tally = 0 + + # Test the square_root_mod_prime function: + + for p in smallprimes: + print_("Testing square_root_mod_prime for modulus p = %d." % p) + squares = [] + + for root in range( 0, 1+p//2 ): + sq = ( root * root ) % p + squares.append( sq ) + calculated = square_root_mod_prime( sq, p ) + if ( calculated * calculated ) % p != sq: + error_tally = error_tally + 1 + print_("Failed to find %d as sqrt( %d ) mod %d. Said %d." % \ + ( root, sq, p, calculated )) + + for nonsquare in range( 0, p ): + if nonsquare not in squares: + try: + calculated = square_root_mod_prime( nonsquare, p ) + except SquareRootError: + pass + else: + error_tally = error_tally + 1 + print_("Failed to report no root for sqrt( %d ) mod %d." % \ + ( nonsquare, p )) + + # Test the jacobi function: + for m in range( 3, 400, 2 ): + print_("Testing jacobi for modulus m = %d." % m) + if is_prime( m ): + squares = [] + for root in range( 1, m ): + if jacobi( root * root, m ) != 1: + error_tally = error_tally + 1 + print_("jacobi( %d * %d, %d ) != 1" % ( root, root, m )) + squares.append( root * root % m ) + for i in range( 1, m ): + if not i in squares: + if jacobi( i, m ) != -1: + error_tally = error_tally + 1 + print_("jacobi( %d, %d ) != -1" % ( i, m )) + else: # m is not prime. + f = factorization( m ) + for a in range( 1, m ): + c = 1 + for i in f: + c = c * jacobi( a, i[0] ) ** i[1] + if c != jacobi( a, m ): + error_tally = error_tally + 1 + print_("%d != jacobi( %d, %d )" % ( c, a, m )) + + +# Test the inverse_mod function: + print_("Testing inverse_mod . . .") + import random + n_tests = 0 + for i in range( 100 ): + m = random.randint( 20, 10000 ) + for j in range( 100 ): + a = random.randint( 1, m-1 ) + if gcd( a, m ) == 1: + n_tests = n_tests + 1 + inv = inverse_mod( a, m ) + if inv <= 0 or inv >= m or ( a * inv ) % m != 1: + error_tally = error_tally + 1 + print_("%d = inverse_mod( %d, %d ) is wrong." % ( inv, a, m )) + assert n_tests > 1000 + print_(n_tests, " tests of inverse_mod completed.") + + class FailedTest(Exception): pass + print_(error_tally, "errors detected.") + if error_tally != 0: + raise FailedTest("%d errors detected" % error_tally) + +if __name__ == '__main__': + __main__() diff --git a/Lambdas/Websocket Authorizer/ecdsa/rfc6979.py b/Lambdas/Websocket Authorizer/ecdsa/rfc6979.py new file mode 100644 index 0000000..6190ebd --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/rfc6979.py @@ -0,0 +1,103 @@ +''' +RFC 6979: + Deterministic Usage of the Digital Signature Algorithm (DSA) and + Elliptic Curve Digital Signature Algorithm (ECDSA) + + http://tools.ietf.org/html/rfc6979 + +Many thanks to Coda Hale for his implementation in Go language: + https://github.com/codahale/rfc6979 +''' + +import hmac +from binascii import hexlify +from .util import number_to_string, number_to_string_crop +from .six import b + +try: + bin(0) +except NameError: + binmap = {"0": "0000", "1": "0001", "2": "0010", "3": "0011", + "4": "0100", "5": "0101", "6": "0110", "7": "0111", + "8": "1000", "9": "1001", "a": "1010", "b": "1011", + "c": "1100", "d": "1101", "e": "1110", "f": "1111"} + def bin(value): # for python2.5 + v = "".join(binmap[x] for x in "%x"%abs(value)).lstrip("0") + if value < 0: + return "-0b" + v + return "0b" + v + +def bit_length(num): + # http://docs.python.org/dev/library/stdtypes.html#int.bit_length + s = bin(num) # binary representation: bin(-37) --> '-0b100101' + s = s.lstrip('-0b') # remove leading zeros and minus sign + return len(s) # len('100101') --> 6 + +def bits2int(data, qlen): + x = int(hexlify(data), 16) + l = len(data) * 8 + + if l > qlen: + return x >> (l-qlen) + return x + +def bits2octets(data, order): + z1 = bits2int(data, bit_length(order)) + z2 = z1 - order + + if z2 < 0: + z2 = z1 + + return number_to_string_crop(z2, order) + +# https://tools.ietf.org/html/rfc6979#section-3.2 +def generate_k(order, secexp, hash_func, data): + ''' + order - order of the DSA generator used in the signature + secexp - secure exponent (private key) in numeric form + hash_func - reference to the same hash function used for generating hash + data - hash in binary form of the signing data + ''' + + qlen = bit_length(order) + holen = hash_func().digest_size + rolen = (qlen + 7) / 8 + bx = number_to_string(secexp, order) + bits2octets(data, order) + + # Step B + v = b('\x01') * holen + + # Step C + k = b('\x00') * holen + + # Step D + + k = hmac.new(k, v+b('\x00')+bx, hash_func).digest() + + # Step E + v = hmac.new(k, v, hash_func).digest() + + # Step F + k = hmac.new(k, v+b('\x01')+bx, hash_func).digest() + + # Step G + v = hmac.new(k, v, hash_func).digest() + + # Step H + while True: + # Step H1 + t = b('') + + # Step H2 + while len(t) < rolen: + v = hmac.new(k, v, hash_func).digest() + t += v + + # Step H3 + secret = bits2int(t, qlen) + + if secret >= 1 and secret < order: + return secret + + k = hmac.new(k, v+b('\x00'), hash_func).digest() + v = hmac.new(k, v, hash_func).digest() diff --git a/Lambdas/Websocket Authorizer/ecdsa/six.py b/Lambdas/Websocket Authorizer/ecdsa/six.py new file mode 100644 index 0000000..3003f8f --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/six.py @@ -0,0 +1,394 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2012 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.2.0" + + +# True if we are running on Python 3. +PY3 = sys.version_info[0] == 3 + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) + # This is a bit ugly, but it avoids running this again. + delattr(tp, self.name) + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + + +class _MovedItems(types.ModuleType): + """Lazy loading of moved objects""" + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("reload_module", "__builtin__", "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("winreg", "_winreg"), +] +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) +del attr + +moves = sys.modules[__name__ + ".moves"] = _MovedItems("moves") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_code = "__code__" + _func_defaults = "__defaults__" + + _iterkeys = "keys" + _itervalues = "values" + _iteritems = "items" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_code = "func_code" + _func_defaults = "func_defaults" + + _iterkeys = "iterkeys" + _itervalues = "itervalues" + _iteritems = "iteritems" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) + + +def iterkeys(d): + """Return an iterator over the keys of a dictionary.""" + return iter(getattr(d, _iterkeys)()) + +def itervalues(d): + """Return an iterator over the values of a dictionary.""" + return iter(getattr(d, _itervalues)()) + +def iteritems(d): + """Return an iterator over the (key, value) pairs of a dictionary.""" + return iter(getattr(d, _iteritems)()) + + +if PY3: + def b(s): + return s.encode("latin-1") + def u(s): + return s + if sys.version_info[1] <= 1: + def int2byte(i): + return bytes((i,)) + else: + # This is about 2x faster than the implementation above on 3.2+ + int2byte = operator.methodcaller("to_bytes", 1, "big") + import io + StringIO = io.StringIO + BytesIO = io.BytesIO +else: + def b(s): + return s + def u(s): + if isinstance(s, unicode): + return s + return unicode(s, "unicode_escape") + int2byte = chr + import StringIO + StringIO = BytesIO = StringIO.StringIO +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +if PY3: + import builtins + exec_ = getattr(builtins, "exec") + + + def reraise(tp, value, tb=None): + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + + + print_ = getattr(builtins, "print") + del builtins + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + + + def print_(*args, **kwargs): + """The new-style print function.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + def write(data): + if not isinstance(data, basestring): + data = str(data) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) + +_add_doc(reraise, """Reraise an exception.""") + + +def with_metaclass(meta, base=object): + """Create a base class with a metaclass.""" + return meta("NewBase", (base,), {}) diff --git a/Lambdas/Websocket Authorizer/ecdsa/test_der.py b/Lambdas/Websocket Authorizer/ecdsa/test_der.py new file mode 100644 index 0000000..c0c555e --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/test_der.py @@ -0,0 +1,88 @@ + +# compatibility with Python 2.6, for that we need unittest2 package, +# which is not available on 3.3 or 3.4 +try: + import unittest2 as unittest +except ImportError: + import unittest +from .der import remove_integer, UnexpectedDER, read_length +from .six import b + +class TestRemoveInteger(unittest.TestCase): + # DER requires the integers to be 0-padded only if they would be + # interpreted as negative, check if those errors are detected + def test_non_minimal_encoding(self): + with self.assertRaises(UnexpectedDER): + remove_integer(b('\x02\x02\x00\x01')) + + def test_negative_with_high_bit_set(self): + with self.assertRaises(UnexpectedDER): + remove_integer(b('\x02\x01\x80')) + + def test_two_zero_bytes_with_high_bit_set(self): + with self.assertRaises(UnexpectedDER): + remove_integer(b('\x02\x03\x00\x00\xff')) + + def test_zero_length_integer(self): + with self.assertRaises(UnexpectedDER): + remove_integer(b('\x02\x00')) + + def test_empty_string(self): + with self.assertRaises(UnexpectedDER): + remove_integer(b('')) + + def test_encoding_of_zero(self): + val, rem = remove_integer(b('\x02\x01\x00')) + + self.assertEqual(val, 0) + self.assertFalse(rem) + + def test_encoding_of_127(self): + val, rem = remove_integer(b('\x02\x01\x7f')) + + self.assertEqual(val, 127) + self.assertFalse(rem) + + def test_encoding_of_128(self): + val, rem = remove_integer(b('\x02\x02\x00\x80')) + + self.assertEqual(val, 128) + self.assertFalse(rem) + + +class TestReadLength(unittest.TestCase): + # DER requires the lengths between 0 and 127 to be encoded using the short + # form and lengths above that encoded with minimal number of bytes + # necessary + def test_zero_length(self): + self.assertEqual((0, 1), read_length(b('\x00'))) + + def test_two_byte_zero_length(self): + with self.assertRaises(UnexpectedDER): + read_length(b('\x81\x00')) + + def test_two_byte_small_length(self): + with self.assertRaises(UnexpectedDER): + read_length(b('\x81\x7f')) + + def test_long_form_with_zero_length(self): + with self.assertRaises(UnexpectedDER): + read_length(b('\x80')) + + def test_smallest_two_byte_length(self): + self.assertEqual((128, 2), read_length(b('\x81\x80'))) + + def test_zero_padded_length(self): + with self.assertRaises(UnexpectedDER): + read_length(b('\x82\x00\x80')) + + def test_two_three_byte_length(self): + self.assertEqual((256, 3), read_length(b'\x82\x01\x00')) + + def test_empty_string(self): + with self.assertRaises(UnexpectedDER): + read_length(b('')) + + def test_length_overflow(self): + with self.assertRaises(UnexpectedDER): + read_length(b('\x83\x01\x00')) diff --git a/Lambdas/Websocket Authorizer/ecdsa/test_malformed_sigs.py b/Lambdas/Websocket Authorizer/ecdsa/test_malformed_sigs.py new file mode 100644 index 0000000..30eee12 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/test_malformed_sigs.py @@ -0,0 +1,87 @@ +from __future__ import with_statement, division + +import pytest +import hashlib + +from .six import b, binary_type +from .keys import SigningKey, VerifyingKey +from .keys import BadSignatureError +from .util import sigencode_der, sigencode_string +from .util import sigdecode_der, sigdecode_string +from .curves import curves, NIST256p, NIST521p + +der_sigs = [] +example_data = b("some data to sign") + +# Just NIST256p with SHA256 is 560 test cases, all curves with all hashes is +# few thousand slow test cases; execute the most interesting only + +#for curve in curves: +for curve in [NIST521p]: + #for hash_alg in ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]: + for hash_alg in ["sha256"]: + key = SigningKey.generate(curve) + signature = key.sign(example_data, hashfunc=getattr(hashlib, hash_alg), + sigencode=sigencode_der) + for pos in range(len(signature)): + for xor in (1<= ["1","0","0"]: + return "-SHA1" + else: + return "-ecdsa-with-SHA1" + + # sk: 1:OpenSSL->python 2:python->OpenSSL + # vk: 3:OpenSSL->python 4:python->OpenSSL + # sig: 5:OpenSSL->python 6:python->OpenSSL + + def test_from_openssl_nist192p(self): + return self.do_test_from_openssl(NIST192p) + def test_from_openssl_nist224p(self): + return self.do_test_from_openssl(NIST224p) + def test_from_openssl_nist256p(self): + return self.do_test_from_openssl(NIST256p) + def test_from_openssl_nist384p(self): + return self.do_test_from_openssl(NIST384p) + def test_from_openssl_nist521p(self): + return self.do_test_from_openssl(NIST521p) + def test_from_openssl_secp256k1(self): + return self.do_test_from_openssl(SECP256k1) + + def do_test_from_openssl(self, curve): + curvename = curve.openssl_name + assert curvename + # OpenSSL: create sk, vk, sign. + # Python: read vk(3), checksig(5), read sk(1), sign, check + mdarg = self.get_openssl_messagedigest_arg() + if os.path.isdir("t"): + shutil.rmtree("t") + os.mkdir("t") + run_openssl("ecparam -name %s -genkey -out t/privkey.pem" % curvename) + run_openssl("ec -in t/privkey.pem -pubout -out t/pubkey.pem") + data = b("data") + with open("t/data.txt","wb") as e: e.write(data) + run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig t/data.txt" % mdarg) + run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig t/data.txt" % mdarg) + with open("t/pubkey.pem","rb") as e: pubkey_pem = e.read() + vk = VerifyingKey.from_pem(pubkey_pem) # 3 + with open("t/data.sig","rb") as e: sig_der = e.read() + self.assertTrue(vk.verify(sig_der, data, # 5 + hashfunc=sha1, sigdecode=sigdecode_der)) + + with open("t/privkey.pem") as e: fp = e.read() + sk = SigningKey.from_pem(fp) # 1 + sig = sk.sign(data) + self.assertTrue(vk.verify(sig, data)) + + def test_to_openssl_nist192p(self): + self.do_test_to_openssl(NIST192p) + def test_to_openssl_nist224p(self): + self.do_test_to_openssl(NIST224p) + def test_to_openssl_nist256p(self): + self.do_test_to_openssl(NIST256p) + def test_to_openssl_nist384p(self): + self.do_test_to_openssl(NIST384p) + def test_to_openssl_nist521p(self): + self.do_test_to_openssl(NIST521p) + def test_to_openssl_secp256k1(self): + self.do_test_to_openssl(SECP256k1) + + def do_test_to_openssl(self, curve): + curvename = curve.openssl_name + assert curvename + # Python: create sk, vk, sign. + # OpenSSL: read vk(4), checksig(6), read sk(2), sign, check + mdarg = self.get_openssl_messagedigest_arg() + if os.path.isdir("t"): + shutil.rmtree("t") + os.mkdir("t") + sk = SigningKey.generate(curve=curve) + vk = sk.get_verifying_key() + data = b("data") + with open("t/pubkey.der","wb") as e: e.write(vk.to_der()) # 4 + with open("t/pubkey.pem","wb") as e: e.write(vk.to_pem()) # 4 + sig_der = sk.sign(data, hashfunc=sha1, sigencode=sigencode_der) + + with open("t/data.sig","wb") as e: e.write(sig_der) # 6 + with open("t/data.txt","wb") as e: e.write(data) + with open("t/baddata.txt","wb") as e: e.write(data+b("corrupt")) + + self.assertRaises(SubprocessError, run_openssl, + "dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/baddata.txt" % mdarg) + run_openssl("dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/data.txt" % mdarg) + + with open("t/privkey.pem","wb") as e: e.write(sk.to_pem()) # 2 + run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig2 t/data.txt" % mdarg) + run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig2 t/data.txt" % mdarg) + +class DER(unittest.TestCase): + def test_oids(self): + oid_ecPublicKey = der.encode_oid(1, 2, 840, 10045, 2, 1) + self.assertEqual(hexlify(oid_ecPublicKey), b("06072a8648ce3d0201")) + self.assertEqual(hexlify(NIST224p.encoded_oid), b("06052b81040021")) + self.assertEqual(hexlify(NIST256p.encoded_oid), + b("06082a8648ce3d030107")) + x = oid_ecPublicKey + b("more") + x1, rest = der.remove_object(x) + self.assertEqual(x1, (1, 2, 840, 10045, 2, 1)) + self.assertEqual(rest, b("more")) + + def test_integer(self): + self.assertEqual(der.encode_integer(0), b("\x02\x01\x00")) + self.assertEqual(der.encode_integer(1), b("\x02\x01\x01")) + self.assertEqual(der.encode_integer(127), b("\x02\x01\x7f")) + self.assertEqual(der.encode_integer(128), b("\x02\x02\x00\x80")) + self.assertEqual(der.encode_integer(256), b("\x02\x02\x01\x00")) + #self.assertEqual(der.encode_integer(-1), b("\x02\x01\xff")) + + def s(n): return der.remove_integer(der.encode_integer(n) + b("junk")) + self.assertEqual(s(0), (0, b("junk"))) + self.assertEqual(s(1), (1, b("junk"))) + self.assertEqual(s(127), (127, b("junk"))) + self.assertEqual(s(128), (128, b("junk"))) + self.assertEqual(s(256), (256, b("junk"))) + self.assertEqual(s(1234567890123456789012345678901234567890), + (1234567890123456789012345678901234567890,b("junk"))) + + def test_number(self): + self.assertEqual(der.encode_number(0), b("\x00")) + self.assertEqual(der.encode_number(127), b("\x7f")) + self.assertEqual(der.encode_number(128), b("\x81\x00")) + self.assertEqual(der.encode_number(3*128+7), b("\x83\x07")) + #self.assertEqual(der.read_number("\x81\x9b"+"more"), (155, 2)) + #self.assertEqual(der.encode_number(155), b("\x81\x9b")) + for n in (0, 1, 2, 127, 128, 3*128+7, 840, 10045): #, 155): + x = der.encode_number(n) + b("more") + n1, llen = der.read_number(x) + self.assertEqual(n1, n) + self.assertEqual(x[llen:], b("more")) + + def test_length(self): + self.assertEqual(der.encode_length(0), b("\x00")) + self.assertEqual(der.encode_length(127), b("\x7f")) + self.assertEqual(der.encode_length(128), b("\x81\x80")) + self.assertEqual(der.encode_length(255), b("\x81\xff")) + self.assertEqual(der.encode_length(256), b("\x82\x01\x00")) + self.assertEqual(der.encode_length(3*256+7), b("\x82\x03\x07")) + self.assertEqual(der.read_length(b("\x81\x9b")+b("more")), (155, 2)) + self.assertEqual(der.encode_length(155), b("\x81\x9b")) + for n in (0, 1, 2, 127, 128, 255, 256, 3*256+7, 155): + x = der.encode_length(n) + b("more") + n1, llen = der.read_length(x) + self.assertEqual(n1, n) + self.assertEqual(x[llen:], b("more")) + + def test_sequence(self): + x = der.encode_sequence(b("ABC"), b("DEF")) + b("GHI") + self.assertEqual(x, b("\x30\x06ABCDEFGHI")) + x1, rest = der.remove_sequence(x) + self.assertEqual(x1, b("ABCDEF")) + self.assertEqual(rest, b("GHI")) + + def test_constructed(self): + x = der.encode_constructed(0, NIST224p.encoded_oid) + self.assertEqual(hexlify(x), b("a007") + b("06052b81040021")) + x = der.encode_constructed(1, unhexlify(b("0102030a0b0c"))) + self.assertEqual(hexlify(x), b("a106") + b("0102030a0b0c")) + +class Util(unittest.TestCase): + def test_trytryagain(self): + tta = util.randrange_from_seed__trytryagain + for i in range(1000): + seed = "seed-%d" % i + for order in (2**8-2, 2**8-1, 2**8, 2**8+1, 2**8+2, + 2**16-1, 2**16+1): + n = tta(seed, order) + self.assertTrue(1 <= n < order, (1, n, order)) + # this trytryagain *does* provide long-term stability + self.assertEqual(("%x"%(tta("seed", NIST224p.order))).encode(), + b("6fa59d73bf0446ae8743cf748fc5ac11d5585a90356417e97155c3bc")) + + def test_randrange(self): + # util.randrange does not provide long-term stability: we might + # change the algorithm in the future. + for i in range(1000): + entropy = util.PRNG("seed-%d" % i) + for order in (2**8-2, 2**8-1, 2**8, + 2**16-1, 2**16+1, + ): + # that oddball 2**16+1 takes half our runtime + n = util.randrange(order, entropy=entropy) + self.assertTrue(1 <= n < order, (1, n, order)) + + def OFF_test_prove_uniformity(self): + order = 2**8-2 + counts = dict([(i, 0) for i in range(1, order)]) + assert 0 not in counts + assert order not in counts + for i in range(1000000): + seed = "seed-%d" % i + n = util.randrange_from_seed__trytryagain(seed, order) + counts[n] += 1 + # this technique should use the full range + self.assertTrue(counts[order-1]) + for i in range(1, order): + print_("%3d: %s" % (i, "*"*(counts[i]//100))) + +class RFC6979(unittest.TestCase): + # https://tools.ietf.org/html/rfc6979#appendix-A.1 + def _do(self, generator, secexp, hsh, hash_func, expected): + actual = rfc6979.generate_k(generator.order(), secexp, hash_func, hsh) + self.assertEqual(expected, actual) + + def test_SECP256k1(self): + '''RFC doesn't contain test vectors for SECP256k1 used in bitcoin. + This vector has been computed by Golang reference implementation instead.''' + self._do( + generator = SECP256k1.generator, + secexp = int("9d0219792467d7d37b4d43298a7d0c05", 16), + hsh = sha256(b("sample")).digest(), + hash_func = sha256, + expected = int("8fa1f95d514760e498f28957b824ee6ec39ed64826ff4fecc2b5739ec45b91cd", 16)) + + def test_SECP256k1_2(self): + self._do( + generator=SECP256k1.generator, + secexp=int("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", 16), + hsh=sha256(b("sample")).digest(), + hash_func=sha256, + expected=int("2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", 16)) + + def test_SECP256k1_3(self): + self._do( + generator=SECP256k1.generator, + secexp=0x1, + hsh=sha256(b("Satoshi Nakamoto")).digest(), + hash_func=sha256, + expected=0x8F8A276C19F4149656B280621E358CCE24F5F52542772691EE69063B74F15D15) + + def test_SECP256k1_4(self): + self._do( + generator=SECP256k1.generator, + secexp=0x1, + hsh=sha256(b("All those moments will be lost in time, like tears in rain. Time to die...")).digest(), + hash_func=sha256, + expected=0x38AA22D72376B4DBC472E06C3BA403EE0A394DA63FC58D88686C611ABA98D6B3) + + def test_SECP256k1_5(self): + self._do( + generator=SECP256k1.generator, + secexp=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140, + hsh=sha256(b("Satoshi Nakamoto")).digest(), + hash_func=sha256, + expected=0x33A19B60E25FB6F4435AF53A3D42D493644827367E6453928554F43E49AA6F90) + + def test_SECP256k1_6(self): + self._do( + generator=SECP256k1.generator, + secexp=0xf8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181, + hsh=sha256(b("Alan Turing")).digest(), + hash_func=sha256, + expected=0x525A82B70E67874398067543FD84C83D30C175FDC45FDEEE082FE13B1D7CFDF1) + + def test_1(self): + # Basic example of the RFC, it also tests 'try-try-again' from Step H of rfc6979 + self._do( + generator = Point(None, 0, 0, int("4000000000000000000020108A2E0CC0D99F8A5EF", 16)), + secexp = int("09A4D6792295A7F730FC3F2B49CBC0F62E862272F", 16), + hsh = unhexlify(b("AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF")), + hash_func = sha256, + expected = int("23AF4074C90A02B3FE61D286D5C87F425E6BDD81B", 16)) + + def test_2(self): + self._do( + generator=NIST192p.generator, + secexp = int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), + hsh = sha1(b("sample")).digest(), + hash_func = sha1, + expected = int("37D7CA00D2C7B0E5E412AC03BD44BA837FDD5B28CD3B0021", 16)) + + def test_3(self): + self._do( + generator=NIST192p.generator, + secexp = int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), + hsh = sha256(b("sample")).digest(), + hash_func = sha256, + expected = int("32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496", 16)) + + def test_4(self): + self._do( + generator=NIST192p.generator, + secexp = int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), + hsh = sha512(b("sample")).digest(), + hash_func = sha512, + expected = int("A2AC7AB055E4F20692D49209544C203A7D1F2C0BFBC75DB1", 16)) + + def test_5(self): + self._do( + generator=NIST192p.generator, + secexp = int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), + hsh = sha1(b("test")).digest(), + hash_func = sha1, + expected = int("D9CF9C3D3297D3260773A1DA7418DB5537AB8DD93DE7FA25", 16)) + + def test_6(self): + self._do( + generator=NIST192p.generator, + secexp = int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), + hsh = sha256(b("test")).digest(), + hash_func = sha256, + expected = int("5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C", 16)) + + def test_7(self): + self._do( + generator=NIST192p.generator, + secexp = int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), + hsh = sha512(b("test")).digest(), + hash_func = sha512, + expected = int("0758753A5254759C7CFBAD2E2D9B0792EEE44136C9480527", 16)) + + def test_8(self): + self._do( + generator=NIST521p.generator, + secexp = int("0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", 16), + hsh = sha1(b("sample")).digest(), + hash_func = sha1, + expected = int("089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9", 16)) + + def test_9(self): + self._do( + generator=NIST521p.generator, + secexp = int("0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", 16), + hsh = sha256(b("sample")).digest(), + hash_func = sha256, + expected = int("0EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0", 16)) + + def test_10(self): + self._do( + generator=NIST521p.generator, + secexp = int("0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", 16), + hsh = sha512(b("test")).digest(), + hash_func = sha512, + expected = int("16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D", 16)) + +def __main__(): + unittest.main() +if __name__ == "__main__": + __main__() diff --git a/Lambdas/Websocket Authorizer/ecdsa/util.py b/Lambdas/Websocket Authorizer/ecdsa/util.py new file mode 100644 index 0000000..0373a98 --- /dev/null +++ b/Lambdas/Websocket Authorizer/ecdsa/util.py @@ -0,0 +1,267 @@ +from __future__ import division + +import os +import math +import binascii +from hashlib import sha256 +from . import der +from .curves import orderlen +from .six import PY3, int2byte, b, next + +# RFC5480: +# The "unrestricted" algorithm identifier is: +# id-ecPublicKey OBJECT IDENTIFIER ::= { +# iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } + +oid_ecPublicKey = (1, 2, 840, 10045, 2, 1) +encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey) + +def randrange(order, entropy=None): + """Return a random integer k such that 1 <= k < order, uniformly + distributed across that range. For simplicity, this only behaves well if + 'order' is fairly close (but below) a power of 256. The try-try-again + algorithm we use takes longer and longer time (on average) to complete as + 'order' falls, rising to a maximum of avg=512 loops for the worst-case + (256**k)+1 . All of the standard curves behave well. There is a cutoff at + 10k loops (which raises RuntimeError) to prevent an infinite loop when + something is really broken like the entropy function not working. + + Note that this function is not declared to be forwards-compatible: we may + change the behavior in future releases. The entropy= argument (which + should get a callable that behaves like os.urandom) can be used to + achieve stability within a given release (for repeatable unit tests), but + should not be used as a long-term-compatible key generation algorithm. + """ + # we could handle arbitrary orders (even 256**k+1) better if we created + # candidates bit-wise instead of byte-wise, which would reduce the + # worst-case behavior to avg=2 loops, but that would be more complex. The + # change would be to round the order up to a power of 256, subtract one + # (to get 0xffff..), use that to get a byte-long mask for the top byte, + # generate the len-1 entropy bytes, generate one extra byte and mask off + # the top bits, then combine it with the rest. Requires jumping back and + # forth between strings and integers a lot. + + if entropy is None: + entropy = os.urandom + assert order > 1 + bytes = orderlen(order) + dont_try_forever = 10000 # gives about 2**-60 failures for worst case + while dont_try_forever > 0: + dont_try_forever -= 1 + candidate = string_to_number(entropy(bytes)) + 1 + if 1 <= candidate < order: + return candidate + continue + raise RuntimeError("randrange() tried hard but gave up, either something" + " is very wrong or you got realllly unlucky. Order was" + " %x" % order) + +class PRNG: + # this returns a callable which, when invoked with an integer N, will + # return N pseudorandom bytes. Note: this is a short-term PRNG, meant + # primarily for the needs of randrange_from_seed__trytryagain(), which + # only needs to run it a few times per seed. It does not provide + # protection against state compromise (forward security). + def __init__(self, seed): + self.generator = self.block_generator(seed) + + def __call__(self, numbytes): + a = [next(self.generator) for i in range(numbytes)] + + if PY3: + return bytes(a) + else: + return "".join(a) + + + def block_generator(self, seed): + counter = 0 + while True: + for byte in sha256(("prng-%d-%s" % (counter, seed)).encode()).digest(): + yield byte + counter += 1 + +def randrange_from_seed__overshoot_modulo(seed, order): + # hash the data, then turn the digest into a number in [1,order). + # + # We use David-Sarah Hopwood's suggestion: turn it into a number that's + # sufficiently larger than the group order, then modulo it down to fit. + # This should give adequate (but not perfect) uniformity, and simple + # code. There are other choices: try-try-again is the main one. + base = PRNG(seed)(2*orderlen(order)) + number = (int(binascii.hexlify(base), 16) % (order-1)) + 1 + assert 1 <= number < order, (1, number, order) + return number + +def lsb_of_ones(numbits): + return (1 << numbits) - 1 +def bits_and_bytes(order): + bits = int(math.log(order-1, 2)+1) + bytes = bits // 8 + extrabits = bits % 8 + return bits, bytes, extrabits + +# the following randrange_from_seed__METHOD() functions take an +# arbitrarily-sized secret seed and turn it into a number that obeys the same +# range limits as randrange() above. They are meant for deriving consistent +# signing keys from a secret rather than generating them randomly, for +# example a protocol in which three signing keys are derived from a master +# secret. You should use a uniformly-distributed unguessable seed with about +# curve.baselen bytes of entropy. To use one, do this: +# seed = os.urandom(curve.baselen) # or other starting point +# secexp = ecdsa.util.randrange_from_seed__trytryagain(sed, curve.order) +# sk = SigningKey.from_secret_exponent(secexp, curve) + +def randrange_from_seed__truncate_bytes(seed, order, hashmod=sha256): + # hash the seed, then turn the digest into a number in [1,order), but + # don't worry about trying to uniformly fill the range. This will lose, + # on average, four bits of entropy. + bits, bytes, extrabits = bits_and_bytes(order) + if extrabits: + bytes += 1 + base = hashmod(seed).digest()[:bytes] + base = "\x00"*(bytes-len(base)) + base + number = 1+int(binascii.hexlify(base), 16) + assert 1 <= number < order + return number + +def randrange_from_seed__truncate_bits(seed, order, hashmod=sha256): + # like string_to_randrange_truncate_bytes, but only lose an average of + # half a bit + bits = int(math.log(order-1, 2)+1) + maxbytes = (bits+7) // 8 + base = hashmod(seed).digest()[:maxbytes] + base = "\x00"*(maxbytes-len(base)) + base + topbits = 8*maxbytes - bits + if topbits: + base = int2byte(ord(base[0]) & lsb_of_ones(topbits)) + base[1:] + number = 1+int(binascii.hexlify(base), 16) + assert 1 <= number < order + return number + +def randrange_from_seed__trytryagain(seed, order): + # figure out exactly how many bits we need (rounded up to the nearest + # bit), so we can reduce the chance of looping to less than 0.5 . This is + # specified to feed from a byte-oriented PRNG, and discards the + # high-order bits of the first byte as necessary to get the right number + # of bits. The average number of loops will range from 1.0 (when + # order=2**k-1) to 2.0 (when order=2**k+1). + assert order > 1 + bits, bytes, extrabits = bits_and_bytes(order) + generate = PRNG(seed) + while True: + extrabyte = b("") + if extrabits: + extrabyte = int2byte(ord(generate(1)) & lsb_of_ones(extrabits)) + guess = string_to_number(extrabyte + generate(bytes)) + 1 + if 1 <= guess < order: + return guess + + +def number_to_string(num, order): + l = orderlen(order) + fmt_str = "%0" + str(2*l) + "x" + string = binascii.unhexlify((fmt_str % num).encode()) + assert len(string) == l, (len(string), l) + return string + +def number_to_string_crop(num, order): + l = orderlen(order) + fmt_str = "%0" + str(2*l) + "x" + string = binascii.unhexlify((fmt_str % num).encode()) + return string[:l] + +def string_to_number(string): + return int(binascii.hexlify(string), 16) + +def string_to_number_fixedlen(string, order): + l = orderlen(order) + assert len(string) == l, (len(string), l) + return int(binascii.hexlify(string), 16) + +# these methods are useful for the sigencode= argument to SK.sign() and the +# sigdecode= argument to VK.verify(), and control how the signature is packed +# or unpacked. + +def sigencode_strings(r, s, order): + r_str = number_to_string(r, order) + s_str = number_to_string(s, order) + return (r_str, s_str) + +def sigencode_string(r, s, order): + # for any given curve, the size of the signature numbers is + # fixed, so just use simple concatenation + r_str, s_str = sigencode_strings(r, s, order) + return r_str + s_str + +def sigencode_der(r, s, order): + return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) + +# canonical versions of sigencode methods +# these enforce low S values, by negating the value (modulo the order) if above order/2 +# see CECKey::Sign() https://github.com/bitcoin/bitcoin/blob/master/src/key.cpp#L214 +def sigencode_strings_canonize(r, s, order): + if s > order / 2: + s = order - s + return sigencode_strings(r, s, order) + +def sigencode_string_canonize(r, s, order): + if s > order / 2: + s = order - s + return sigencode_string(r, s, order) + +def sigencode_der_canonize(r, s, order): + if s > order / 2: + s = order - s + return sigencode_der(r, s, order) + + +class MalformedSignature(Exception): + pass + + +def sigdecode_string(signature, order): + l = orderlen(order) + if not len(signature) == 2 * l: + raise MalformedSignature( + "Invalid length of signature, expected {0} bytes long, " + "provided string is {1} bytes long" + .format(2 * l, len(signature))) + r = string_to_number_fixedlen(signature[:l], order) + s = string_to_number_fixedlen(signature[l:], order) + return r, s + +def sigdecode_strings(rs_strings, order): + if not len(rs_strings) == 2: + raise MalformedSignature( + "Invalid number of strings provided: {0}, expected 2" + .format(len(rs_strings))) + (r_str, s_str) = rs_strings + l = orderlen(order) + if not len(r_str) == l: + raise MalformedSignature( + "Invalid length of first string ('r' parameter), " + "expected {0} bytes long, provided string is {1} bytes long" + .format(l, len(r_str))) + if not len(s_str) == l: + raise MalformedSignature( + "Invalid length of second string ('s' parameter), " + "expected {0} bytes long, provided string is {1} bytes long" + .format(l, len(s_str))) + r = string_to_number_fixedlen(r_str, order) + s = string_to_number_fixedlen(s_str, order) + return r, s + +def sigdecode_der(sig_der, order): + #return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) + rs_strings, empty = der.remove_sequence(sig_der) + if empty != b(""): + raise der.UnexpectedDER("trailing junk after DER sig: %s" % + binascii.hexlify(empty)) + r, rest = der.remove_integer(rs_strings) + s, empty = der.remove_integer(rest) + if empty != b(""): + raise der.UnexpectedDER("trailing junk after DER numbers: %s" % + binascii.hexlify(empty)) + return r, s + diff --git a/Lambdas/Websocket Authorizer/jose/__init__.py b/Lambdas/Websocket Authorizer/jose/__init__.py new file mode 100644 index 0000000..b34b5b4 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/__init__.py @@ -0,0 +1,11 @@ + +__version__ = "3.0.1" +__author__ = 'Michael Davis' +__license__ = 'MIT' +__copyright__ = 'Copyright 2016 Michael Davis' + + +from .exceptions import JOSEError # noqa: F401 +from .exceptions import JWSError # noqa: F401 +from .exceptions import ExpiredSignatureError # noqa: F401 +from .exceptions import JWTError # noqa: F401 diff --git a/Lambdas/Websocket Authorizer/jose/backends/__init__.py b/Lambdas/Websocket Authorizer/jose/backends/__init__.py new file mode 100644 index 0000000..d1b9fa1 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/backends/__init__.py @@ -0,0 +1,13 @@ + +try: + from jose.backends.cryptography_backend import CryptographyRSAKey as RSAKey # noqa: F401 +except ImportError: + try: + from jose.backends.pycrypto_backend import RSAKey # noqa: F401 + except ImportError: + from jose.backends.rsa_backend import RSAKey # noqa: F401 + +try: + from jose.backends.cryptography_backend import CryptographyECKey as ECKey # noqa: F401 +except ImportError: + from jose.backends.ecdsa_backend import ECDSAECKey as ECKey # noqa: F401 diff --git a/Lambdas/Websocket Authorizer/jose/backends/_asn1.py b/Lambdas/Websocket Authorizer/jose/backends/_asn1.py new file mode 100644 index 0000000..e252cc7 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/backends/_asn1.py @@ -0,0 +1,82 @@ +"""ASN1 encoding helpers for converting between PKCS1 and PKCS8. + +Required by rsa_backend and pycrypto_backend but not cryptography_backend. +""" +from pyasn1.codec.der import decoder, encoder +from pyasn1.type import namedtype, univ + +RSA_ENCRYPTION_ASN1_OID = "1.2.840.113549.1.1.1" + + +class RsaAlgorithmIdentifier(univ.Sequence): + """ASN1 structure for recording RSA PrivateKeyAlgorithm identifiers.""" + componentType = namedtype.NamedTypes( + namedtype.NamedType("rsaEncryption", univ.ObjectIdentifier()), + namedtype.NamedType("parameters", univ.Null()) + ) + + +class PKCS8PrivateKey(univ.Sequence): + """ASN1 structure for recording PKCS8 private keys.""" + componentType = namedtype.NamedTypes( + namedtype.NamedType("version", univ.Integer()), + namedtype.NamedType("privateKeyAlgorithm", RsaAlgorithmIdentifier()), + namedtype.NamedType("privateKey", univ.OctetString()) + ) + + +class PublicKeyInfo(univ.Sequence): + """ASN1 structure for recording PKCS8 public keys.""" + componentType = namedtype.NamedTypes( + namedtype.NamedType("algorithm", RsaAlgorithmIdentifier()), + namedtype.NamedType("publicKey", univ.BitString()) + ) + + +def rsa_private_key_pkcs8_to_pkcs1(pkcs8_key): + """Convert a PKCS8-encoded RSA private key to PKCS1.""" + decoded_values = decoder.decode(pkcs8_key, asn1Spec=PKCS8PrivateKey()) + + try: + decoded_key = decoded_values[0] + except IndexError: + raise ValueError("Invalid private key encoding") + + return decoded_key["privateKey"] + + +def rsa_private_key_pkcs1_to_pkcs8(pkcs1_key): + """Convert a PKCS1-encoded RSA private key to PKCS8.""" + algorithm = RsaAlgorithmIdentifier() + algorithm["rsaEncryption"] = RSA_ENCRYPTION_ASN1_OID + + pkcs8_key = PKCS8PrivateKey() + pkcs8_key["version"] = 0 + pkcs8_key["privateKeyAlgorithm"] = algorithm + pkcs8_key["privateKey"] = pkcs1_key + + return encoder.encode(pkcs8_key) + + +def rsa_public_key_pkcs1_to_pkcs8(pkcs1_key): + """Convert a PKCS1-encoded RSA private key to PKCS8.""" + algorithm = RsaAlgorithmIdentifier() + algorithm["rsaEncryption"] = RSA_ENCRYPTION_ASN1_OID + + pkcs8_key = PublicKeyInfo() + pkcs8_key["algorithm"] = algorithm + pkcs8_key["publicKey"] = univ.BitString.fromOctetString(pkcs1_key) + + return encoder.encode(pkcs8_key) + + +def rsa_public_key_pkcs8_to_pkcs1(pkcs8_key): + """Convert a PKCS8-encoded RSA private key to PKCS1.""" + decoded_values = decoder.decode(pkcs8_key, asn1Spec=PublicKeyInfo()) + + try: + decoded_key = decoded_values[0] + except IndexError: + raise ValueError("Invalid public key encoding.") + + return decoded_key["publicKey"].asOctets() diff --git a/Lambdas/Websocket Authorizer/jose/backends/base.py b/Lambdas/Websocket Authorizer/jose/backends/base.py new file mode 100644 index 0000000..37fc2ea --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/backends/base.py @@ -0,0 +1,21 @@ +class Key(object): + """ + A simple interface for implementing JWK keys. + """ + def __init__(self, key, algorithm): + pass + + def sign(self, msg): + raise NotImplementedError() + + def verify(self, msg, sig): + raise NotImplementedError() + + def public_key(self): + raise NotImplementedError() + + def to_pem(self): + raise NotImplementedError() + + def to_dict(self): + raise NotImplementedError() diff --git a/Lambdas/Websocket Authorizer/jose/backends/cryptography_backend.py b/Lambdas/Websocket Authorizer/jose/backends/cryptography_backend.py new file mode 100644 index 0000000..b9bdc0d --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/backends/cryptography_backend.py @@ -0,0 +1,371 @@ +from __future__ import division + +import math + +import six + +try: + from ecdsa import SigningKey as EcdsaSigningKey, VerifyingKey as EcdsaVerifyingKey +except ImportError: + EcdsaSigningKey = EcdsaVerifyingKey = None + +from jose.backends.base import Key +from jose.utils import base64_to_long, long_to_base64 +from jose.constants import ALGORITHMS +from jose.exceptions import JWKError + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec, rsa, padding +from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature, encode_dss_signature +from cryptography.hazmat.primitives.serialization import load_pem_private_key, load_pem_public_key +from cryptography.utils import int_from_bytes, int_to_bytes +from cryptography.x509 import load_pem_x509_certificate + + +class CryptographyECKey(Key): + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + + def __init__(self, key, algorithm, cryptography_backend=default_backend): + if algorithm not in ALGORITHMS.EC: + raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm) + + self.hash_alg = { + ALGORITHMS.ES256: self.SHA256, + ALGORITHMS.ES384: self.SHA384, + ALGORITHMS.ES512: self.SHA512 + }.get(algorithm) + self._algorithm = algorithm + + self.cryptography_backend = cryptography_backend + + if hasattr(key, 'public_bytes') or hasattr(key, 'private_bytes'): + self.prepared_key = key + return + + if None not in (EcdsaSigningKey, EcdsaVerifyingKey) and isinstance(key, (EcdsaSigningKey, EcdsaVerifyingKey)): + # convert to PEM and let cryptography below load it as PEM + key = key.to_pem().decode('utf-8') + + if isinstance(key, dict): + self.prepared_key = self._process_jwk(key) + return + + if isinstance(key, six.string_types): + key = key.encode('utf-8') + + if isinstance(key, six.binary_type): + # Attempt to load key. We don't know if it's + # a Public Key or a Private Key, so we try + # the Public Key first. + try: + try: + key = load_pem_public_key(key, self.cryptography_backend()) + except ValueError: + key = load_pem_private_key(key, password=None, backend=self.cryptography_backend()) + except Exception as e: + raise JWKError(e) + + self.prepared_key = key + return + + raise JWKError('Unable to parse an ECKey from key: %s' % key) + + def _process_jwk(self, jwk_dict): + if not jwk_dict.get('kty') == 'EC': + raise JWKError("Incorrect key type. Expected: 'EC', Received: %s" % jwk_dict.get('kty')) + + if not all(k in jwk_dict for k in ['x', 'y', 'crv']): + raise JWKError('Mandatory parameters are missing') + + x = base64_to_long(jwk_dict.get('x')) + y = base64_to_long(jwk_dict.get('y')) + curve = { + 'P-256': ec.SECP256R1, + 'P-384': ec.SECP384R1, + 'P-521': ec.SECP521R1, + }[jwk_dict['crv']] + + public = ec.EllipticCurvePublicNumbers(x, y, curve()) + + if 'd' in jwk_dict: + d = base64_to_long(jwk_dict.get('d')) + private = ec.EllipticCurvePrivateNumbers(d, public) + + return private.private_key(self.cryptography_backend()) + else: + return public.public_key(self.cryptography_backend()) + + def _sig_component_length(self): + """Determine the correct serialization length for an encoded signature component. + + This is the number of bytes required to encode the maximum key value. + """ + return int(math.ceil(self.prepared_key.key_size / 8.0)) + + def _der_to_raw(self, der_signature): + """Convert signature from DER encoding to RAW encoding.""" + r, s = decode_dss_signature(der_signature) + component_length = self._sig_component_length() + return int_to_bytes(r, component_length) + int_to_bytes(s, component_length) + + def _raw_to_der(self, raw_signature): + """Convert signature from RAW encoding to DER encoding.""" + component_length = self._sig_component_length() + if len(raw_signature) != int(2 * component_length): + raise ValueError("Invalid signature") + + r_bytes = raw_signature[:component_length] + s_bytes = raw_signature[component_length:] + r = int_from_bytes(r_bytes, "big") + s = int_from_bytes(s_bytes, "big") + return encode_dss_signature(r, s) + + def sign(self, msg): + if self.hash_alg.digest_size * 8 > self.prepared_key.curve.key_size: + raise TypeError("this curve (%s) is too short " + "for your digest (%d)" % (self.prepared_key.curve.name, + 8 * self.hash_alg.digest_size)) + signature = self.prepared_key.sign(msg, ec.ECDSA(self.hash_alg())) + return self._der_to_raw(signature) + + def verify(self, msg, sig): + try: + signature = self._raw_to_der(sig) + self.prepared_key.verify(signature, msg, ec.ECDSA(self.hash_alg())) + return True + except Exception: + return False + + def is_public(self): + return hasattr(self.prepared_key, 'public_bytes') + + def public_key(self): + if self.is_public(): + return self + return self.__class__(self.prepared_key.public_key(), self._algorithm) + + def to_pem(self): + if self.is_public(): + pem = self.prepared_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + return pem + pem = self.prepared_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + ) + return pem + + def to_dict(self): + if not self.is_public(): + public_key = self.prepared_key.public_key() + else: + public_key = self.prepared_key + + crv = { + 'secp256r1': 'P-256', + 'secp384r1': 'P-384', + 'secp521r1': 'P-521', + }[self.prepared_key.curve.name] + + # Calculate the key size in bytes. Section 6.2.1.2 and 6.2.1.3 of + # RFC7518 prescribes that the 'x', 'y' and 'd' parameters of the curve + # points must be encoded as octed-strings of this length. + key_size = (self.prepared_key.curve.key_size + 7) // 8 + + data = { + 'alg': self._algorithm, + 'kty': 'EC', + 'crv': crv, + 'x': long_to_base64(public_key.public_numbers().x, size=key_size), + 'y': long_to_base64(public_key.public_numbers().y, size=key_size), + } + + if not self.is_public(): + data['d'] = long_to_base64( + self.prepared_key.private_numbers().private_value, + size=key_size + ) + + return data + + +class CryptographyRSAKey(Key): + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + + def __init__(self, key, algorithm, cryptography_backend=default_backend): + if algorithm not in ALGORITHMS.RSA: + raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm) + + self.hash_alg = { + ALGORITHMS.RS256: self.SHA256, + ALGORITHMS.RS384: self.SHA384, + ALGORITHMS.RS512: self.SHA512 + }.get(algorithm) + self._algorithm = algorithm + + self.cryptography_backend = cryptography_backend + + # if it conforms to RSAPublicKey interface + if hasattr(key, 'public_bytes') and hasattr(key, 'public_numbers'): + self.prepared_key = key + return + + if isinstance(key, dict): + self.prepared_key = self._process_jwk(key) + return + + if isinstance(key, six.string_types): + key = key.encode('utf-8') + + if isinstance(key, six.binary_type): + try: + if key.startswith(b'-----BEGIN CERTIFICATE-----'): + self._process_cert(key) + return + + try: + self.prepared_key = load_pem_public_key(key, self.cryptography_backend()) + except ValueError: + self.prepared_key = load_pem_private_key(key, password=None, backend=self.cryptography_backend()) + except Exception as e: + raise JWKError(e) + return + + raise JWKError('Unable to parse an RSA_JWK from key: %s' % key) + + def _process_jwk(self, jwk_dict): + if not jwk_dict.get('kty') == 'RSA': + raise JWKError("Incorrect key type. Expected: 'RSA', Received: %s" % jwk_dict.get('kty')) + + e = base64_to_long(jwk_dict.get('e', 256)) + n = base64_to_long(jwk_dict.get('n')) + public = rsa.RSAPublicNumbers(e, n) + + if 'd' not in jwk_dict: + return public.public_key(self.cryptography_backend()) + else: + # This is a private key. + d = base64_to_long(jwk_dict.get('d')) + + extra_params = ['p', 'q', 'dp', 'dq', 'qi'] + + if any(k in jwk_dict for k in extra_params): + # Precomputed private key parameters are available. + if not all(k in jwk_dict for k in extra_params): + # These values must be present when 'p' is according to + # Section 6.3.2 of RFC7518, so if they are not we raise + # an error. + raise JWKError('Precomputed private key parameters are incomplete.') + + p = base64_to_long(jwk_dict['p']) + q = base64_to_long(jwk_dict['q']) + dp = base64_to_long(jwk_dict['dp']) + dq = base64_to_long(jwk_dict['dq']) + qi = base64_to_long(jwk_dict['qi']) + else: + # The precomputed private key parameters are not available, + # so we use cryptography's API to fill them in. + p, q = rsa.rsa_recover_prime_factors(n, e, d) + dp = rsa.rsa_crt_dmp1(d, p) + dq = rsa.rsa_crt_dmq1(d, q) + qi = rsa.rsa_crt_iqmp(p, q) + + private = rsa.RSAPrivateNumbers(p, q, d, dp, dq, qi, public) + + return private.private_key(self.cryptography_backend()) + + def _process_cert(self, key): + key = load_pem_x509_certificate(key, self.cryptography_backend()) + self.prepared_key = key.public_key() + + def sign(self, msg): + try: + signature = self.prepared_key.sign( + msg, + padding.PKCS1v15(), + self.hash_alg() + ) + except Exception as e: + raise JWKError(e) + return signature + + def verify(self, msg, sig): + try: + self.prepared_key.verify( + sig, + msg, + padding.PKCS1v15(), + self.hash_alg() + ) + return True + except InvalidSignature: + return False + + def is_public(self): + return hasattr(self.prepared_key, 'public_bytes') + + def public_key(self): + if self.is_public(): + return self + return self.__class__(self.prepared_key.public_key(), self._algorithm) + + def to_pem(self, pem_format='PKCS8'): + if self.is_public(): + if pem_format == 'PKCS8': + fmt = serialization.PublicFormat.SubjectPublicKeyInfo + elif pem_format == 'PKCS1': + fmt = serialization.PublicFormat.PKCS1 + else: + raise ValueError("Invalid format specified: %r" % pem_format) + pem = self.prepared_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=fmt + ) + return pem + + if pem_format == 'PKCS8': + fmt = serialization.PrivateFormat.PKCS8 + elif pem_format == 'PKCS1': + fmt = serialization.PrivateFormat.TraditionalOpenSSL + else: + raise ValueError("Invalid format specified: %r" % pem_format) + + return self.prepared_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=fmt, + encryption_algorithm=serialization.NoEncryption() + ) + + def to_dict(self): + if not self.is_public(): + public_key = self.prepared_key.public_key() + else: + public_key = self.prepared_key + + data = { + 'alg': self._algorithm, + 'kty': 'RSA', + 'n': long_to_base64(public_key.public_numbers().n), + 'e': long_to_base64(public_key.public_numbers().e), + } + + if not self.is_public(): + data.update({ + 'd': long_to_base64(self.prepared_key.private_numbers().d), + 'p': long_to_base64(self.prepared_key.private_numbers().p), + 'q': long_to_base64(self.prepared_key.private_numbers().q), + 'dp': long_to_base64(self.prepared_key.private_numbers().dmp1), + 'dq': long_to_base64(self.prepared_key.private_numbers().dmq1), + 'qi': long_to_base64(self.prepared_key.private_numbers().iqmp), + }) + + return data diff --git a/Lambdas/Websocket Authorizer/jose/backends/ecdsa_backend.py b/Lambdas/Websocket Authorizer/jose/backends/ecdsa_backend.py new file mode 100644 index 0000000..8b8b9a2 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/backends/ecdsa_backend.py @@ -0,0 +1,144 @@ +import hashlib +import six + +from jose.backends.base import Key +import ecdsa + +from jose.constants import ALGORITHMS +from jose.exceptions import JWKError +from jose.utils import base64_to_long, long_to_base64 + + +class ECDSAECKey(Key): + """ + Performs signing and verification operations using + ECDSA and the specified hash function + + This class requires the ecdsa package to be installed. + + This is based off of the implementation in PyJWT 0.3.2 + """ + SHA256 = hashlib.sha256 + SHA384 = hashlib.sha384 + SHA512 = hashlib.sha512 + + CURVE_MAP = { + SHA256: ecdsa.curves.NIST256p, + SHA384: ecdsa.curves.NIST384p, + SHA512: ecdsa.curves.NIST521p, + } + + def __init__(self, key, algorithm): + if algorithm not in ALGORITHMS.EC: + raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm) + + self.hash_alg = { + ALGORITHMS.ES256: self.SHA256, + ALGORITHMS.ES384: self.SHA384, + ALGORITHMS.ES512: self.SHA512 + }.get(algorithm) + self._algorithm = algorithm + + self.curve = self.CURVE_MAP.get(self.hash_alg) + + if isinstance(key, (ecdsa.SigningKey, ecdsa.VerifyingKey)): + self.prepared_key = key + return + + if isinstance(key, dict): + self.prepared_key = self._process_jwk(key) + return + + if isinstance(key, six.string_types): + key = key.encode('utf-8') + + if isinstance(key, six.binary_type): + # Attempt to load key. We don't know if it's + # a Signing Key or a Verifying Key, so we try + # the Verifying Key first. + try: + key = ecdsa.VerifyingKey.from_pem(key) + except ecdsa.der.UnexpectedDER: + key = ecdsa.SigningKey.from_pem(key) + except Exception as e: + raise JWKError(e) + + self.prepared_key = key + return + + raise JWKError('Unable to parse an ECKey from key: %s' % key) + + def _process_jwk(self, jwk_dict): + if not jwk_dict.get('kty') == 'EC': + raise JWKError("Incorrect key type. Expected: 'EC', Recieved: %s" % jwk_dict.get('kty')) + + if not all(k in jwk_dict for k in ['x', 'y', 'crv']): + raise JWKError('Mandatory parameters are missing') + + if 'd' in jwk_dict: + # We are dealing with a private key; the secret exponent is enough + # to create an ecdsa key. + d = base64_to_long(jwk_dict.get('d')) + return ecdsa.keys.SigningKey.from_secret_exponent(d, self.curve) + else: + x = base64_to_long(jwk_dict.get('x')) + y = base64_to_long(jwk_dict.get('y')) + + if not ecdsa.ecdsa.point_is_valid(self.curve.generator, x, y): + raise JWKError("Point: %s, %s is not a valid point" % (x, y)) + + point = ecdsa.ellipticcurve.Point(self.curve.curve, x, y, self.curve.order) + return ecdsa.keys.VerifyingKey.from_public_point(point, self.curve) + + def sign(self, msg): + return self.prepared_key.sign(msg, hashfunc=self.hash_alg, sigencode=ecdsa.util.sigencode_string) + + def verify(self, msg, sig): + try: + return self.prepared_key.verify(sig, msg, hashfunc=self.hash_alg, sigdecode=ecdsa.util.sigdecode_string) + except Exception: + return False + + def is_public(self): + return isinstance(self.prepared_key, ecdsa.VerifyingKey) + + def public_key(self): + if self.is_public(): + return self + return self.__class__(self.prepared_key.get_verifying_key(), self._algorithm) + + def to_pem(self): + return self.prepared_key.to_pem() + + def to_dict(self): + if not self.is_public(): + public_key = self.prepared_key.get_verifying_key() + else: + public_key = self.prepared_key + + crv = { + ecdsa.curves.NIST256p: 'P-256', + ecdsa.curves.NIST384p: 'P-384', + ecdsa.curves.NIST521p: 'P-521', + }[self.prepared_key.curve] + + # Calculate the key size in bytes. Section 6.2.1.2 and 6.2.1.3 of + # RFC7518 prescribes that the 'x', 'y' and 'd' parameters of the curve + # points must be encoded as octed-strings of this length. + key_size = self.prepared_key.curve.baselen + + data = { + 'alg': self._algorithm, + 'kty': 'EC', + 'crv': crv, + 'x': long_to_base64(public_key.pubkey.point.x(), size=key_size), + 'y': long_to_base64(public_key.pubkey.point.y(), size=key_size), + } + + if not self.is_public(): + data['d'] = long_to_base64( + self.prepared_key.privkey.secret_multiplier, + size=key_size + ) + + return data diff --git a/Lambdas/Websocket Authorizer/jose/backends/pycrypto_backend.py b/Lambdas/Websocket Authorizer/jose/backends/pycrypto_backend.py new file mode 100644 index 0000000..a12e861 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/backends/pycrypto_backend.py @@ -0,0 +1,212 @@ +from base64 import b64encode + +import six + +import Crypto.Hash.SHA256 +import Crypto.Hash.SHA384 +import Crypto.Hash.SHA512 + +from Crypto.PublicKey import RSA +from Crypto.Signature import PKCS1_v1_5 +from Crypto.Util.asn1 import DerSequence + +from jose.backends.base import Key +from jose.backends._asn1 import rsa_public_key_pkcs8_to_pkcs1 +from jose.utils import base64_to_long, long_to_base64 +from jose.constants import ALGORITHMS +from jose.exceptions import JWKError +from jose.utils import base64url_decode + + +# We default to using PyCryptodome, however, if PyCrypto is installed, it is +# used instead. This is so that environments that require the use of PyCrypto +# are still supported. +if hasattr(RSA, 'RsaKey'): + _RSAKey = RSA.RsaKey +else: + _RSAKey = RSA._RSAobj + + +def _der_to_pem(der_key, marker): + """ + Perform a simple DER to PEM conversion. + """ + pem_key_chunks = [('-----BEGIN %s-----' % marker).encode('utf-8')] + + # Limit base64 output lines to 64 characters by limiting input lines to 48 characters. + for chunk_start in range(0, len(der_key), 48): + pem_key_chunks.append(b64encode(der_key[chunk_start:chunk_start + 48])) + + pem_key_chunks.append(('-----END %s-----' % marker).encode('utf-8')) + + return b'\n'.join(pem_key_chunks) + + +class RSAKey(Key): + """ + Performs signing and verification operations using + RSASSA-PKCS-v1_5 and the specified hash function. + This class requires PyCrypto package to be installed. + This is based off of the implementation in PyJWT 0.3.2 + """ + + SHA256 = Crypto.Hash.SHA256 + SHA384 = Crypto.Hash.SHA384 + SHA512 = Crypto.Hash.SHA512 + + def __init__(self, key, algorithm): + + if algorithm not in ALGORITHMS.RSA: + raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm) + + self.hash_alg = { + ALGORITHMS.RS256: self.SHA256, + ALGORITHMS.RS384: self.SHA384, + ALGORITHMS.RS512: self.SHA512 + }.get(algorithm) + self._algorithm = algorithm + + if isinstance(key, _RSAKey): + self.prepared_key = key + return + + if isinstance(key, dict): + self._process_jwk(key) + return + + if isinstance(key, six.string_types): + key = key.encode('utf-8') + + if isinstance(key, six.binary_type): + if key.startswith(b'-----BEGIN CERTIFICATE-----'): + try: + self._process_cert(key) + except Exception as e: + raise JWKError(e) + return + + try: + self.prepared_key = RSA.importKey(key) + except Exception as e: + raise JWKError(e) + return + + raise JWKError('Unable to parse an RSA_JWK from key: %s' % key) + + def _process_jwk(self, jwk_dict): + if not jwk_dict.get('kty') == 'RSA': + raise JWKError("Incorrect key type. Expected: 'RSA', Recieved: %s" % jwk_dict.get('kty')) + + e = base64_to_long(jwk_dict.get('e', 256)) + n = base64_to_long(jwk_dict.get('n')) + params = (n, e) + + if 'd' in jwk_dict: + params += (base64_to_long(jwk_dict.get('d')),) + + extra_params = ['p', 'q', 'dp', 'dq', 'qi'] + + if any(k in jwk_dict for k in extra_params): + # Precomputed private key parameters are available. + if not all(k in jwk_dict for k in extra_params): + # These values must be present when 'p' is according to + # Section 6.3.2 of RFC7518, so if they are not we raise + # an error. + raise JWKError('Precomputed private key parameters are incomplete.') + + p = base64_to_long(jwk_dict.get('p')) + q = base64_to_long(jwk_dict.get('q')) + qi = base64_to_long(jwk_dict.get('qi')) + + # PyCrypto does not take the dp and dq as arguments, so we do + # not pass them. Furthermore, the parameter qi specified in + # the JWK is the inverse of q modulo p, whereas PyCrypto + # takes the inverse of p modulo q. We therefore switch the + # parameters to make the third parameter the inverse of the + # second parameter modulo the first parameter. + params += (q, p, qi) + + self.prepared_key = RSA.construct(params) + + return self.prepared_key + + def _process_cert(self, key): + pemLines = key.replace(b' ', b'').split() + certDer = base64url_decode(b''.join(pemLines[1:-1])) + certSeq = DerSequence() + certSeq.decode(certDer) + tbsSeq = DerSequence() + tbsSeq.decode(certSeq[0]) + self.prepared_key = RSA.importKey(tbsSeq[6]) + return + + def sign(self, msg): + try: + return PKCS1_v1_5.new(self.prepared_key).sign(self.hash_alg.new(msg)) + except Exception as e: + raise JWKError(e) + + def verify(self, msg, sig): + try: + return PKCS1_v1_5.new(self.prepared_key).verify(self.hash_alg.new(msg), sig) + except Exception: + return False + + def is_public(self): + return not self.prepared_key.has_private() + + def public_key(self): + if self.is_public(): + return self + return self.__class__(self.prepared_key.publickey(), self._algorithm) + + def to_pem(self, pem_format='PKCS8'): + if pem_format == 'PKCS8': + pkcs = 8 + elif pem_format == 'PKCS1': + pkcs = 1 + else: + raise ValueError("Invalid pem format specified: %r" % (pem_format,)) + + if self.is_public(): + # PyCrypto/dome always export public keys as PKCS8 + if pkcs == 8: + pem = self.prepared_key.exportKey('PEM') + else: + pkcs8_der = self.prepared_key.exportKey('DER') + pkcs1_der = rsa_public_key_pkcs8_to_pkcs1(pkcs8_der) + pem = _der_to_pem(pkcs1_der, 'RSA PUBLIC KEY') + return pem + else: + pem = self.prepared_key.exportKey('PEM', pkcs=pkcs) + return pem + + def to_dict(self): + data = { + 'alg': self._algorithm, + 'kty': 'RSA', + 'n': long_to_base64(self.prepared_key.n), + 'e': long_to_base64(self.prepared_key.e), + } + + if not self.is_public(): + # Section 6.3.2 of RFC7518 prescribes that when we include the + # optional parameters p and q, we must also include the values of + # dp and dq, which are not readily available from PyCrypto - so we + # calculate them. Moreover, PyCrypto stores the inverse of p + # modulo q rather than the inverse of q modulo p, so we switch + # p and q. As far as I can tell, this is OK - RFC7518 only + # asserts that p is the 'first factor', but does not specify + # what 'first' means in this case. + dp = self.prepared_key.d % (self.prepared_key.p - 1) + dq = self.prepared_key.d % (self.prepared_key.q - 1) + data.update({ + 'd': long_to_base64(self.prepared_key.d), + 'p': long_to_base64(self.prepared_key.q), + 'q': long_to_base64(self.prepared_key.p), + 'dp': long_to_base64(dq), + 'dq': long_to_base64(dp), + 'qi': long_to_base64(self.prepared_key.u), + }) + + return data diff --git a/Lambdas/Websocket Authorizer/jose/backends/rsa_backend.py b/Lambdas/Websocket Authorizer/jose/backends/rsa_backend.py new file mode 100644 index 0000000..c1f5539 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/backends/rsa_backend.py @@ -0,0 +1,263 @@ +import binascii + +import six +from pyasn1.error import PyAsn1Error + +import rsa as pyrsa +import rsa.pem as pyrsa_pem + +from jose.backends.base import Key +from jose.backends._asn1 import ( + rsa_private_key_pkcs1_to_pkcs8, + rsa_private_key_pkcs8_to_pkcs1, + rsa_public_key_pkcs1_to_pkcs8, +) +from jose.constants import ALGORITHMS +from jose.exceptions import JWKError +from jose.utils import base64_to_long, long_to_base64 + + +LEGACY_INVALID_PKCS8_RSA_HEADER = binascii.unhexlify( + "30" # sequence + "8204BD" # DER-encoded sequence contents length of 1213 bytes -- INCORRECT STATIC LENGTH + "020100" # integer: 0 -- Version + "30" # sequence + "0D" # DER-encoded sequence contents length of 13 bytes -- PrivateKeyAlgorithmIdentifier + "06092A864886F70D010101" # OID -- rsaEncryption + "0500" # NULL -- parameters +) +ASN1_SEQUENCE_ID = binascii.unhexlify("30") +RSA_ENCRYPTION_ASN1_OID = "1.2.840.113549.1.1.1" + +# Functions gcd and rsa_recover_prime_factors were copied from cryptography 1.9 +# to enable pure python rsa module to be in compliance with section 6.3.1 of RFC7518 +# which requires only private exponent (d) for private key. + + +def _gcd(a, b): + """Calculate the Greatest Common Divisor of a and b. + + Unless b==0, the result will have the same sign as b (so that when + b is divided by it, the result comes out positive). + """ + while b: + a, b = b, (a % b) + return a + + +# Controls the number of iterations rsa_recover_prime_factors will perform +# to obtain the prime factors. Each iteration increments by 2 so the actual +# maximum attempts is half this number. +_MAX_RECOVERY_ATTEMPTS = 1000 + + +def _rsa_recover_prime_factors(n, e, d): + """ + Compute factors p and q from the private exponent d. We assume that n has + no more than two factors. This function is adapted from code in PyCrypto. + """ + # See 8.2.2(i) in Handbook of Applied Cryptography. + ktot = d * e - 1 + # The quantity d*e-1 is a multiple of phi(n), even, + # and can be represented as t*2^s. + t = ktot + while t % 2 == 0: + t = t // 2 + # Cycle through all multiplicative inverses in Zn. + # The algorithm is non-deterministic, but there is a 50% chance + # any candidate a leads to successful factoring. + # See "Digitalized Signatures and Public Key Functions as Intractable + # as Factorization", M. Rabin, 1979 + spotted = False + a = 2 + while not spotted and a < _MAX_RECOVERY_ATTEMPTS: + k = t + # Cycle through all values a^{t*2^i}=a^k + while k < ktot: + cand = pow(a, k, n) + # Check if a^k is a non-trivial root of unity (mod n) + if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: + # We have found a number such that (cand-1)(cand+1)=0 (mod n). + # Either of the terms divides n. + p = _gcd(cand + 1, n) + spotted = True + break + k *= 2 + # This value was not any good... let's try another! + a += 2 + if not spotted: + raise ValueError("Unable to compute factors p and q from exponent d.") + # Found ! + q, r = divmod(n, p) + assert r == 0 + p, q = sorted((p, q), reverse=True) + return (p, q) + + +def pem_to_spki(pem, fmt='PKCS8'): + key = RSAKey(pem, ALGORITHMS.RS256) + return key.to_pem(fmt) + + +def _legacy_private_key_pkcs8_to_pkcs1(pkcs8_key): + """Legacy RSA private key PKCS8-to-PKCS1 conversion. + + .. warning:: + + This is incorrect parsing and only works because the legacy PKCS1-to-PKCS8 + encoding was also incorrect. + """ + # Only allow this processing if the prefix matches + # AND the following byte indicates an ASN1 sequence, + # as we would expect with the legacy encoding. + if not pkcs8_key.startswith(LEGACY_INVALID_PKCS8_RSA_HEADER + ASN1_SEQUENCE_ID): + raise ValueError("Invalid private key encoding") + + return pkcs8_key[len(LEGACY_INVALID_PKCS8_RSA_HEADER):] + + +class RSAKey(Key): + SHA256 = 'SHA-256' + SHA384 = 'SHA-384' + SHA512 = 'SHA-512' + + def __init__(self, key, algorithm): + if algorithm not in ALGORITHMS.RSA: + raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm) + + self.hash_alg = { + ALGORITHMS.RS256: self.SHA256, + ALGORITHMS.RS384: self.SHA384, + ALGORITHMS.RS512: self.SHA512 + }.get(algorithm) + self._algorithm = algorithm + + if isinstance(key, dict): + self._prepared_key = self._process_jwk(key) + return + + if isinstance(key, (pyrsa.PublicKey, pyrsa.PrivateKey)): + self._prepared_key = key + return + + if isinstance(key, six.string_types): + key = key.encode('utf-8') + + if isinstance(key, six.binary_type): + try: + self._prepared_key = pyrsa.PublicKey.load_pkcs1(key) + except ValueError: + try: + self._prepared_key = pyrsa.PublicKey.load_pkcs1_openssl_pem(key) + except ValueError: + try: + self._prepared_key = pyrsa.PrivateKey.load_pkcs1(key) + except ValueError: + try: + der = pyrsa_pem.load_pem(key, b'PRIVATE KEY') + try: + pkcs1_key = rsa_private_key_pkcs8_to_pkcs1(der) + except PyAsn1Error: + # If the key was encoded using the old, invalid, + # encoding then pyasn1 will throw an error attempting + # to parse the key. + pkcs1_key = _legacy_private_key_pkcs8_to_pkcs1(der) + self._prepared_key = pyrsa.PrivateKey.load_pkcs1(pkcs1_key, format="DER") + except ValueError as e: + raise JWKError(e) + return + raise JWKError('Unable to parse an RSA_JWK from key: %s' % key) + + def _process_jwk(self, jwk_dict): + if not jwk_dict.get('kty') == 'RSA': + raise JWKError("Incorrect key type. Expected: 'RSA', Recieved: %s" % jwk_dict.get('kty')) + + e = base64_to_long(jwk_dict.get('e')) + n = base64_to_long(jwk_dict.get('n')) + + if 'd' not in jwk_dict: + return pyrsa.PublicKey(e=e, n=n) + else: + d = base64_to_long(jwk_dict.get('d')) + extra_params = ['p', 'q', 'dp', 'dq', 'qi'] + + if any(k in jwk_dict for k in extra_params): + # Precomputed private key parameters are available. + if not all(k in jwk_dict for k in extra_params): + # These values must be present when 'p' is according to + # Section 6.3.2 of RFC7518, so if they are not we raise + # an error. + raise JWKError('Precomputed private key parameters are incomplete.') + + p = base64_to_long(jwk_dict['p']) + q = base64_to_long(jwk_dict['q']) + return pyrsa.PrivateKey(e=e, n=n, d=d, p=p, q=q) + else: + p, q = _rsa_recover_prime_factors(n, e, d) + return pyrsa.PrivateKey(n=n, e=e, d=d, p=p, q=q) + + def sign(self, msg): + return pyrsa.sign(msg, self._prepared_key, self.hash_alg) + + def verify(self, msg, sig): + try: + pyrsa.verify(msg, sig, self._prepared_key) + return True + except pyrsa.pkcs1.VerificationError: + return False + + def is_public(self): + return isinstance(self._prepared_key, pyrsa.PublicKey) + + def public_key(self): + if isinstance(self._prepared_key, pyrsa.PublicKey): + return self + return self.__class__(pyrsa.PublicKey(n=self._prepared_key.n, e=self._prepared_key.e), self._algorithm) + + def to_pem(self, pem_format='PKCS8'): + + if isinstance(self._prepared_key, pyrsa.PrivateKey): + der = self._prepared_key.save_pkcs1(format='DER') + if pem_format == 'PKCS8': + pkcs8_der = rsa_private_key_pkcs1_to_pkcs8(der) + pem = pyrsa_pem.save_pem(pkcs8_der, pem_marker='PRIVATE KEY') + elif pem_format == 'PKCS1': + pem = pyrsa_pem.save_pem(der, pem_marker='RSA PRIVATE KEY') + else: + raise ValueError("Invalid pem format specified: %r" % (pem_format,)) + else: + if pem_format == 'PKCS8': + pkcs1_der = self._prepared_key.save_pkcs1(format="DER") + pkcs8_der = rsa_public_key_pkcs1_to_pkcs8(pkcs1_der) + pem = pyrsa_pem.save_pem(pkcs8_der, pem_marker='PUBLIC KEY') + elif pem_format == 'PKCS1': + der = self._prepared_key.save_pkcs1(format='DER') + pem = pyrsa_pem.save_pem(der, pem_marker='RSA PUBLIC KEY') + else: + raise ValueError("Invalid pem format specified: %r" % (pem_format,)) + return pem + + def to_dict(self): + if not self.is_public(): + public_key = self.public_key()._prepared_key + else: + public_key = self._prepared_key + + data = { + 'alg': self._algorithm, + 'kty': 'RSA', + 'n': long_to_base64(public_key.n), + 'e': long_to_base64(public_key.e), + } + + if not self.is_public(): + data.update({ + 'd': long_to_base64(self._prepared_key.d), + 'p': long_to_base64(self._prepared_key.p), + 'q': long_to_base64(self._prepared_key.q), + 'dp': long_to_base64(self._prepared_key.exp1), + 'dq': long_to_base64(self._prepared_key.exp2), + 'qi': long_to_base64(self._prepared_key.coef), + }) + + return data diff --git a/Lambdas/Websocket Authorizer/jose/constants.py b/Lambdas/Websocket Authorizer/jose/constants.py new file mode 100644 index 0000000..eb14654 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/constants.py @@ -0,0 +1,39 @@ +import hashlib + + +class Algorithms(object): + NONE = 'none' + HS256 = 'HS256' + HS384 = 'HS384' + HS512 = 'HS512' + RS256 = 'RS256' + RS384 = 'RS384' + RS512 = 'RS512' + ES256 = 'ES256' + ES384 = 'ES384' + ES512 = 'ES512' + + HMAC = {HS256, HS384, HS512} + RSA = {RS256, RS384, RS512} + EC = {ES256, ES384, ES512} + + SUPPORTED = HMAC.union(RSA).union(EC) + + ALL = SUPPORTED.union([NONE]) + + HASHES = { + HS256: hashlib.sha256, + HS384: hashlib.sha384, + HS512: hashlib.sha512, + RS256: hashlib.sha256, + RS384: hashlib.sha384, + RS512: hashlib.sha512, + ES256: hashlib.sha256, + ES384: hashlib.sha384, + ES512: hashlib.sha512, + } + + KEYS = {} + + +ALGORITHMS = Algorithms() diff --git a/Lambdas/Websocket Authorizer/jose/exceptions.py b/Lambdas/Websocket Authorizer/jose/exceptions.py new file mode 100644 index 0000000..22334d6 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/exceptions.py @@ -0,0 +1,36 @@ + + +class JOSEError(Exception): + pass + + +class JWSError(JOSEError): + pass + + +class JWSSignatureError(JWSError): + pass + + +class JWSAlgorithmError(JWSError): + pass + + +class JWTError(JOSEError): + pass + + +class JWTClaimsError(JWTError): + pass + + +class JWTSignatureError(JWTError): + pass + + +class ExpiredSignatureError(JWTError): + pass + + +class JWKError(JOSEError): + pass diff --git a/Lambdas/Websocket Authorizer/jose/jwk.py b/Lambdas/Websocket Authorizer/jose/jwk.py new file mode 100644 index 0000000..87f30b4 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/jwk.py @@ -0,0 +1,142 @@ + +import hashlib +import hmac +import six + +from jose.constants import ALGORITHMS +from jose.exceptions import JWKError +from jose.utils import base64url_decode, base64url_encode +from jose.utils import constant_time_string_compare +from jose.backends.base import Key + +try: + from jose.backends import RSAKey # noqa: F401 +except ImportError: + pass + +try: + from jose.backends import ECKey # noqa: F401 +except ImportError: + pass + + +def get_key(algorithm): + if algorithm in ALGORITHMS.KEYS: + return ALGORITHMS.KEYS[algorithm] + elif algorithm in ALGORITHMS.HMAC: + return HMACKey + elif algorithm in ALGORITHMS.RSA: + from jose.backends import RSAKey # noqa: F811 + return RSAKey + elif algorithm in ALGORITHMS.EC: + from jose.backends import ECKey # noqa: F811 + return ECKey + return None + + +def register_key(algorithm, key_class): + if not issubclass(key_class, Key): + raise TypeError("Key class not a subclass of jwk.Key") + ALGORITHMS.KEYS[algorithm] = key_class + ALGORITHMS.SUPPORTED.add(algorithm) + return True + + +def construct(key_data, algorithm=None): + """ + Construct a Key object for the given algorithm with the given + key_data. + """ + + # Allow for pulling the algorithm off of the passed in jwk. + if not algorithm and isinstance(key_data, dict): + algorithm = key_data.get('alg', None) + + if not algorithm: + raise JWKError('Unable to find a algorithm for key: %s' % key_data) + + key_class = get_key(algorithm) + if not key_class: + raise JWKError('Unable to find a algorithm for key: %s' % key_data) + return key_class(key_data, algorithm) + + +def get_algorithm_object(algorithm): + algorithms = { + ALGORITHMS.HS256: 'SHA256', + ALGORITHMS.HS384: 'SHA384', + ALGORITHMS.HS512: 'SHA512', + ALGORITHMS.RS256: 'SHA256', + ALGORITHMS.RS384: 'SHA384', + ALGORITHMS.RS512: 'SHA512', + ALGORITHMS.ES256: 'SHA256', + ALGORITHMS.ES384: 'SHA384', + ALGORITHMS.ES512: 'SHA512', + } + key = get_key(algorithm) + attr = algorithms.get(algorithm, None) + return getattr(key, attr) + + +class HMACKey(Key): + """ + Performs signing and verification operations using HMAC + and the specified hash function. + """ + SHA256 = hashlib.sha256 + SHA384 = hashlib.sha384 + SHA512 = hashlib.sha512 + + def __init__(self, key, algorithm): + if algorithm not in ALGORITHMS.HMAC: + raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm) + self._algorithm = algorithm + self.hash_alg = get_algorithm_object(algorithm) + + if isinstance(key, dict): + self.prepared_key = self._process_jwk(key) + return + + if not isinstance(key, six.string_types) and not isinstance(key, bytes): + raise JWKError('Expecting a string- or bytes-formatted key.') + + if isinstance(key, six.text_type): + key = key.encode('utf-8') + + invalid_strings = [ + b'-----BEGIN PUBLIC KEY-----', + b'-----BEGIN RSA PUBLIC KEY-----', + b'-----BEGIN CERTIFICATE-----', + b'ssh-rsa' + ] + + if any(string_value in key for string_value in invalid_strings): + raise JWKError( + 'The specified key is an asymmetric key or x509 certificate and' + ' should not be used as an HMAC secret.') + + self.prepared_key = key + + def _process_jwk(self, jwk_dict): + if not jwk_dict.get('kty') == 'oct': + raise JWKError("Incorrect key type. Expected: 'oct', Recieved: %s" % jwk_dict.get('kty')) + + k = jwk_dict.get('k') + k = k.encode('utf-8') + k = bytes(k) + k = base64url_decode(k) + + return k + + def sign(self, msg): + return hmac.new(self.prepared_key, msg, self.hash_alg).digest() + + def verify(self, msg, sig): + return constant_time_string_compare(sig, self.sign(msg)) + + def to_dict(self): + return { + 'alg': self._algorithm, + 'kty': 'oct', + 'k': base64url_encode(self.prepared_key), + } diff --git a/Lambdas/Websocket Authorizer/jose/jws.py b/Lambdas/Websocket Authorizer/jose/jws.py new file mode 100644 index 0000000..9d2fc0d --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/jws.py @@ -0,0 +1,273 @@ + +import binascii +import json +import six + +try: + from collections.abc import Mapping, Iterable # Python 3 +except ImportError: + from collections import Mapping, Iterable # Python 2, will be deprecated in Python 3.8 + +from jose import jwk +from jose.constants import ALGORITHMS +from jose.exceptions import JWSError +from jose.exceptions import JWSSignatureError +from jose.utils import base64url_encode +from jose.utils import base64url_decode + + +def sign(payload, key, headers=None, algorithm=ALGORITHMS.HS256): + """Signs a claims set and returns a JWS string. + + Args: + payload (str): A string to sign + key (str or dict): The key to use for signing the claim set. Can be + individual JWK or JWK set. + headers (dict, optional): A set of headers that will be added to + the default headers. Any headers that are added as additional + headers will override the default headers. + algorithm (str, optional): The algorithm to use for signing the + the claims. Defaults to HS256. + + Returns: + str: The string representation of the header, claims, and signature. + + Raises: + JWSError: If there is an error signing the token. + + Examples: + + >>> jws.sign({'a': 'b'}, 'secret', algorithm='HS256') + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' + + """ + + if algorithm not in ALGORITHMS.SUPPORTED: + raise JWSError('Algorithm %s not supported.' % algorithm) + + encoded_header = _encode_header(algorithm, additional_headers=headers) + encoded_payload = _encode_payload(payload) + signed_output = _sign_header_and_claims(encoded_header, encoded_payload, algorithm, key) + + return signed_output + + +def verify(token, key, algorithms, verify=True): + """Verifies a JWS string's signature. + + Args: + token (str): A signed JWS to be verified. + key (str or dict): A key to attempt to verify the payload with. Can be + individual JWK or JWK set. + algorithms (str or list): Valid algorithms that should be used to verify the JWS. + + Returns: + str: The str representation of the payload, assuming the signature is valid. + + Raises: + JWSError: If there is an exception verifying a token. + + Examples: + + >>> token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' + >>> jws.verify(token, 'secret', algorithms='HS256') + + """ + + header, payload, signing_input, signature = _load(token) + + if verify: + _verify_signature(signing_input, header, signature, key, algorithms) + + return payload + + +def get_unverified_header(token): + """Returns the decoded headers without verification of any kind. + + Args: + token (str): A signed JWS to decode the headers from. + + Returns: + dict: The dict representation of the token headers. + + Raises: + JWSError: If there is an exception decoding the token. + """ + header, claims, signing_input, signature = _load(token) + return header + + +def get_unverified_headers(token): + """Returns the decoded headers without verification of any kind. + + This is simply a wrapper of get_unverified_header() for backwards + compatibility. + + Args: + token (str): A signed JWS to decode the headers from. + + Returns: + dict: The dict representation of the token headers. + + Raises: + JWSError: If there is an exception decoding the token. + """ + return get_unverified_header(token) + + +def get_unverified_claims(token): + """Returns the decoded claims without verification of any kind. + + Args: + token (str): A signed JWS to decode the headers from. + + Returns: + str: The str representation of the token claims. + + Raises: + JWSError: If there is an exception decoding the token. + """ + header, claims, signing_input, signature = _load(token) + return claims + + +def _encode_header(algorithm, additional_headers=None): + header = { + "typ": "JWT", + "alg": algorithm + } + + if additional_headers: + header.update(additional_headers) + + json_header = json.dumps( + header, + separators=(',', ':'), + sort_keys=True, + ).encode('utf-8') + + return base64url_encode(json_header) + + +def _encode_payload(payload): + if isinstance(payload, Mapping): + try: + payload = json.dumps( + payload, + separators=(',', ':'), + ).encode('utf-8') + except ValueError: + pass + + return base64url_encode(payload) + + +def _sign_header_and_claims(encoded_header, encoded_claims, algorithm, key_data): + signing_input = b'.'.join([encoded_header, encoded_claims]) + try: + key = jwk.construct(key_data, algorithm) + signature = key.sign(signing_input) + except Exception as e: + raise JWSError(e) + + encoded_signature = base64url_encode(signature) + + encoded_string = b'.'.join([encoded_header, encoded_claims, encoded_signature]) + + return encoded_string.decode('utf-8') + + +def _load(jwt): + if isinstance(jwt, six.text_type): + jwt = jwt.encode('utf-8') + try: + signing_input, crypto_segment = jwt.rsplit(b'.', 1) + header_segment, claims_segment = signing_input.split(b'.', 1) + header_data = base64url_decode(header_segment) + except ValueError: + raise JWSError('Not enough segments') + except (TypeError, binascii.Error): + raise JWSError('Invalid header padding') + + try: + header = json.loads(header_data.decode('utf-8')) + except ValueError as e: + raise JWSError('Invalid header string: %s' % e) + + if not isinstance(header, Mapping): + raise JWSError('Invalid header string: must be a json object') + + try: + payload = base64url_decode(claims_segment) + except (TypeError, binascii.Error): + raise JWSError('Invalid payload padding') + + try: + signature = base64url_decode(crypto_segment) + except (TypeError, binascii.Error): + raise JWSError('Invalid crypto padding') + + return (header, payload, signing_input, signature) + + +def _sig_matches_keys(keys, signing_input, signature, alg): + for key in keys: + key = jwk.construct(key, alg) + try: + if key.verify(signing_input, signature): + return True + except Exception: + pass + return False + + +def _get_keys(key): + + try: + key = json.loads(key) + except Exception: + pass + + # JWK Set per RFC 7517 + if 'keys' in key: + return key['keys'] + + # Individual JWK per RFC 7517 + elif 'kty' in key: + return (key,) + + # Some other mapping. Firebase uses just dict of kid, cert pairs + elif isinstance(key, Mapping): + values = key.values() + if values: + return values + return (key,) + + # Iterable but not text or mapping => list- or tuple-like + elif (isinstance(key, Iterable) and + not (isinstance(key, six.string_types) or isinstance(key, Mapping))): + return key + + # Scalar value, wrap in tuple. + else: + return (key,) + + +def _verify_signature(signing_input, header, signature, key='', algorithms=None): + + alg = header.get('alg') + if not alg: + raise JWSError('No algorithm was specified in the JWS header.') + + if algorithms is not None and alg not in algorithms: + raise JWSError('The specified alg value is not allowed') + + keys = _get_keys(key) + try: + if not _sig_matches_keys(keys, signing_input, signature, alg): + raise JWSSignatureError() + except JWSSignatureError: + raise JWSError('Signature verification failed.') + except JWSError: + raise JWSError('Invalid or unsupported algorithm: %s' % alg) diff --git a/Lambdas/Websocket Authorizer/jose/jwt.py b/Lambdas/Websocket Authorizer/jose/jwt.py new file mode 100644 index 0000000..ee3b98d --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/jwt.py @@ -0,0 +1,507 @@ + +import json + +from calendar import timegm +try: + from collections.abc import Mapping # Python3 +except ImportError: + from collections import Mapping # Python2, will be deprecated in Python 3.8 +from datetime import datetime +from datetime import timedelta +from six import string_types + +from jose import jws + +from .exceptions import JWSError +from .exceptions import JWTClaimsError +from .exceptions import JWTError +from .exceptions import ExpiredSignatureError +from .constants import ALGORITHMS +from .utils import timedelta_total_seconds, calculate_at_hash + + +def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=None): + """Encodes a claims set and returns a JWT string. + + JWTs are JWS signed objects with a few reserved claims. + + Args: + claims (dict): A claims set to sign + key (str or dict): The key to use for signing the claim set. Can be + individual JWK or JWK set. + algorithm (str, optional): The algorithm to use for signing the + the claims. Defaults to HS256. + headers (dict, optional): A set of headers that will be added to + the default headers. Any headers that are added as additional + headers will override the default headers. + access_token (str, optional): If present, the 'at_hash' claim will + be calculated and added to the claims present in the 'claims' + parameter. + + Returns: + str: The string representation of the header, claims, and signature. + + Raises: + JWTError: If there is an error encoding the claims. + + Examples: + + >>> jwt.encode({'a': 'b'}, 'secret', algorithm='HS256') + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' + + """ + + for time_claim in ['exp', 'iat', 'nbf']: + + # Convert datetime to a intDate value in known time-format claims + if isinstance(claims.get(time_claim), datetime): + claims[time_claim] = timegm(claims[time_claim].utctimetuple()) + + if access_token: + claims['at_hash'] = calculate_at_hash(access_token, + ALGORITHMS.HASHES[algorithm]) + + return jws.sign(claims, key, headers=headers, algorithm=algorithm) + + +def decode(token, key, algorithms=None, options=None, audience=None, + issuer=None, subject=None, access_token=None): + """Verifies a JWT string's signature and validates reserved claims. + + Args: + token (str): A signed JWS to be verified. + key (str or dict): A key to attempt to verify the payload with. Can be + individual JWK or JWK set. + algorithms (str or list): Valid algorithms that should be used to verify the JWS. + audience (str): The intended audience of the token. If the "aud" claim is + included in the claim set, then the audience must be included and must equal + the provided claim. + issuer (str or iterable): Acceptable value(s) for the issuer of the token. + If the "iss" claim is included in the claim set, then the issuer must be + given and the claim in the token must be among the acceptable values. + subject (str): The subject of the token. If the "sub" claim is + included in the claim set, then the subject must be included and must equal + the provided claim. + access_token (str): An access token string. If the "at_hash" claim is included in the + claim set, then the access_token must be included, and it must match + the "at_hash" claim. + options (dict): A dictionary of options for skipping validation steps. + + defaults = { + 'verify_signature': True, + 'verify_aud': True, + 'verify_iat': True, + 'verify_exp': True, + 'verify_nbf': True, + 'verify_iss': True, + 'verify_sub': True, + 'verify_jti': True, + 'verify_at_hash': True, + 'require_aud': False, + 'require_iat': False, + 'require_exp': False, + 'require_nbf': False, + 'require_iss': False, + 'require_sub': False, + 'require_jti': False, + 'require_at_hash': False, + 'leeway': 0, + } + + Returns: + dict: The dict representation of the claims set, assuming the signature is valid + and all requested data validation passes. + + Raises: + JWTError: If the signature is invalid in any way. + ExpiredSignatureError: If the signature has expired. + JWTClaimsError: If any claim is invalid in any way. + + Examples: + + >>> payload = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' + >>> jwt.decode(payload, 'secret', algorithms='HS256') + + """ + + defaults = { + 'verify_signature': True, + 'verify_aud': True, + 'verify_iat': True, + 'verify_exp': True, + 'verify_nbf': True, + 'verify_iss': True, + 'verify_sub': True, + 'verify_jti': True, + 'verify_at_hash': True, + 'require_aud': False, + 'require_iat': False, + 'require_exp': False, + 'require_nbf': False, + 'require_iss': False, + 'require_sub': False, + 'require_jti': False, + 'require_at_hash': False, + 'leeway': 0, + } + + if options: + defaults.update(options) + + verify_signature = defaults.get('verify_signature', True) + + try: + payload = jws.verify(token, key, algorithms, verify=verify_signature) + except JWSError as e: + raise JWTError(e) + + # Needed for at_hash verification + algorithm = jws.get_unverified_header(token)['alg'] + + try: + claims = json.loads(payload.decode('utf-8')) + except ValueError as e: + raise JWTError('Invalid payload string: %s' % e) + + if not isinstance(claims, Mapping): + raise JWTError('Invalid payload string: must be a json object') + + _validate_claims(claims, audience=audience, issuer=issuer, + subject=subject, algorithm=algorithm, + access_token=access_token, + options=defaults) + + return claims + + +def get_unverified_header(token): + """Returns the decoded headers without verification of any kind. + + Args: + token (str): A signed JWT to decode the headers from. + + Returns: + dict: The dict representation of the token headers. + + Raises: + JWTError: If there is an exception decoding the token. + """ + try: + headers = jws.get_unverified_headers(token) + except Exception: + raise JWTError('Error decoding token headers.') + + return headers + + +def get_unverified_headers(token): + """Returns the decoded headers without verification of any kind. + + This is simply a wrapper of get_unverified_header() for backwards + compatibility. + + Args: + token (str): A signed JWT to decode the headers from. + + Returns: + dict: The dict representation of the token headers. + + Raises: + JWTError: If there is an exception decoding the token. + """ + return get_unverified_header(token) + + +def get_unverified_claims(token): + """Returns the decoded claims without verification of any kind. + + Args: + token (str): A signed JWT to decode the headers from. + + Returns: + dict: The dict representation of the token claims. + + Raises: + JWTError: If there is an exception decoding the token. + """ + try: + claims = jws.get_unverified_claims(token) + except Exception: + raise JWTError('Error decoding token claims.') + + try: + claims = json.loads(claims.decode('utf-8')) + except ValueError as e: + raise JWTError('Invalid claims string: %s' % e) + + if not isinstance(claims, Mapping): + raise JWTError('Invalid claims string: must be a json object') + + return claims + + +def _validate_iat(claims): + """Validates that the 'iat' claim is valid. + + The "iat" (issued at) claim identifies the time at which the JWT was + issued. This claim can be used to determine the age of the JWT. Its + value MUST be a number containing a NumericDate value. Use of this + claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + """ + + if 'iat' not in claims: + return + + try: + int(claims['iat']) + except ValueError: + raise JWTClaimsError('Issued At claim (iat) must be an integer.') + + +def _validate_nbf(claims, leeway=0): + """Validates that the 'nbf' claim is valid. + + The "nbf" (not before) claim identifies the time before which the JWT + MUST NOT be accepted for processing. The processing of the "nbf" + claim requires that the current date/time MUST be after or equal to + the not-before date/time listed in the "nbf" claim. Implementers MAY + provide for some small leeway, usually no more than a few minutes, to + account for clock skew. Its value MUST be a number containing a + NumericDate value. Use of this claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + leeway (int): The number of seconds of skew that is allowed. + """ + + if 'nbf' not in claims: + return + + try: + nbf = int(claims['nbf']) + except ValueError: + raise JWTClaimsError('Not Before claim (nbf) must be an integer.') + + now = timegm(datetime.utcnow().utctimetuple()) + + if nbf > (now + leeway): + raise JWTClaimsError('The token is not yet valid (nbf)') + + +def _validate_exp(claims, leeway=0): + """Validates that the 'exp' claim is valid. + + The "exp" (expiration time) claim identifies the expiration time on + or after which the JWT MUST NOT be accepted for processing. The + processing of the "exp" claim requires that the current date/time + MUST be before the expiration date/time listed in the "exp" claim. + Implementers MAY provide for some small leeway, usually no more than + a few minutes, to account for clock skew. Its value MUST be a number + containing a NumericDate value. Use of this claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + leeway (int): The number of seconds of skew that is allowed. + """ + + if 'exp' not in claims: + return + + try: + exp = int(claims['exp']) + except ValueError: + raise JWTClaimsError('Expiration Time claim (exp) must be an integer.') + + now = timegm(datetime.utcnow().utctimetuple()) + + if exp < (now - leeway): + raise ExpiredSignatureError('Signature has expired.') + + +def _validate_aud(claims, audience=None): + """Validates that the 'aud' claim is valid. + + The "aud" (audience) claim identifies the recipients that the JWT is + intended for. Each principal intended to process the JWT MUST + identify itself with a value in the audience claim. If the principal + processing the claim does not identify itself with a value in the + "aud" claim when this claim is present, then the JWT MUST be + rejected. In the general case, the "aud" value is an array of case- + sensitive strings, each containing a StringOrURI value. In the + special case when the JWT has one audience, the "aud" value MAY be a + single case-sensitive string containing a StringOrURI value. The + interpretation of audience values is generally application specific. + Use of this claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + audience (str): The audience that is verifying the token. + """ + + if 'aud' not in claims: + # if audience: + # raise JWTError('Audience claim expected, but not in claims') + return + + audience_claims = claims['aud'] + if isinstance(audience_claims, string_types): + audience_claims = [audience_claims] + if not isinstance(audience_claims, list): + raise JWTClaimsError('Invalid claim format in token') + if any(not isinstance(c, string_types) for c in audience_claims): + raise JWTClaimsError('Invalid claim format in token') + if audience not in audience_claims: + raise JWTClaimsError('Invalid audience') + + +def _validate_iss(claims, issuer=None): + """Validates that the 'iss' claim is valid. + + The "iss" (issuer) claim identifies the principal that issued the + JWT. The processing of this claim is generally application specific. + The "iss" value is a case-sensitive string containing a StringOrURI + value. Use of this claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + issuer (str or iterable): Acceptable value(s) for the issuer that + signed the token. + """ + + if issuer is not None: + if isinstance(issuer, string_types): + issuer = (issuer,) + if claims.get('iss') not in issuer: + raise JWTClaimsError('Invalid issuer') + + +def _validate_sub(claims, subject=None): + """Validates that the 'sub' claim is valid. + + The "sub" (subject) claim identifies the principal that is the + subject of the JWT. The claims in a JWT are normally statements + about the subject. The subject value MUST either be scoped to be + locally unique in the context of the issuer or be globally unique. + The processing of this claim is generally application specific. The + "sub" value is a case-sensitive string containing a StringOrURI + value. Use of this claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + subject (str): The subject of the token. + """ + + if 'sub' not in claims: + return + + if not isinstance(claims['sub'], string_types): + raise JWTClaimsError('Subject must be a string.') + + if subject is not None: + if claims.get('sub') != subject: + raise JWTClaimsError('Invalid subject') + + +def _validate_jti(claims): + """Validates that the 'jti' claim is valid. + + The "jti" (JWT ID) claim provides a unique identifier for the JWT. + The identifier value MUST be assigned in a manner that ensures that + there is a negligible probability that the same value will be + accidentally assigned to a different data object; if the application + uses multiple issuers, collisions MUST be prevented among values + produced by different issuers as well. The "jti" claim can be used + to prevent the JWT from being replayed. The "jti" value is a case- + sensitive string. Use of this claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + """ + if 'jti' not in claims: + return + + if not isinstance(claims['jti'], string_types): + raise JWTClaimsError('JWT ID must be a string.') + + +def _validate_at_hash(claims, access_token, algorithm): + """ + Validates that the 'at_hash' is valid. + + Its value is the base64url encoding of the left-most half of the hash + of the octets of the ASCII representation of the access_token value, + where the hash algorithm used is the hash algorithm used in the alg + Header Parameter of the ID Token's JOSE Header. For instance, if the + alg is RS256, hash the access_token value with SHA-256, then take the + left-most 128 bits and base64url encode them. The at_hash value is a + case sensitive string. Use of this claim is OPTIONAL. + + Args: + claims (dict): The claims dictionary to validate. + access_token (str): The access token returned by the OpenID Provider. + algorithm (str): The algorithm used to sign the JWT, as specified by + the token headers. + """ + if 'at_hash' not in claims: + return + + if not access_token: + msg = 'No access_token provided to compare against at_hash claim.' + raise JWTClaimsError(msg) + + try: + expected_hash = calculate_at_hash(access_token, + ALGORITHMS.HASHES[algorithm]) + except (TypeError, ValueError): + msg = 'Unable to calculate at_hash to verify against token claims.' + raise JWTClaimsError(msg) + + if claims['at_hash'] != expected_hash: + raise JWTClaimsError('at_hash claim does not match access_token.') + + +def _validate_claims(claims, audience=None, issuer=None, subject=None, + algorithm=None, access_token=None, options=None): + + leeway = options.get('leeway', 0) + + if isinstance(leeway, timedelta): + leeway = timedelta_total_seconds(leeway) + + for require_claim in [ + e[len("require_"):] for e in options.keys() if e.startswith("require_") and options[e] + ]: + if require_claim not in claims: + raise JWTError('missing required key "%s" among claims' % require_claim) + else: + options['verify_' + require_claim] = True # override verify when required + + if not isinstance(audience, (string_types, type(None))): + raise JWTError('audience must be a string or None') + + if options.get('verify_iat'): + _validate_iat(claims) + + if options.get('verify_nbf'): + _validate_nbf(claims, leeway=leeway) + + if options.get('verify_exp'): + _validate_exp(claims, leeway=leeway) + + if options.get('verify_aud'): + _validate_aud(claims, audience=audience) + + if options.get('verify_iss'): + _validate_iss(claims, issuer=issuer) + + if options.get('verify_sub'): + _validate_sub(claims, subject=subject) + + if options.get('verify_jti'): + _validate_jti(claims) + + if options.get('verify_at_hash'): + _validate_at_hash(claims, access_token, algorithm) diff --git a/Lambdas/Websocket Authorizer/jose/utils.py b/Lambdas/Websocket Authorizer/jose/utils.py new file mode 100644 index 0000000..2b98472 --- /dev/null +++ b/Lambdas/Websocket Authorizer/jose/utils.py @@ -0,0 +1,134 @@ + +import base64 +import hmac +import six +import struct +import sys + +if sys.version_info > (3,): + # Deal with integer compatibilities between Python 2 and 3. + # Using `from builtins import int` is not supported on AppEngine. + long = int + + +# Piggyback of the backends implementation of the function that converts a long +# to a bytes stream. Some plumbing is necessary to have the signatures match. +try: + from Crypto.Util.number import long_to_bytes +except ImportError: + try: + from cryptography.utils import int_to_bytes as _long_to_bytes + + def long_to_bytes(n, blocksize=0): + return _long_to_bytes(n, blocksize or None) + + except ImportError: + from ecdsa.ecdsa import int_to_string as _long_to_bytes + + def long_to_bytes(n, blocksize=0): + ret = _long_to_bytes(n) + if blocksize == 0: + return ret + else: + assert len(ret) <= blocksize + padding = blocksize - len(ret) + return b'\x00' * padding + ret + + +def long_to_base64(data, size=0): + return base64.urlsafe_b64encode(long_to_bytes(data, size)).strip(b'=') + + +def int_arr_to_long(arr): + return long(''.join(["%02x" % byte for byte in arr]), 16) + + +def base64_to_long(data): + if isinstance(data, six.text_type): + data = data.encode("ascii") + + # urlsafe_b64decode will happily convert b64encoded data + _d = base64.urlsafe_b64decode(bytes(data) + b'==') + return int_arr_to_long(struct.unpack('%sB' % len(_d), _d)) + + +def calculate_at_hash(access_token, hash_alg): + """Helper method for calculating an access token + hash, as described in http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken + + Its value is the base64url encoding of the left-most half of the hash of the octets + of the ASCII representation of the access_token value, where the hash algorithm + used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE + Header. For instance, if the alg is RS256, hash the access_token value with SHA-256, + then take the left-most 128 bits and base64url encode them. The at_hash value is a + case sensitive string. + + Args: + access_token (str): An access token string. + hash_alg (callable): A callable returning a hash object, e.g. hashlib.sha256 + + """ + hash_digest = hash_alg(access_token.encode('utf-8')).digest() + cut_at = int(len(hash_digest) / 2) + truncated = hash_digest[:cut_at] + at_hash = base64url_encode(truncated) + return at_hash.decode('utf-8') + + +def base64url_decode(input): + """Helper method to base64url_decode a string. + + Args: + input (str): A base64url_encoded string to decode. + + """ + rem = len(input) % 4 + + if rem > 0: + input += b'=' * (4 - rem) + + return base64.urlsafe_b64decode(input) + + +def base64url_encode(input): + """Helper method to base64url_encode a string. + + Args: + input (str): A base64url_encoded string to encode. + + """ + return base64.urlsafe_b64encode(input).replace(b'=', b'') + + +def timedelta_total_seconds(delta): + """Helper method to determine the total number of seconds + from a timedelta. + + Args: + delta (timedelta): A timedelta to convert to seconds. + """ + return delta.days * 24 * 60 * 60 + delta.seconds + + +def constant_time_string_compare(a, b): + """Helper for comparing string in constant time, independent + of the python version being used. + + Args: + a (str): A string to compare + b (str): A string to compare + """ + + try: + return hmac.compare_digest(a, b) + except AttributeError: + + if len(a) != len(b): + return False + + result = 0 + + for x, y in zip(a, b): + result |= ord(x) ^ ord(y) + + return result == 0 diff --git a/Lambdas/Websocket Authorizer/lambda_function.py b/Lambdas/Websocket Authorizer/lambda_function.py new file mode 100644 index 0000000..3b0a9ea --- /dev/null +++ b/Lambdas/Websocket Authorizer/lambda_function.py @@ -0,0 +1,82 @@ +import json +import time +import urllib.request +from jose import jwk, jwt +from jose.utils import base64url_decode +import logging + +logging.basicConfig(format='%(levelname)s: %(asctime)s: %(message)s') +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +region = 'us-east-1' +userpool_id = 'us-east-1_XcUWWJXMT' +app_client_id = 'ms2jhuludm93g9qfpuio8m9k6' +keys_url = 'https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json'.format(region, userpool_id) +# instead of re-downloading the public keys every time +# we download them only on cold start +# https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/ +with urllib.request.urlopen(keys_url) as f: + response = f.read() +keys = json.loads(response.decode('utf-8'))['keys'] + +def lambda_handler(event, context): + #logger.info(event) + token = event['queryStringParameters']['token'] + # get the kid from the headers prior to verification + headers = jwt.get_unverified_headers(token) + kid = headers['kid'] + # search for the kid in the downloaded public keys + key_index = -1 + for i in range(len(keys)): + if kid == keys[i]['kid']: + key_index = i + break + if key_index == -1: + print('Public key not found in jwks.json') + return False + # construct the public key + public_key = jwk.construct(keys[key_index]) + # get the last two sections of the token, + # message and signature (encoded in base64) + message, encoded_signature = str(token).rsplit('.', 1) + # decode the signature + decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) + # verify the signature + if not public_key.verify(message.encode("utf8"), decoded_signature): + print('Signature verification failed') + return False + print('Signature successfully verified') + # since we passed the verification, we can now safely + # use the unverified claims + claims = jwt.get_unverified_claims(token) + # additionally we can verify the token expiration + if time.time() > claims['exp']: + print('Token is expired') + return False + # and the Audience (use claims['client_id'] if verifying an access token) + if claims['client_id'] != app_client_id: + print('Token was not issued for this audience') + return False + # now we can use the claims + return generateAllow("user", event["methodArn"]) #claims + +def generateAllow(principleID, resource): + return generatePolicy(principleID,'Allow', resource) +def generateDeny(principleID, resource): + return generatePolicy(principleID, 'Deny', resource) +def generatePolicy(principleID, effect, resource): + authResponse = {} + authResponse["principleId"] = principleID + if (effect and resource): + policyDocument = {} + policyDocument["Version"] = '2012-10-17' + policyDocument["Statement"] = [] + statementOne = {} + statementOne["Action"] = 'execute-api:Invoke' + statementOne["Effect"] = effect + statementOne["Resource"] = resource + policyDocument["Statement"].append(statementOne) + authResponse["policyDocument"] = policyDocument + + return authResponse \ No newline at end of file diff --git a/Lambdas/Websocket Authorizer/lambda_function.zip b/Lambdas/Websocket Authorizer/lambda_function.zip new file mode 100644 index 0000000000000000000000000000000000000000..0d2ad683f05b52fc3a4363444fc9e7fab4181303 GIT binary patch literal 184410 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 sCuW>Znvdph;BlWsp*x^(Kxw_2|3 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

2UcE3z+T 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�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 literal 0 HcmV?d00001 diff --git a/Lambdas/Websocket Authorizer/pyasn1/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/__init__.py new file mode 100644 index 0000000..92838e0 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/__init__.py @@ -0,0 +1,7 @@ +import sys + +# https://www.python.org/dev/peps/pep-0396/ +__version__ = '0.4.7' + +if sys.version_info[:2] < (2, 4): + raise RuntimeError('PyASN1 requires Python 2.4 or later') diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/codec/__init__.py new file mode 100644 index 0000000..8c3066b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/ber/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/__init__.py new file mode 100644 index 0000000..8c3066b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/ber/decoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/decoder.py new file mode 100644 index 0000000..5759ab8 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/decoder.py @@ -0,0 +1,1654 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import debug +from pyasn1 import error +from pyasn1.codec.ber import eoo +from pyasn1.compat.integer import from_bytes +from pyasn1.compat.octets import oct2int, octs2ints, ints2octs, null +from pyasn1.type import base +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import tagmap +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['decode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_DECODER) + +noValue = base.noValue + + +class AbstractDecoder(object): + protoComponent = None + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + raise error.PyAsn1Error('Decoder not implemented for %s' % (tagSet,)) + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,)) + + +class AbstractSimpleDecoder(AbstractDecoder): + @staticmethod + def substrateCollector(asn1Object, substrate, length): + return substrate[:length], substrate[length:] + + def _createComponent(self, asn1Spec, tagSet, value, **options): + if options.get('native'): + return value + elif asn1Spec is None: + return self.protoComponent.clone(value, tagSet=tagSet) + elif value is noValue: + return asn1Spec + else: + return asn1Spec.clone(value) + + +class ExplicitTagDecoder(AbstractSimpleDecoder): + protoComponent = univ.Any('') + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun: + return substrateFun( + self._createComponent(asn1Spec, tagSet, '', **options), + substrate, length + ) + + head, tail = substrate[:length], substrate[length:] + + value, _ = decodeFun(head, asn1Spec, tagSet, length, **options) + + if LOG: + LOG('explicit tag container carries %d octets of trailing payload ' + '(will be lost!): %s' % (len(_), debug.hexdump(_))) + + return value, tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun: + return substrateFun( + self._createComponent(asn1Spec, tagSet, '', **options), + substrate, length + ) + + value, substrate = decodeFun(substrate, asn1Spec, tagSet, length, **options) + + eooMarker, substrate = decodeFun(substrate, allowEoo=True, **options) + + if eooMarker is eoo.endOfOctets: + return value, substrate + else: + raise error.PyAsn1Error('Missing end-of-octets terminator') + + +explicitTagDecoder = ExplicitTagDecoder() + + +class IntegerDecoder(AbstractSimpleDecoder): + protoComponent = univ.Integer(0) + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + head, tail = substrate[:length], substrate[length:] + + if not head: + return self._createComponent(asn1Spec, tagSet, 0, **options), tail + + value = from_bytes(head, signed=True) + + return self._createComponent(asn1Spec, tagSet, value, **options), tail + + +class BooleanDecoder(IntegerDecoder): + protoComponent = univ.Boolean(0) + + def _createComponent(self, asn1Spec, tagSet, value, **options): + return IntegerDecoder._createComponent( + self, asn1Spec, tagSet, value and 1 or 0, **options) + + +class BitStringDecoder(AbstractSimpleDecoder): + protoComponent = univ.BitString(()) + supportConstructedForm = True + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + head, tail = substrate[:length], substrate[length:] + + if substrateFun: + return substrateFun(self._createComponent( + asn1Spec, tagSet, noValue, **options), substrate, length) + + if not head: + raise error.PyAsn1Error('Empty BIT STRING substrate') + + if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? + + trailingBits = oct2int(head[0]) + if trailingBits > 7: + raise error.PyAsn1Error( + 'Trailing bits overflow %s' % trailingBits + ) + + value = self.protoComponent.fromOctetString( + head[1:], internalFormat=True, padding=trailingBits) + + return self._createComponent(asn1Spec, tagSet, value, **options), tail + + if not self.supportConstructedForm: + raise error.PyAsn1Error('Constructed encoding form prohibited ' + 'at %s' % self.__class__.__name__) + + if LOG: + LOG('assembling constructed serialization') + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + bitString = self.protoComponent.fromOctetString(null, internalFormat=True) + + while head: + component, head = decodeFun(head, self.protoComponent, + substrateFun=substrateFun, **options) + + trailingBits = oct2int(component[0]) + if trailingBits > 7: + raise error.PyAsn1Error( + 'Trailing bits overflow %s' % trailingBits + ) + + bitString = self.protoComponent.fromOctetString( + component[1:], internalFormat=True, + prepend=bitString, padding=trailingBits + ) + + return self._createComponent(asn1Spec, tagSet, bitString, **options), tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if substrateFun: + return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options), substrate, length) + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + bitString = self.protoComponent.fromOctetString(null, internalFormat=True) + + while substrate: + component, substrate = decodeFun(substrate, self.protoComponent, + substrateFun=substrateFun, + allowEoo=True, **options) + if component is eoo.endOfOctets: + break + + trailingBits = oct2int(component[0]) + if trailingBits > 7: + raise error.PyAsn1Error( + 'Trailing bits overflow %s' % trailingBits + ) + + bitString = self.protoComponent.fromOctetString( + component[1:], internalFormat=True, + prepend=bitString, padding=trailingBits + ) + + else: + raise error.SubstrateUnderrunError('No EOO seen before substrate ends') + + return self._createComponent(asn1Spec, tagSet, bitString, **options), substrate + + +class OctetStringDecoder(AbstractSimpleDecoder): + protoComponent = univ.OctetString('') + supportConstructedForm = True + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + head, tail = substrate[:length], substrate[length:] + + if substrateFun: + return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options), + substrate, length) + + if tagSet[0].tagFormat == tag.tagFormatSimple: # XXX what tag to check? + return self._createComponent(asn1Spec, tagSet, head, **options), tail + + if not self.supportConstructedForm: + raise error.PyAsn1Error('Constructed encoding form prohibited at %s' % self.__class__.__name__) + + if LOG: + LOG('assembling constructed serialization') + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + header = null + + while head: + component, head = decodeFun(head, self.protoComponent, + substrateFun=substrateFun, + **options) + header += component + + return self._createComponent(asn1Spec, tagSet, header, **options), tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if substrateFun and substrateFun is not self.substrateCollector: + asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options) + return substrateFun(asn1Object, substrate, length) + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + header = null + + while substrate: + component, substrate = decodeFun(substrate, + self.protoComponent, + substrateFun=substrateFun, + allowEoo=True, **options) + if component is eoo.endOfOctets: + break + + header += component + + else: + raise error.SubstrateUnderrunError( + 'No EOO seen before substrate ends' + ) + + return self._createComponent(asn1Spec, tagSet, header, **options), substrate + + +class NullDecoder(AbstractSimpleDecoder): + protoComponent = univ.Null('') + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + head, tail = substrate[:length], substrate[length:] + + component = self._createComponent(asn1Spec, tagSet, '', **options) + + if head: + raise error.PyAsn1Error('Unexpected %d-octet substrate for Null' % length) + + return component, tail + + +class ObjectIdentifierDecoder(AbstractSimpleDecoder): + protoComponent = univ.ObjectIdentifier(()) + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + head, tail = substrate[:length], substrate[length:] + if not head: + raise error.PyAsn1Error('Empty substrate') + + head = octs2ints(head) + + oid = () + index = 0 + substrateLen = len(head) + while index < substrateLen: + subId = head[index] + index += 1 + if subId < 128: + oid += (subId,) + elif subId > 128: + # Construct subid from a number of octets + nextSubId = subId + subId = 0 + while nextSubId >= 128: + subId = (subId << 7) + (nextSubId & 0x7F) + if index >= substrateLen: + raise error.SubstrateUnderrunError( + 'Short substrate for sub-OID past %s' % (oid,) + ) + nextSubId = head[index] + index += 1 + oid += ((subId << 7) + nextSubId,) + elif subId == 128: + # ASN.1 spec forbids leading zeros (0x80) in OID + # encoding, tolerating it opens a vulnerability. See + # https://www.esat.kuleuven.be/cosic/publications/article-1432.pdf + # page 7 + raise error.PyAsn1Error('Invalid octet 0x80 in OID encoding') + + # Decode two leading arcs + if 0 <= oid[0] <= 39: + oid = (0,) + oid + elif 40 <= oid[0] <= 79: + oid = (1, oid[0] - 40) + oid[1:] + elif oid[0] >= 80: + oid = (2, oid[0] - 80) + oid[1:] + else: + raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0]) + + return self._createComponent(asn1Spec, tagSet, oid, **options), tail + + +class RealDecoder(AbstractSimpleDecoder): + protoComponent = univ.Real() + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatSimple: + raise error.PyAsn1Error('Simple tag format expected') + + head, tail = substrate[:length], substrate[length:] + + if not head: + return self._createComponent(asn1Spec, tagSet, 0.0, **options), tail + + fo = oct2int(head[0]) + head = head[1:] + if fo & 0x80: # binary encoding + if not head: + raise error.PyAsn1Error("Incomplete floating-point value") + + if LOG: + LOG('decoding binary encoded REAL') + + n = (fo & 0x03) + 1 + + if n == 4: + n = oct2int(head[0]) + head = head[1:] + + eo, head = head[:n], head[n:] + + if not eo or not head: + raise error.PyAsn1Error('Real exponent screwed') + + e = oct2int(eo[0]) & 0x80 and -1 or 0 + + while eo: # exponent + e <<= 8 + e |= oct2int(eo[0]) + eo = eo[1:] + + b = fo >> 4 & 0x03 # base bits + + if b > 2: + raise error.PyAsn1Error('Illegal Real base') + + if b == 1: # encbase = 8 + e *= 3 + + elif b == 2: # encbase = 16 + e *= 4 + p = 0 + + while head: # value + p <<= 8 + p |= oct2int(head[0]) + head = head[1:] + + if fo & 0x40: # sign bit + p = -p + + sf = fo >> 2 & 0x03 # scale bits + p *= 2 ** sf + value = (p, 2, e) + + elif fo & 0x40: # infinite value + if LOG: + LOG('decoding infinite REAL') + + value = fo & 0x01 and '-inf' or 'inf' + + elif fo & 0xc0 == 0: # character encoding + if not head: + raise error.PyAsn1Error("Incomplete floating-point value") + + if LOG: + LOG('decoding character encoded REAL') + + try: + if fo & 0x3 == 0x1: # NR1 + value = (int(head), 10, 0) + + elif fo & 0x3 == 0x2: # NR2 + value = float(head) + + elif fo & 0x3 == 0x3: # NR3 + value = float(head) + + else: + raise error.SubstrateUnderrunError( + 'Unknown NR (tag %s)' % fo + ) + + except ValueError: + raise error.SubstrateUnderrunError( + 'Bad character Real syntax' + ) + + else: + raise error.SubstrateUnderrunError( + 'Unknown encoding (tag %s)' % fo + ) + + return self._createComponent(asn1Spec, tagSet, value, **options), tail + + +class AbstractConstructedDecoder(AbstractDecoder): + protoComponent = None + + +class UniversalConstructedTypeDecoder(AbstractConstructedDecoder): + protoRecordComponent = None + protoSequenceComponent = None + + def _getComponentTagMap(self, asn1Object, idx): + raise NotImplementedError() + + def _getComponentPositionByType(self, asn1Object, tagSet, idx): + raise NotImplementedError() + + def _decodeComponents(self, substrate, tagSet=None, decodeFun=None, **options): + components = [] + componentTypes = set() + + while substrate: + component, substrate = decodeFun(substrate, **options) + if component is eoo.endOfOctets: + break + + components.append(component) + componentTypes.add(component.tagSet) + + # Now we have to guess is it SEQUENCE/SET or SEQUENCE OF/SET OF + # The heuristics is: + # * 1+ components of different types -> likely SEQUENCE/SET + # * otherwise -> likely SEQUENCE OF/SET OF + if len(componentTypes) > 1: + protoComponent = self.protoRecordComponent + + else: + protoComponent = self.protoSequenceComponent + + asn1Object = protoComponent.clone( + # construct tagSet from base tag from prototype ASN.1 object + # and additional tags recovered from the substrate + tagSet=tag.TagSet(protoComponent.tagSet.baseTag, *tagSet.superTags) + ) + + if LOG: + LOG('guessed %r container type (pass `asn1Spec` to guide the ' + 'decoder)' % asn1Object) + + for idx, component in enumerate(components): + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + return asn1Object, substrate + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatConstructed: + raise error.PyAsn1Error('Constructed tag format expected') + + head, tail = substrate[:length], substrate[length:] + + if substrateFun is not None: + if asn1Spec is not None: + asn1Object = asn1Spec.clone() + + elif self.protoComponent is not None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + + else: + asn1Object = self.protoRecordComponent, self.protoSequenceComponent + + return substrateFun(asn1Object, substrate, length) + + if asn1Spec is None: + asn1Object, trailing = self._decodeComponents( + head, tagSet=tagSet, decodeFun=decodeFun, **options + ) + + if trailing: + if LOG: + LOG('Unused trailing %d octets encountered: %s' % ( + len(trailing), debug.hexdump(trailing))) + + return asn1Object, tail + + asn1Object = asn1Spec.clone() + asn1Object.clear() + + if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId): + + namedTypes = asn1Spec.componentType + + isSetType = asn1Spec.typeId == univ.Set.typeId + isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault + + if LOG: + LOG('decoding %sdeterministic %s type %r chosen by type ID' % ( + not isDeterministic and 'non-' or '', isSetType and 'SET' or '', + asn1Spec)) + + seenIndices = set() + idx = 0 + while head: + if not namedTypes: + componentType = None + + elif isSetType: + componentType = namedTypes.tagMapUnique + + else: + try: + if isDeterministic: + componentType = namedTypes[idx].asn1Object + + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + componentType = namedTypes.getTagMapNearPosition(idx) + + else: + componentType = namedTypes[idx].asn1Object + + except IndexError: + raise error.PyAsn1Error( + 'Excessive components decoded at %r' % (asn1Spec,) + ) + + component, head = decodeFun(head, componentType, **options) + + if not isDeterministic and namedTypes: + if isSetType: + idx = namedTypes.getPositionByType(component.effectiveTagSet) + + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + idx = namedTypes.getPositionNearType(component.effectiveTagSet, idx) + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + seenIndices.add(idx) + idx += 1 + + if LOG: + LOG('seen component indices %s' % seenIndices) + + if namedTypes: + if not namedTypes.requiredComponents.issubset(seenIndices): + raise error.PyAsn1Error( + 'ASN.1 object %s has uninitialized ' + 'components' % asn1Object.__class__.__name__) + + if namedTypes.hasOpenTypes: + + openTypes = options.get('openTypes', {}) + + if LOG: + LOG('using open types map: %r' % openTypes) + + if openTypes or options.get('decodeOpenTypes', False): + + for idx, namedType in enumerate(namedTypes.namedTypes): + if not namedType.openType: + continue + + if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue: + continue + + governingValue = asn1Object.getComponentByName( + namedType.openType.name + ) + + try: + openType = openTypes[governingValue] + + except KeyError: + + try: + openType = namedType.openType[governingValue] + + except KeyError: + if LOG: + LOG('failed to resolve open type by governing ' + 'value %r' % (governingValue,)) + continue + + if LOG: + LOG('resolved open type %r by governing ' + 'value %r' % (openType, governingValue)) + + containerValue = asn1Object.getComponentByPosition(idx) + + if containerValue.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + for pos, containerElement in enumerate( + containerValue): + + component, rest = decodeFun( + containerValue[pos].asOctets(), + asn1Spec=openType, **options + ) + + containerValue[pos] = component + + else: + component, rest = decodeFun( + asn1Object.getComponentByPosition(idx).asOctets(), + asn1Spec=openType, **options + ) + + asn1Object.setComponentByPosition(idx, component) + + else: + inconsistency = asn1Object.isInconsistent + if inconsistency: + raise inconsistency + + else: + asn1Object = asn1Spec.clone() + asn1Object.clear() + + componentType = asn1Spec.componentType + + if LOG: + LOG('decoding type %r chosen by given `asn1Spec`' % componentType) + + idx = 0 + + while head: + component, head = decodeFun(head, componentType, **options) + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + idx += 1 + + return asn1Object, tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if tagSet[0].tagFormat != tag.tagFormatConstructed: + raise error.PyAsn1Error('Constructed tag format expected') + + if substrateFun is not None: + if asn1Spec is not None: + asn1Object = asn1Spec.clone() + + elif self.protoComponent is not None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + + else: + asn1Object = self.protoRecordComponent, self.protoSequenceComponent + + return substrateFun(asn1Object, substrate, length) + + if asn1Spec is None: + return self._decodeComponents( + substrate, tagSet=tagSet, decodeFun=decodeFun, + **dict(options, allowEoo=True) + ) + + asn1Object = asn1Spec.clone() + asn1Object.clear() + + if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId): + + namedTypes = asn1Object.componentType + + isSetType = asn1Object.typeId == univ.Set.typeId + isDeterministic = not isSetType and not namedTypes.hasOptionalOrDefault + + if LOG: + LOG('decoding %sdeterministic %s type %r chosen by type ID' % ( + not isDeterministic and 'non-' or '', isSetType and 'SET' or '', + asn1Spec)) + + seenIndices = set() + idx = 0 + while substrate: + if len(namedTypes) <= idx: + asn1Spec = None + + elif isSetType: + asn1Spec = namedTypes.tagMapUnique + + else: + try: + if isDeterministic: + asn1Spec = namedTypes[idx].asn1Object + + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + asn1Spec = namedTypes.getTagMapNearPosition(idx) + + else: + asn1Spec = namedTypes[idx].asn1Object + + except IndexError: + raise error.PyAsn1Error( + 'Excessive components decoded at %r' % (asn1Object,) + ) + + component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True, **options) + if component is eoo.endOfOctets: + break + + if not isDeterministic and namedTypes: + if isSetType: + idx = namedTypes.getPositionByType(component.effectiveTagSet) + elif namedTypes[idx].isOptional or namedTypes[idx].isDefaulted: + idx = namedTypes.getPositionNearType(component.effectiveTagSet, idx) + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + seenIndices.add(idx) + idx += 1 + + else: + raise error.SubstrateUnderrunError( + 'No EOO seen before substrate ends' + ) + + if LOG: + LOG('seen component indices %s' % seenIndices) + + if namedTypes: + if not namedTypes.requiredComponents.issubset(seenIndices): + raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__) + + if namedTypes.hasOpenTypes: + + openTypes = options.get('openTypes', {}) + + if LOG: + LOG('using open types map: %r' % openTypes) + + if openTypes or options.get('decodeOpenTypes', False): + + for idx, namedType in enumerate(namedTypes.namedTypes): + if not namedType.openType: + continue + + if namedType.isOptional and not asn1Object.getComponentByPosition(idx).isValue: + continue + + governingValue = asn1Object.getComponentByName( + namedType.openType.name + ) + + try: + openType = openTypes[governingValue] + + except KeyError: + + try: + openType = namedType.openType[governingValue] + + except KeyError: + if LOG: + LOG('failed to resolve open type by governing ' + 'value %r' % (governingValue,)) + continue + + if LOG: + LOG('resolved open type %r by governing ' + 'value %r' % (openType, governingValue)) + + containerValue = asn1Object.getComponentByPosition(idx) + + if containerValue.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + for pos, containerElement in enumerate( + containerValue): + + component, rest = decodeFun( + containerValue[pos].asOctets(), + asn1Spec=openType, **dict(options, allowEoo=True) + ) + + containerValue[pos] = component + + else: + component, rest = decodeFun( + asn1Object.getComponentByPosition(idx).asOctets(), + asn1Spec=openType, **dict(options, allowEoo=True) + ) + + if component is not eoo.endOfOctets: + asn1Object.setComponentByPosition(idx, component) + + else: + inconsistency = asn1Object.isInconsistent + if inconsistency: + raise inconsistency + + else: + asn1Object = asn1Spec.clone() + asn1Object.clear() + + componentType = asn1Spec.componentType + + if LOG: + LOG('decoding type %r chosen by given `asn1Spec`' % componentType) + + idx = 0 + + while substrate: + component, substrate = decodeFun(substrate, componentType, allowEoo=True, **options) + + if component is eoo.endOfOctets: + break + + asn1Object.setComponentByPosition( + idx, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False + ) + + idx += 1 + + else: + raise error.SubstrateUnderrunError( + 'No EOO seen before substrate ends' + ) + + return asn1Object, substrate + + +class SequenceOrSequenceOfDecoder(UniversalConstructedTypeDecoder): + protoRecordComponent = univ.Sequence() + protoSequenceComponent = univ.SequenceOf() + + +class SequenceDecoder(SequenceOrSequenceOfDecoder): + protoComponent = univ.Sequence() + + +class SequenceOfDecoder(SequenceOrSequenceOfDecoder): + protoComponent = univ.SequenceOf() + + +class SetOrSetOfDecoder(UniversalConstructedTypeDecoder): + protoRecordComponent = univ.Set() + protoSequenceComponent = univ.SetOf() + + +class SetDecoder(SetOrSetOfDecoder): + protoComponent = univ.Set() + + + +class SetOfDecoder(SetOrSetOfDecoder): + protoComponent = univ.SetOf() + + +class ChoiceDecoder(AbstractConstructedDecoder): + protoComponent = univ.Choice() + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + head, tail = substrate[:length], substrate[length:] + + if asn1Spec is None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + + else: + asn1Object = asn1Spec.clone() + + if substrateFun: + return substrateFun(asn1Object, substrate, length) + + if asn1Object.tagSet == tagSet: + if LOG: + LOG('decoding %s as explicitly tagged CHOICE' % (tagSet,)) + + component, head = decodeFun( + head, asn1Object.componentTagMap, **options + ) + + else: + if LOG: + LOG('decoding %s as untagged CHOICE' % (tagSet,)) + + component, head = decodeFun( + head, asn1Object.componentTagMap, + tagSet, length, state, **options + ) + + effectiveTagSet = component.effectiveTagSet + + if LOG: + LOG('decoded component %s, effective tag set %s' % (component, effectiveTagSet)) + + asn1Object.setComponentByType( + effectiveTagSet, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False, + innerFlag=False + ) + + return asn1Object, tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + asn1Object = self.protoComponent.clone(tagSet=tagSet) + else: + asn1Object = asn1Spec.clone() + + if substrateFun: + return substrateFun(asn1Object, substrate, length) + + if asn1Object.tagSet == tagSet: + if LOG: + LOG('decoding %s as explicitly tagged CHOICE' % (tagSet,)) + + component, substrate = decodeFun( + substrate, asn1Object.componentType.tagMapUnique, **options + ) + + # eat up EOO marker + eooMarker, substrate = decodeFun( + substrate, allowEoo=True, **options + ) + + if eooMarker is not eoo.endOfOctets: + raise error.PyAsn1Error('No EOO seen before substrate ends') + + else: + if LOG: + LOG('decoding %s as untagged CHOICE' % (tagSet,)) + + component, substrate = decodeFun( + substrate, asn1Object.componentType.tagMapUnique, + tagSet, length, state, **options + ) + + effectiveTagSet = component.effectiveTagSet + + if LOG: + LOG('decoded component %s, effective tag set %s' % (component, effectiveTagSet)) + + asn1Object.setComponentByType( + effectiveTagSet, component, + verifyConstraints=False, + matchTags=False, matchConstraints=False, + innerFlag=False + ) + + return asn1Object, substrate + + +class AnyDecoder(AbstractSimpleDecoder): + protoComponent = univ.Any() + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + isUntagged = True + + elif asn1Spec.__class__ is tagmap.TagMap: + isUntagged = tagSet not in asn1Spec.tagMap + + else: + isUntagged = tagSet != asn1Spec.tagSet + + if isUntagged: + fullSubstrate = options['fullSubstrate'] + + # untagged Any container, recover inner header substrate + length += len(fullSubstrate) - len(substrate) + substrate = fullSubstrate + + if LOG: + LOG('decoding as untagged ANY, substrate %s' % debug.hexdump(substrate)) + + if substrateFun: + return substrateFun(self._createComponent(asn1Spec, tagSet, noValue, **options), + substrate, length) + + head, tail = substrate[:length], substrate[length:] + + return self._createComponent(asn1Spec, tagSet, head, **options), tail + + def indefLenValueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + if asn1Spec is None: + isTagged = False + + elif asn1Spec.__class__ is tagmap.TagMap: + isTagged = tagSet in asn1Spec.tagMap + + else: + isTagged = tagSet == asn1Spec.tagSet + + if isTagged: + # tagged Any type -- consume header substrate + header = null + + if LOG: + LOG('decoding as tagged ANY') + + else: + fullSubstrate = options['fullSubstrate'] + + # untagged Any, recover header substrate + header = fullSubstrate[:-len(substrate)] + + if LOG: + LOG('decoding as untagged ANY, header substrate %s' % debug.hexdump(header)) + + # Any components do not inherit initial tag + asn1Spec = self.protoComponent + + if substrateFun and substrateFun is not self.substrateCollector: + asn1Object = self._createComponent(asn1Spec, tagSet, noValue, **options) + return substrateFun(asn1Object, header + substrate, length + len(header)) + + if LOG: + LOG('assembling constructed serialization') + + # All inner fragments are of the same type, treat them as octet string + substrateFun = self.substrateCollector + + while substrate: + component, substrate = decodeFun(substrate, asn1Spec, + substrateFun=substrateFun, + allowEoo=True, **options) + if component is eoo.endOfOctets: + break + + header += component + + else: + raise error.SubstrateUnderrunError( + 'No EOO seen before substrate ends' + ) + + if substrateFun: + return header, substrate + + else: + return self._createComponent(asn1Spec, tagSet, header, **options), substrate + + +# character string types +class UTF8StringDecoder(OctetStringDecoder): + protoComponent = char.UTF8String() + + +class NumericStringDecoder(OctetStringDecoder): + protoComponent = char.NumericString() + + +class PrintableStringDecoder(OctetStringDecoder): + protoComponent = char.PrintableString() + + +class TeletexStringDecoder(OctetStringDecoder): + protoComponent = char.TeletexString() + + +class VideotexStringDecoder(OctetStringDecoder): + protoComponent = char.VideotexString() + + +class IA5StringDecoder(OctetStringDecoder): + protoComponent = char.IA5String() + + +class GraphicStringDecoder(OctetStringDecoder): + protoComponent = char.GraphicString() + + +class VisibleStringDecoder(OctetStringDecoder): + protoComponent = char.VisibleString() + + +class GeneralStringDecoder(OctetStringDecoder): + protoComponent = char.GeneralString() + + +class UniversalStringDecoder(OctetStringDecoder): + protoComponent = char.UniversalString() + + +class BMPStringDecoder(OctetStringDecoder): + protoComponent = char.BMPString() + + +# "useful" types +class ObjectDescriptorDecoder(OctetStringDecoder): + protoComponent = useful.ObjectDescriptor() + + +class GeneralizedTimeDecoder(OctetStringDecoder): + protoComponent = useful.GeneralizedTime() + + +class UTCTimeDecoder(OctetStringDecoder): + protoComponent = useful.UTCTime() + + +tagMap = { + univ.Integer.tagSet: IntegerDecoder(), + univ.Boolean.tagSet: BooleanDecoder(), + univ.BitString.tagSet: BitStringDecoder(), + univ.OctetString.tagSet: OctetStringDecoder(), + univ.Null.tagSet: NullDecoder(), + univ.ObjectIdentifier.tagSet: ObjectIdentifierDecoder(), + univ.Enumerated.tagSet: IntegerDecoder(), + univ.Real.tagSet: RealDecoder(), + univ.Sequence.tagSet: SequenceOrSequenceOfDecoder(), # conflicts with SequenceOf + univ.Set.tagSet: SetOrSetOfDecoder(), # conflicts with SetOf + univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any + # character string types + char.UTF8String.tagSet: UTF8StringDecoder(), + char.NumericString.tagSet: NumericStringDecoder(), + char.PrintableString.tagSet: PrintableStringDecoder(), + char.TeletexString.tagSet: TeletexStringDecoder(), + char.VideotexString.tagSet: VideotexStringDecoder(), + char.IA5String.tagSet: IA5StringDecoder(), + char.GraphicString.tagSet: GraphicStringDecoder(), + char.VisibleString.tagSet: VisibleStringDecoder(), + char.GeneralString.tagSet: GeneralStringDecoder(), + char.UniversalString.tagSet: UniversalStringDecoder(), + char.BMPString.tagSet: BMPStringDecoder(), + # useful types + useful.ObjectDescriptor.tagSet: ObjectDescriptorDecoder(), + useful.GeneralizedTime.tagSet: GeneralizedTimeDecoder(), + useful.UTCTime.tagSet: UTCTimeDecoder() +} + +# Type-to-codec map for ambiguous ASN.1 types +typeMap = { + univ.Set.typeId: SetDecoder(), + univ.SetOf.typeId: SetOfDecoder(), + univ.Sequence.typeId: SequenceDecoder(), + univ.SequenceOf.typeId: SequenceOfDecoder(), + univ.Choice.typeId: ChoiceDecoder(), + univ.Any.typeId: AnyDecoder() +} + +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in tagMap.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in typeMap: + typeMap[typeId] = typeDecoder + + +(stDecodeTag, + stDecodeLength, + stGetValueDecoder, + stGetValueDecoderByAsn1Spec, + stGetValueDecoderByTag, + stTryAsExplicitTag, + stDecodeValue, + stDumpRawValue, + stErrorCondition, + stStop) = [x for x in range(10)] + + +class Decoder(object): + defaultErrorState = stErrorCondition + #defaultErrorState = stDumpRawValue + defaultRawDecoder = AnyDecoder() + supportIndefLength = True + + # noinspection PyDefaultArgument + def __init__(self, tagMap, typeMap={}): + self.__tagMap = tagMap + self.__typeMap = typeMap + # Tag & TagSet objects caches + self.__tagCache = {} + self.__tagSetCache = {} + self.__eooSentinel = ints2octs((0, 0)) + + def __call__(self, substrate, asn1Spec=None, + tagSet=None, length=None, state=stDecodeTag, + decodeFun=None, substrateFun=None, + **options): + + if LOG: + LOG('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) + + allowEoo = options.pop('allowEoo', False) + + # Look for end-of-octets sentinel + if allowEoo and self.supportIndefLength: + if substrate[:2] == self.__eooSentinel: + if LOG: + LOG('end-of-octets sentinel found') + return eoo.endOfOctets, substrate[2:] + + value = noValue + + tagMap = self.__tagMap + typeMap = self.__typeMap + tagCache = self.__tagCache + tagSetCache = self.__tagSetCache + + fullSubstrate = substrate + + while state is not stStop: + + if state is stDecodeTag: + if not substrate: + raise error.SubstrateUnderrunError( + 'Short octet stream on tag decoding' + ) + + # Decode tag + isShortTag = True + firstOctet = substrate[0] + substrate = substrate[1:] + + try: + lastTag = tagCache[firstOctet] + + except KeyError: + integerTag = oct2int(firstOctet) + tagClass = integerTag & 0xC0 + tagFormat = integerTag & 0x20 + tagId = integerTag & 0x1F + + if tagId == 0x1F: + isShortTag = False + lengthOctetIdx = 0 + tagId = 0 + + try: + while True: + integerTag = oct2int(substrate[lengthOctetIdx]) + lengthOctetIdx += 1 + tagId <<= 7 + tagId |= (integerTag & 0x7F) + if not integerTag & 0x80: + break + + substrate = substrate[lengthOctetIdx:] + + except IndexError: + raise error.SubstrateUnderrunError( + 'Short octet stream on long tag decoding' + ) + + lastTag = tag.Tag( + tagClass=tagClass, tagFormat=tagFormat, tagId=tagId + ) + + if isShortTag: + # cache short tags + tagCache[firstOctet] = lastTag + + if tagSet is None: + if isShortTag: + try: + tagSet = tagSetCache[firstOctet] + + except KeyError: + # base tag not recovered + tagSet = tag.TagSet((), lastTag) + tagSetCache[firstOctet] = tagSet + else: + tagSet = tag.TagSet((), lastTag) + + else: + tagSet = lastTag + tagSet + + state = stDecodeLength + + if LOG: + LOG('tag decoded into %s, decoding length' % tagSet) + + if state is stDecodeLength: + # Decode length + if not substrate: + raise error.SubstrateUnderrunError( + 'Short octet stream on length decoding' + ) + + firstOctet = oct2int(substrate[0]) + + if firstOctet < 128: + size = 1 + length = firstOctet + + elif firstOctet > 128: + size = firstOctet & 0x7F + # encoded in size bytes + encodedLength = octs2ints(substrate[1:size + 1]) + # missing check on maximum size, which shouldn't be a + # problem, we can handle more than is possible + if len(encodedLength) != size: + raise error.SubstrateUnderrunError( + '%s<%s at %s' % (size, len(encodedLength), tagSet) + ) + + length = 0 + for lengthOctet in encodedLength: + length <<= 8 + length |= lengthOctet + size += 1 + + else: + size = 1 + length = -1 + + substrate = substrate[size:] + + if length == -1: + if not self.supportIndefLength: + raise error.PyAsn1Error('Indefinite length encoding not supported by this codec') + + else: + if len(substrate) < length: + raise error.SubstrateUnderrunError('%d-octet short' % (length - len(substrate))) + + state = stGetValueDecoder + + if LOG: + LOG('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length]))) + + if state is stGetValueDecoder: + if asn1Spec is None: + state = stGetValueDecoderByTag + + else: + state = stGetValueDecoderByAsn1Spec + # + # There're two ways of creating subtypes in ASN.1 what influences + # decoder operation. These methods are: + # 1) Either base types used in or no IMPLICIT tagging has been + # applied on subtyping. + # 2) Subtype syntax drops base type information (by means of + # IMPLICIT tagging. + # The first case allows for complete tag recovery from substrate + # while the second one requires original ASN.1 type spec for + # decoding. + # + # In either case a set of tags (tagSet) is coming from substrate + # in an incremental, tag-by-tag fashion (this is the case of + # EXPLICIT tag which is most basic). Outermost tag comes first + # from the wire. + # + if state is stGetValueDecoderByTag: + try: + concreteDecoder = tagMap[tagSet] + + except KeyError: + concreteDecoder = None + + if concreteDecoder: + state = stDecodeValue + + else: + try: + concreteDecoder = tagMap[tagSet[:1]] + + except KeyError: + concreteDecoder = None + + if concreteDecoder: + state = stDecodeValue + else: + state = stTryAsExplicitTag + + if LOG: + LOG('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as explicit tag')) + debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__) + + if state is stGetValueDecoderByAsn1Spec: + + if asn1Spec.__class__ is tagmap.TagMap: + try: + chosenSpec = asn1Spec[tagSet] + + except KeyError: + chosenSpec = None + + if LOG: + LOG('candidate ASN.1 spec is a map of:') + + for firstOctet, v in asn1Spec.presentTypes.items(): + LOG(' %s -> %s' % (firstOctet, v.__class__.__name__)) + + if asn1Spec.skipTypes: + LOG('but neither of: ') + for firstOctet, v in asn1Spec.skipTypes.items(): + LOG(' %s -> %s' % (firstOctet, v.__class__.__name__)) + LOG('new candidate ASN.1 spec is %s, chosen by %s' % (chosenSpec is None and '' or chosenSpec.prettyPrintType(), tagSet)) + + elif tagSet == asn1Spec.tagSet or tagSet in asn1Spec.tagMap: + chosenSpec = asn1Spec + if LOG: + LOG('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) + + else: + chosenSpec = None + + if chosenSpec is not None: + try: + # ambiguous type or just faster codec lookup + concreteDecoder = typeMap[chosenSpec.typeId] + + if LOG: + LOG('value decoder chosen for an ambiguous type by type ID %s' % (chosenSpec.typeId,)) + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(chosenSpec.tagSet.baseTag, chosenSpec.tagSet.baseTag) + try: + # base type or tagged subtype + concreteDecoder = tagMap[baseTagSet] + + if LOG: + LOG('value decoder chosen by base %s' % (baseTagSet,)) + + except KeyError: + concreteDecoder = None + + if concreteDecoder: + asn1Spec = chosenSpec + state = stDecodeValue + + else: + state = stTryAsExplicitTag + + else: + concreteDecoder = None + state = stTryAsExplicitTag + + if LOG: + LOG('codec %s chosen by ASN.1 spec, decoding %s' % (state is stDecodeValue and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as explicit tag')) + debug.scope.push(chosenSpec is None and '?' or chosenSpec.__class__.__name__) + + if state is stDecodeValue: + if not options.get('recursiveFlag', True) and not substrateFun: # deprecate this + substrateFun = lambda a, b, c: (a, b[:c]) + + options.update(fullSubstrate=fullSubstrate) + + if length == -1: # indef length + value, substrate = concreteDecoder.indefLenValueDecoder( + substrate, asn1Spec, + tagSet, length, stGetValueDecoder, + self, substrateFun, + **options + ) + + else: + value, substrate = concreteDecoder.valueDecoder( + substrate, asn1Spec, + tagSet, length, stGetValueDecoder, + self, substrateFun, + **options + ) + + if LOG: + LOG('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, isinstance(value, base.Asn1Item) and value.prettyPrint() or value, substrate and debug.hexdump(substrate) or '')) + + state = stStop + break + + if state is stTryAsExplicitTag: + if (tagSet and + tagSet[0].tagFormat == tag.tagFormatConstructed and + tagSet[0].tagClass != tag.tagClassUniversal): + # Assume explicit tagging + concreteDecoder = explicitTagDecoder + state = stDecodeValue + + else: + concreteDecoder = None + state = self.defaultErrorState + + if LOG: + LOG('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "", state is stDecodeValue and 'value' or 'as failure')) + + if state is stDumpRawValue: + concreteDecoder = self.defaultRawDecoder + + if LOG: + LOG('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) + + state = stDecodeValue + + if state is stErrorCondition: + raise error.PyAsn1Error( + '%s not in asn1Spec: %r' % (tagSet, asn1Spec) + ) + + if LOG: + debug.scope.pop() + LOG('decoder left scope %s, call completed' % debug.scope) + + return value, substrate + + +#: Turns BER octet stream into an ASN.1 object. +#: +#: Takes BER octet-stream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: BER octet-stream +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from BER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError +#: On decoding errors +#: +#: Examples +#: -------- +#: Decode BER serialisation without ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +#: Decode BER serialisation with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder(tagMap, typeMap) + +# XXX +# non-recursive decoding; return position rather than substrate diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/ber/encoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/encoder.py new file mode 100644 index 0000000..778aa86 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/encoder.py @@ -0,0 +1,890 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import debug +from pyasn1 import error +from pyasn1.codec.ber import eoo +from pyasn1.compat.integer import to_bytes +from pyasn1.compat.octets import (int2oct, oct2int, ints2octs, null, + str2octs, isOctetsType) +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['encode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER) + + +class AbstractItemEncoder(object): + supportIndefLenMode = True + + # An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)` + eooIntegerSubstrate = (0, 0) + eooOctetsSubstrate = ints2octs(eooIntegerSubstrate) + + # noinspection PyMethodMayBeStatic + def encodeTag(self, singleTag, isConstructed): + tagClass, tagFormat, tagId = singleTag + encodedTag = tagClass | tagFormat + if isConstructed: + encodedTag |= tag.tagFormatConstructed + + if tagId < 31: + return encodedTag | tagId, + + else: + substrate = tagId & 0x7f, + + tagId >>= 7 + + while tagId: + substrate = (0x80 | (tagId & 0x7f),) + substrate + tagId >>= 7 + + return (encodedTag | 0x1F,) + substrate + + def encodeLength(self, length, defMode): + if not defMode and self.supportIndefLenMode: + return (0x80,) + + if length < 0x80: + return length, + + else: + substrate = () + while length: + substrate = (length & 0xff,) + substrate + length >>= 8 + + substrateLen = len(substrate) + + if substrateLen > 126: + raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen) + + return (0x80 | substrateLen,) + substrate + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + raise error.PyAsn1Error('Not implemented') + + def encode(self, value, asn1Spec=None, encodeFun=None, **options): + + if asn1Spec is None: + tagSet = value.tagSet + else: + tagSet = asn1Spec.tagSet + + # untagged item? + if not tagSet: + substrate, isConstructed, isOctets = self.encodeValue( + value, asn1Spec, encodeFun, **options + ) + return substrate + + defMode = options.get('defMode', True) + + substrate = null + + for idx, singleTag in enumerate(tagSet.superTags): + + defModeOverride = defMode + + # base tag? + if not idx: + try: + substrate, isConstructed, isOctets = self.encodeValue( + value, asn1Spec, encodeFun, **options + ) + + except error.PyAsn1Error: + exc = sys.exc_info() + raise error.PyAsn1Error( + 'Error encoding %r: %s' % (value, exc[1])) + + if LOG: + LOG('encoded %svalue %s into %s' % ( + isConstructed and 'constructed ' or '', value, substrate + )) + + if not substrate and isConstructed and options.get('ifNotEmpty', False): + return substrate + + if not isConstructed: + defModeOverride = True + + if LOG: + LOG('overridden encoding mode into definitive for primitive type') + + header = self.encodeTag(singleTag, isConstructed) + + if LOG: + LOG('encoded %stag %s into %s' % ( + isConstructed and 'constructed ' or '', + singleTag, debug.hexdump(ints2octs(header)))) + + header += self.encodeLength(len(substrate), defModeOverride) + + if LOG: + LOG('encoded %s octets (tag + payload) into %s' % ( + len(substrate), debug.hexdump(ints2octs(header)))) + + if isOctets: + substrate = ints2octs(header) + substrate + + if not defModeOverride: + substrate += self.eooOctetsSubstrate + + else: + substrate = header + substrate + + if not defModeOverride: + substrate += self.eooIntegerSubstrate + + if not isOctets: + substrate = ints2octs(substrate) + + return substrate + + +class EndOfOctetsEncoder(AbstractItemEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + return null, False, True + + +class BooleanEncoder(AbstractItemEncoder): + supportIndefLenMode = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + return value and (1,) or (0,), False, False + + +class IntegerEncoder(AbstractItemEncoder): + supportIndefLenMode = False + supportCompactZero = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if value == 0: + if LOG: + LOG('encoding %spayload for zero INTEGER' % ( + self.supportCompactZero and 'no ' or '' + )) + + # de-facto way to encode zero + if self.supportCompactZero: + return (), False, False + else: + return (0,), False, False + + return to_bytes(int(value), signed=True), False, True + + +class BitStringEncoder(AbstractItemEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is not None: + # TODO: try to avoid ASN.1 schema instantiation + value = asn1Spec.clone(value) + + valueLength = len(value) + if valueLength % 8: + alignedValue = value << (8 - valueLength % 8) + else: + alignedValue = value + + maxChunkSize = options.get('maxChunkSize', 0) + if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8: + substrate = alignedValue.asOctets() + return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True + + if LOG: + LOG('encoding into up to %s-octet chunks' % maxChunkSize) + + baseTag = value.tagSet.baseTag + + # strip off explicit tags + if baseTag: + tagSet = tag.TagSet(baseTag, baseTag) + + else: + tagSet = tag.TagSet() + + alignedValue = alignedValue.clone(tagSet=tagSet) + + stop = 0 + substrate = null + while stop < valueLength: + start = stop + stop = min(start + maxChunkSize * 8, valueLength) + substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options) + + return substrate, True, True + + +class OctetStringEncoder(AbstractItemEncoder): + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + if asn1Spec is None: + substrate = value.asOctets() + + elif not isOctetsType(value): + substrate = asn1Spec.clone(value).asOctets() + + else: + substrate = value + + maxChunkSize = options.get('maxChunkSize', 0) + + if not maxChunkSize or len(substrate) <= maxChunkSize: + return substrate, False, True + + if LOG: + LOG('encoding into up to %s-octet chunks' % maxChunkSize) + + # strip off explicit tags for inner chunks + + if asn1Spec is None: + baseTag = value.tagSet.baseTag + + # strip off explicit tags + if baseTag: + tagSet = tag.TagSet(baseTag, baseTag) + + else: + tagSet = tag.TagSet() + + asn1Spec = value.clone(tagSet=tagSet) + + elif not isOctetsType(value): + baseTag = asn1Spec.tagSet.baseTag + + # strip off explicit tags + if baseTag: + tagSet = tag.TagSet(baseTag, baseTag) + + else: + tagSet = tag.TagSet() + + asn1Spec = asn1Spec.clone(tagSet=tagSet) + + pos = 0 + substrate = null + + while True: + chunk = value[pos:pos + maxChunkSize] + if not chunk: + break + + substrate += encodeFun(chunk, asn1Spec, **options) + pos += maxChunkSize + + return substrate, True, True + + +class NullEncoder(AbstractItemEncoder): + supportIndefLenMode = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + return null, False, True + + +class ObjectIdentifierEncoder(AbstractItemEncoder): + supportIndefLenMode = False + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is not None: + value = asn1Spec.clone(value) + + oid = value.asTuple() + + # Build the first pair + try: + first = oid[0] + second = oid[1] + + except IndexError: + raise error.PyAsn1Error('Short OID %s' % (value,)) + + if 0 <= second <= 39: + if first == 1: + oid = (second + 40,) + oid[2:] + elif first == 0: + oid = (second,) + oid[2:] + elif first == 2: + oid = (second + 80,) + oid[2:] + else: + raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) + + elif first == 2: + oid = (second + 80,) + oid[2:] + + else: + raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) + + octets = () + + # Cycle through subIds + for subOid in oid: + if 0 <= subOid <= 127: + # Optimize for the common case + octets += (subOid,) + + elif subOid > 127: + # Pack large Sub-Object IDs + res = (subOid & 0x7f,) + subOid >>= 7 + + while subOid: + res = (0x80 | (subOid & 0x7f),) + res + subOid >>= 7 + + # Add packed Sub-Object ID to resulted Object ID + octets += res + + else: + raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value)) + + return octets, False, False + + +class RealEncoder(AbstractItemEncoder): + supportIndefLenMode = 0 + binEncBase = 2 # set to None to choose encoding base automatically + + @staticmethod + def _dropFloatingPoint(m, encbase, e): + ms, es = 1, 1 + if m < 0: + ms = -1 # mantissa sign + + if e < 0: + es = -1 # exponent sign + + m *= ms + + if encbase == 8: + m *= 2 ** (abs(e) % 3 * es) + e = abs(e) // 3 * es + + elif encbase == 16: + m *= 2 ** (abs(e) % 4 * es) + e = abs(e) // 4 * es + + while True: + if int(m) != m: + m *= encbase + e -= 1 + continue + break + + return ms, int(m), encbase, e + + def _chooseEncBase(self, value): + m, b, e = value + encBase = [2, 8, 16] + if value.binEncBase in encBase: + return self._dropFloatingPoint(m, value.binEncBase, e) + + elif self.binEncBase in encBase: + return self._dropFloatingPoint(m, self.binEncBase, e) + + # auto choosing base 2/8/16 + mantissa = [m, m, m] + exponent = [e, e, e] + sign = 1 + encbase = 2 + e = float('inf') + + for i in range(3): + (sign, + mantissa[i], + encBase[i], + exponent[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponent[i]) + + if abs(exponent[i]) < abs(e) or (abs(exponent[i]) == abs(e) and mantissa[i] < m): + e = exponent[i] + m = int(mantissa[i]) + encbase = encBase[i] + + if LOG: + LOG('automatically chosen REAL encoding base %s, sign %s, mantissa %s, ' + 'exponent %s' % (encbase, sign, m, e)) + + return sign, m, encbase, e + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is not None: + value = asn1Spec.clone(value) + + if value.isPlusInf: + return (0x40,), False, False + + if value.isMinusInf: + return (0x41,), False, False + + m, b, e = value + + if not m: + return null, False, True + + if b == 10: + if LOG: + LOG('encoding REAL into character form') + + return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True + + elif b == 2: + fo = 0x80 # binary encoding + ms, m, encbase, e = self._chooseEncBase(value) + + if ms < 0: # mantissa sign + fo |= 0x40 # sign bit + + # exponent & mantissa normalization + if encbase == 2: + while m & 0x1 == 0: + m >>= 1 + e += 1 + + elif encbase == 8: + while m & 0x7 == 0: + m >>= 3 + e += 1 + fo |= 0x10 + + else: # encbase = 16 + while m & 0xf == 0: + m >>= 4 + e += 1 + fo |= 0x20 + + sf = 0 # scale factor + + while m & 0x1 == 0: + m >>= 1 + sf += 1 + + if sf > 3: + raise error.PyAsn1Error('Scale factor overflow') # bug if raised + + fo |= sf << 2 + eo = null + if e == 0 or e == -1: + eo = int2oct(e & 0xff) + + else: + while e not in (0, -1): + eo = int2oct(e & 0xff) + eo + e >>= 8 + + if e == 0 and eo and oct2int(eo[0]) & 0x80: + eo = int2oct(0) + eo + + if e == -1 and eo and not (oct2int(eo[0]) & 0x80): + eo = int2oct(0xff) + eo + + n = len(eo) + if n > 0xff: + raise error.PyAsn1Error('Real exponent overflow') + + if n == 1: + pass + + elif n == 2: + fo |= 1 + + elif n == 3: + fo |= 2 + + else: + fo |= 3 + eo = int2oct(n & 0xff) + eo + + po = null + + while m: + po = int2oct(m & 0xff) + po + m >>= 8 + + substrate = int2oct(fo) + eo + po + + return substrate, False, True + + else: + raise error.PyAsn1Error('Prohibited Real base %s' % b) + + +class SequenceEncoder(AbstractItemEncoder): + omitEmptyOptionals = False + + # TODO: handling three flavors of input is too much -- split over codecs + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + substrate = null + + omitEmptyOptionals = options.get( + 'omitEmptyOptionals', self.omitEmptyOptionals) + + if LOG: + LOG('%sencoding empty OPTIONAL components' % ( + omitEmptyOptionals and 'not ' or '')) + + if asn1Spec is None: + # instance of ASN.1 schema + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + namedTypes = value.componentType + + for idx, component in enumerate(value.values()): + if namedTypes: + namedType = namedTypes[idx] + + if namedType.isOptional and not component.isValue: + if LOG: + LOG('not encoding OPTIONAL component %r' % (namedType,)) + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + if LOG: + LOG('not encoding DEFAULT component %r' % (namedType,)) + continue + + if omitEmptyOptionals: + options.update(ifNotEmpty=namedType.isOptional) + + # wrap open type blob if needed + if namedTypes and namedType.openType: + + wrapType = namedType.asn1Object + + if wrapType.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + substrate += encodeFun( + component, asn1Spec, + **dict(options, wrapType=wrapType.componentType)) + + else: + chunk = encodeFun(component, asn1Spec, **options) + + if wrapType.isSameTypeWith(component): + substrate += chunk + + else: + substrate += encodeFun(chunk, wrapType, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) + + else: + substrate += encodeFun(component, asn1Spec, **options) + + else: + # bare Python value + ASN.1 schema + for idx, namedType in enumerate(asn1Spec.componentType.namedTypes): + + try: + component = value[namedType.name] + + except KeyError: + raise error.PyAsn1Error('Component name "%s" not found in %r' % ( + namedType.name, value)) + + if namedType.isOptional and namedType.name not in value: + if LOG: + LOG('not encoding OPTIONAL component %r' % (namedType,)) + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + if LOG: + LOG('not encoding DEFAULT component %r' % (namedType,)) + continue + + if omitEmptyOptionals: + options.update(ifNotEmpty=namedType.isOptional) + + componentSpec = namedType.asn1Object + + # wrap open type blob if needed + if namedType.openType: + + if componentSpec.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + + substrate += encodeFun( + component, componentSpec, + **dict(options, wrapType=componentSpec.componentType)) + + else: + chunk = encodeFun(component, componentSpec, **options) + + if componentSpec.isSameTypeWith(component): + substrate += chunk + + else: + substrate += encodeFun(chunk, componentSpec, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (componentSpec,)) + + else: + substrate += encodeFun(component, componentSpec, **options) + + return substrate, True, True + + +class SequenceOfEncoder(AbstractItemEncoder): + def _encodeComponents(self, value, asn1Spec, encodeFun, **options): + + if asn1Spec is None: + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + else: + asn1Spec = asn1Spec.componentType + + chunks = [] + + wrapType = options.pop('wrapType', None) + + for idx, component in enumerate(value): + chunk = encodeFun(component, asn1Spec, **options) + + if (wrapType is not None and + not wrapType.isSameTypeWith(component)): + # wrap encoded value with wrapper container (e.g. ANY) + chunk = encodeFun(chunk, wrapType, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) + + chunks.append(chunk) + + return chunks + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + return null.join(chunks), True, True + + +class ChoiceEncoder(AbstractItemEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is None: + component = value.getComponent() + else: + names = [namedType.name for namedType in asn1Spec.componentType.namedTypes + if namedType.name in value] + if len(names) != 1: + raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value)) + + name = names[0] + + component = value[name] + asn1Spec = asn1Spec[name] + + return encodeFun(component, asn1Spec, **options), True, True + + +class AnyEncoder(OctetStringEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if asn1Spec is None: + value = value.asOctets() + elif not isOctetsType(value): + value = asn1Spec.clone(value).asOctets() + + return value, not options.get('defMode', True), True + + +tagMap = { + eoo.endOfOctets.tagSet: EndOfOctetsEncoder(), + univ.Boolean.tagSet: BooleanEncoder(), + univ.Integer.tagSet: IntegerEncoder(), + univ.BitString.tagSet: BitStringEncoder(), + univ.OctetString.tagSet: OctetStringEncoder(), + univ.Null.tagSet: NullEncoder(), + univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), + univ.Enumerated.tagSet: IntegerEncoder(), + univ.Real.tagSet: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SequenceOf.tagSet: SequenceOfEncoder(), + univ.SetOf.tagSet: SequenceOfEncoder(), + univ.Choice.tagSet: ChoiceEncoder(), + # character string types + char.UTF8String.tagSet: OctetStringEncoder(), + char.NumericString.tagSet: OctetStringEncoder(), + char.PrintableString.tagSet: OctetStringEncoder(), + char.TeletexString.tagSet: OctetStringEncoder(), + char.VideotexString.tagSet: OctetStringEncoder(), + char.IA5String.tagSet: OctetStringEncoder(), + char.GraphicString.tagSet: OctetStringEncoder(), + char.VisibleString.tagSet: OctetStringEncoder(), + char.GeneralString.tagSet: OctetStringEncoder(), + char.UniversalString.tagSet: OctetStringEncoder(), + char.BMPString.tagSet: OctetStringEncoder(), + # useful types + useful.ObjectDescriptor.tagSet: OctetStringEncoder(), + useful.GeneralizedTime.tagSet: OctetStringEncoder(), + useful.UTCTime.tagSet: OctetStringEncoder() +} + +# Put in ambiguous & non-ambiguous types for faster codec lookup +typeMap = { + univ.Boolean.typeId: BooleanEncoder(), + univ.Integer.typeId: IntegerEncoder(), + univ.BitString.typeId: BitStringEncoder(), + univ.OctetString.typeId: OctetStringEncoder(), + univ.Null.typeId: NullEncoder(), + univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(), + univ.Enumerated.typeId: IntegerEncoder(), + univ.Real.typeId: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.Set.typeId: SequenceEncoder(), + univ.SetOf.typeId: SequenceOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder(), + univ.Choice.typeId: ChoiceEncoder(), + univ.Any.typeId: AnyEncoder(), + # character string types + char.UTF8String.typeId: OctetStringEncoder(), + char.NumericString.typeId: OctetStringEncoder(), + char.PrintableString.typeId: OctetStringEncoder(), + char.TeletexString.typeId: OctetStringEncoder(), + char.VideotexString.typeId: OctetStringEncoder(), + char.IA5String.typeId: OctetStringEncoder(), + char.GraphicString.typeId: OctetStringEncoder(), + char.VisibleString.typeId: OctetStringEncoder(), + char.GeneralString.typeId: OctetStringEncoder(), + char.UniversalString.typeId: OctetStringEncoder(), + char.BMPString.typeId: OctetStringEncoder(), + # useful types + useful.ObjectDescriptor.typeId: OctetStringEncoder(), + useful.GeneralizedTime.typeId: OctetStringEncoder(), + useful.UTCTime.typeId: OctetStringEncoder() +} + + +class Encoder(object): + fixedDefLengthMode = None + fixedChunkSize = None + + # noinspection PyDefaultArgument + def __init__(self, tagMap, typeMap={}): + self.__tagMap = tagMap + self.__typeMap = typeMap + + def __call__(self, value, asn1Spec=None, **options): + try: + if asn1Spec is None: + typeId = value.typeId + else: + typeId = asn1Spec.typeId + + except AttributeError: + raise error.PyAsn1Error('Value %r is not ASN.1 type instance ' + 'and "asn1Spec" not given' % (value,)) + + if LOG: + LOG('encoder called in %sdef mode, chunk size %s for ' + 'type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), asn1Spec is None and value.prettyPrintType() or asn1Spec.prettyPrintType(), value)) + + if self.fixedDefLengthMode is not None: + options.update(defMode=self.fixedDefLengthMode) + + if self.fixedChunkSize is not None: + options.update(maxChunkSize=self.fixedChunkSize) + + + try: + concreteEncoder = self.__typeMap[typeId] + + if LOG: + LOG('using value codec %s chosen by type ID %s' % (concreteEncoder.__class__.__name__, typeId)) + + except KeyError: + if asn1Spec is None: + tagSet = value.tagSet + else: + tagSet = asn1Spec.tagSet + + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag) + + try: + concreteEncoder = self.__tagMap[baseTagSet] + + except KeyError: + raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet)) + + if LOG: + LOG('using value codec %s chosen by tagSet %s' % (concreteEncoder.__class__.__name__, tagSet)) + + substrate = concreteEncoder.encode(value, asn1Spec, self, **options) + + if LOG: + LOG('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate))) + + return substrate + +#: Turns ASN.1 object into BER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a BER octet stream. +#: +#: Parameters +#: ---------- +#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` +#: parameter is required to guide the encoding process. +#: +#: Keyword Args +#: ------------ +#: asn1Spec: +#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: +#: defMode: :py:class:`bool` +#: If :obj:`False`, produces indefinite length encoding +#: +#: maxChunkSize: :py:class:`int` +#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size) +#: +#: Returns +#: ------- +#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: Given ASN.1 object encoded into BER octetstream +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode Python value into BER with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> encode([1, 2, 3], asn1Spec=seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +#: Encode ASN.1 value object into BER +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +encode = Encoder(tagMap, typeMap) diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/ber/eoo.py b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/eoo.py new file mode 100644 index 0000000..48eb859 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/ber/eoo.py @@ -0,0 +1,28 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1.type import base +from pyasn1.type import tag + +__all__ = ['endOfOctets'] + + +class EndOfOctets(base.SimpleAsn1Type): + defaultValue = 0 + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00) + ) + + _instance = None + + def __new__(cls, *args, **kwargs): + if cls._instance is None: + cls._instance = object.__new__(cls, *args, **kwargs) + + return cls._instance + + +endOfOctets = EndOfOctets() diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/cer/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/codec/cer/__init__.py new file mode 100644 index 0000000..8c3066b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/cer/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/cer/decoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/cer/decoder.py new file mode 100644 index 0000000..3e86fd0 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/cer/decoder.py @@ -0,0 +1,114 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error +from pyasn1.codec.ber import decoder +from pyasn1.compat.octets import oct2int +from pyasn1.type import univ + +__all__ = ['decode'] + + +class BooleanDecoder(decoder.AbstractSimpleDecoder): + protoComponent = univ.Boolean(0) + + def valueDecoder(self, substrate, asn1Spec, + tagSet=None, length=None, state=None, + decodeFun=None, substrateFun=None, + **options): + head, tail = substrate[:length], substrate[length:] + if not head or length != 1: + raise error.PyAsn1Error('Not single-octet Boolean payload') + byte = oct2int(head[0]) + # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while + # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1 + # in https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + if byte == 0xff: + value = 1 + elif byte == 0x00: + value = 0 + else: + raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte) + return self._createComponent(asn1Spec, tagSet, value, **options), tail + +# TODO: prohibit non-canonical encoding +BitStringDecoder = decoder.BitStringDecoder +OctetStringDecoder = decoder.OctetStringDecoder +RealDecoder = decoder.RealDecoder + +tagMap = decoder.tagMap.copy() +tagMap.update( + {univ.Boolean.tagSet: BooleanDecoder(), + univ.BitString.tagSet: BitStringDecoder(), + univ.OctetString.tagSet: OctetStringDecoder(), + univ.Real.tagSet: RealDecoder()} +) + +typeMap = decoder.typeMap.copy() + +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in tagMap.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in typeMap: + typeMap[typeId] = typeDecoder + + +class Decoder(decoder.Decoder): + pass + + +#: Turns CER octet stream into an ASN.1 object. +#: +#: Takes CER octet-stream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: CER octet-stream +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError +#: On decoding errors +#: +#: Examples +#: -------- +#: Decode CER serialisation without ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00') +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +#: Decode CER serialisation with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder(tagMap, decoder.typeMap) diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/cer/encoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/cer/encoder.py new file mode 100644 index 0000000..935b696 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/cer/encoder.py @@ -0,0 +1,313 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error +from pyasn1.codec.ber import encoder +from pyasn1.compat.octets import str2octs, null +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['encode'] + + +class BooleanEncoder(encoder.IntegerEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + if value == 0: + substrate = (0,) + else: + substrate = (255,) + return substrate, False, False + + +class RealEncoder(encoder.RealEncoder): + def _chooseEncBase(self, value): + m, b, e = value + return self._dropFloatingPoint(m, b, e) + + +# specialized GeneralStringEncoder here + +class TimeEncoderMixIn(object): + Z_CHAR = ord('Z') + PLUS_CHAR = ord('+') + MINUS_CHAR = ord('-') + COMMA_CHAR = ord(',') + DOT_CHAR = ord('.') + ZERO_CHAR = ord('0') + + MIN_LENGTH = 12 + MAX_LENGTH = 19 + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + # CER encoding constraints: + # - minutes are mandatory, seconds are optional + # - sub-seconds must NOT be zero / no meaningless zeros + # - no hanging fraction dot + # - time in UTC (Z) + # - only dot is allowed for fractions + + if asn1Spec is not None: + value = asn1Spec.clone(value) + + numbers = value.asNumbers() + + if self.PLUS_CHAR in numbers or self.MINUS_CHAR in numbers: + raise error.PyAsn1Error('Must be UTC time: %r' % value) + + if numbers[-1] != self.Z_CHAR: + raise error.PyAsn1Error('Missing "Z" time zone specifier: %r' % value) + + if self.COMMA_CHAR in numbers: + raise error.PyAsn1Error('Comma in fractions disallowed: %r' % value) + + if self.DOT_CHAR in numbers: + + isModified = False + + numbers = list(numbers) + + searchIndex = min(numbers.index(self.DOT_CHAR) + 4, len(numbers) - 1) + + while numbers[searchIndex] != self.DOT_CHAR: + if numbers[searchIndex] == self.ZERO_CHAR: + del numbers[searchIndex] + isModified = True + + searchIndex -= 1 + + searchIndex += 1 + + if searchIndex < len(numbers): + if numbers[searchIndex] == self.Z_CHAR: + # drop hanging comma + del numbers[searchIndex - 1] + isModified = True + + if isModified: + value = value.clone(numbers) + + if not self.MIN_LENGTH < len(numbers) < self.MAX_LENGTH: + raise error.PyAsn1Error('Length constraint violated: %r' % value) + + options.update(maxChunkSize=1000) + + return encoder.OctetStringEncoder.encodeValue( + self, value, asn1Spec, encodeFun, **options + ) + + +class GeneralizedTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder): + MIN_LENGTH = 12 + MAX_LENGTH = 20 + + +class UTCTimeEncoder(TimeEncoderMixIn, encoder.OctetStringEncoder): + MIN_LENGTH = 10 + MAX_LENGTH = 14 + + +class SetOfEncoder(encoder.SequenceOfEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + # sort by serialised and padded components + if len(chunks) > 1: + zero = str2octs('\x00') + maxLen = max(map(len, chunks)) + paddedChunks = [ + (x.ljust(maxLen, zero), x) for x in chunks + ] + paddedChunks.sort(key=lambda x: x[0]) + + chunks = [x[1] for x in paddedChunks] + + return null.join(chunks), True, True + + +class SequenceOfEncoder(encoder.SequenceOfEncoder): + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + if options.get('ifNotEmpty', False) and not len(value): + return null, True, True + + chunks = self._encodeComponents( + value, asn1Spec, encodeFun, **options) + + return null.join(chunks), True, True + + +class SetEncoder(encoder.SequenceEncoder): + @staticmethod + def _componentSortKey(componentAndType): + """Sort SET components by tag + + Sort regardless of the Choice value (static sort) + """ + component, asn1Spec = componentAndType + + if asn1Spec is None: + asn1Spec = component + + if asn1Spec.typeId == univ.Choice.typeId and not asn1Spec.tagSet: + if asn1Spec.tagSet: + return asn1Spec.tagSet + else: + return asn1Spec.componentType.minTagSet + else: + return asn1Spec.tagSet + + def encodeValue(self, value, asn1Spec, encodeFun, **options): + + substrate = null + + comps = [] + compsMap = {} + + if asn1Spec is None: + # instance of ASN.1 schema + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + namedTypes = value.componentType + + for idx, component in enumerate(value.values()): + if namedTypes: + namedType = namedTypes[idx] + + if namedType.isOptional and not component.isValue: + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + continue + + compsMap[id(component)] = namedType + + else: + compsMap[id(component)] = None + + comps.append((component, asn1Spec)) + + else: + # bare Python value + ASN.1 schema + for idx, namedType in enumerate(asn1Spec.componentType.namedTypes): + + try: + component = value[namedType.name] + + except KeyError: + raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value)) + + if namedType.isOptional and namedType.name not in value: + continue + + if namedType.isDefaulted and component == namedType.asn1Object: + continue + + compsMap[id(component)] = namedType + comps.append((component, asn1Spec[idx])) + + for comp, compType in sorted(comps, key=self._componentSortKey): + namedType = compsMap[id(comp)] + + if namedType: + options.update(ifNotEmpty=namedType.isOptional) + + chunk = encodeFun(comp, compType, **options) + + # wrap open type blob if needed + if namedType and namedType.openType: + wrapType = namedType.asn1Object + if wrapType.tagSet and not wrapType.isSameTypeWith(comp): + chunk = encodeFun(chunk, wrapType, **options) + + substrate += chunk + + return substrate, True, True + + +class SequenceEncoder(encoder.SequenceEncoder): + omitEmptyOptionals = True + + +tagMap = encoder.tagMap.copy() +tagMap.update({ + univ.Boolean.tagSet: BooleanEncoder(), + univ.Real.tagSet: RealEncoder(), + useful.GeneralizedTime.tagSet: GeneralizedTimeEncoder(), + useful.UTCTime.tagSet: UTCTimeEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SetOf.tagSet: SetOfEncoder(), + univ.Sequence.typeId: SequenceEncoder() +}) + +typeMap = encoder.typeMap.copy() +typeMap.update({ + univ.Boolean.typeId: BooleanEncoder(), + univ.Real.typeId: RealEncoder(), + useful.GeneralizedTime.typeId: GeneralizedTimeEncoder(), + useful.UTCTime.typeId: UTCTimeEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.Set.typeId: SetEncoder(), + univ.SetOf.typeId: SetOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder() +}) + + +class Encoder(encoder.Encoder): + fixedDefLengthMode = False + fixedChunkSize = 1000 + +#: Turns ASN.1 object into CER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a CER octet stream. +#: +#: Parameters +#: ---------- +#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` +#: parameter is required to guide the encoding process. +#: +#: Keyword Args +#: ------------ +#: asn1Spec: +#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: +#: Returns +#: ------- +#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: Given ASN.1 object encoded into BER octet-stream +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode Python value into CER with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> encode([1, 2, 3], asn1Spec=seq) +#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00' +#: +#: Encode ASN.1 value object into CER +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00' +#: +encode = Encoder(tagMap, typeMap) + +# EncoderFactory queries class instance and builds a map of tags -> encoders diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/der/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/codec/der/__init__.py new file mode 100644 index 0000000..8c3066b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/der/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/der/decoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/der/decoder.py new file mode 100644 index 0000000..1a13fdb --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/der/decoder.py @@ -0,0 +1,94 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1.codec.cer import decoder +from pyasn1.type import univ + +__all__ = ['decode'] + + +class BitStringDecoder(decoder.BitStringDecoder): + supportConstructedForm = False + + +class OctetStringDecoder(decoder.OctetStringDecoder): + supportConstructedForm = False + +# TODO: prohibit non-canonical encoding +RealDecoder = decoder.RealDecoder + +tagMap = decoder.tagMap.copy() +tagMap.update( + {univ.BitString.tagSet: BitStringDecoder(), + univ.OctetString.tagSet: OctetStringDecoder(), + univ.Real.tagSet: RealDecoder()} +) + +typeMap = decoder.typeMap.copy() + +# Put in non-ambiguous types for faster codec lookup +for typeDecoder in tagMap.values(): + if typeDecoder.protoComponent is not None: + typeId = typeDecoder.protoComponent.__class__.typeId + if typeId is not None and typeId not in typeMap: + typeMap[typeId] = typeDecoder + + +class Decoder(decoder.Decoder): + supportIndefLength = False + + +#: Turns DER octet stream into an ASN.1 object. +#: +#: Takes DER octet-stream and decode it into an ASN.1 object +#: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: DER octet-stream +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure +#: being decoded, *asn1Spec* may or may not be required. Most common reason for +#: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. +#: +#: Returns +#: ------- +#: : :py:class:`tuple` +#: A tuple of pyasn1 object recovered from DER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: and the unprocessed trailing portion of the *substrate* (may be empty) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError +#: On decoding errors +#: +#: Examples +#: -------- +#: Decode DER serialisation without ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +#: Decode DER serialisation with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder(tagMap, typeMap) diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/der/encoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/der/encoder.py new file mode 100644 index 0000000..90e982d --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/der/encoder.py @@ -0,0 +1,107 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error +from pyasn1.codec.cer import encoder +from pyasn1.type import univ + +__all__ = ['encode'] + + +class SetEncoder(encoder.SetEncoder): + @staticmethod + def _componentSortKey(componentAndType): + """Sort SET components by tag + + Sort depending on the actual Choice value (dynamic sort) + """ + component, asn1Spec = componentAndType + + if asn1Spec is None: + compType = component + else: + compType = asn1Spec + + if compType.typeId == univ.Choice.typeId and not compType.tagSet: + if asn1Spec is None: + return component.getComponent().tagSet + else: + # TODO: move out of sorting key function + names = [namedType.name for namedType in asn1Spec.componentType.namedTypes + if namedType.name in component] + if len(names) != 1: + raise error.PyAsn1Error( + '%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component)) + + # TODO: support nested CHOICE ordering + return asn1Spec[names[0]].tagSet + + else: + return compType.tagSet + +tagMap = encoder.tagMap.copy() +tagMap.update({ + # Set & SetOf have same tags + univ.Set.tagSet: SetEncoder() +}) + +typeMap = encoder.typeMap.copy() +typeMap.update({ + # Set & SetOf have same tags + univ.Set.typeId: SetEncoder() +}) + + +class Encoder(encoder.Encoder): + fixedDefLengthMode = True + fixedChunkSize = 0 + +#: Turns ASN.1 object into DER octet stream. +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a DER octet stream. +#: +#: Parameters +#: ---------- +#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` +#: parameter is required to guide the encoding process. +#: +#: Keyword Args +#: ------------ +#: asn1Spec: +#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: +#: Returns +#: ------- +#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) +#: Given ASN.1 object encoded into BER octet-stream +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode Python value into DER with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> encode([1, 2, 3], asn1Spec=seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +#: Encode ASN.1 value object into DER +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +encode = Encoder(tagMap, typeMap) diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/native/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/codec/native/__init__.py new file mode 100644 index 0000000..8c3066b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/native/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/native/decoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/native/decoder.py new file mode 100644 index 0000000..104b92e --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/native/decoder.py @@ -0,0 +1,213 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import debug +from pyasn1 import error +from pyasn1.type import base +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['decode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_DECODER) + + +class AbstractScalarDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + return asn1Spec.clone(pyObject) + + +class BitStringDecoder(AbstractScalarDecoder): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + return asn1Spec.clone(univ.BitString.fromBinaryString(pyObject)) + + +class SequenceOrSetDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + componentsTypes = asn1Spec.componentType + + for field in asn1Value: + if field in pyObject: + asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options) + + return asn1Value + + +class SequenceOfOrSetOfDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + for pyValue in pyObject: + asn1Value.append(decodeFun(pyValue, asn1Spec.componentType), **options) + + return asn1Value + + +class ChoiceDecoder(object): + def __call__(self, pyObject, asn1Spec, decodeFun=None, **options): + asn1Value = asn1Spec.clone() + + componentsTypes = asn1Spec.componentType + + for field in pyObject: + if field in componentsTypes: + asn1Value[field] = decodeFun(pyObject[field], componentsTypes[field].asn1Object, **options) + break + + return asn1Value + + +tagMap = { + univ.Integer.tagSet: AbstractScalarDecoder(), + univ.Boolean.tagSet: AbstractScalarDecoder(), + univ.BitString.tagSet: BitStringDecoder(), + univ.OctetString.tagSet: AbstractScalarDecoder(), + univ.Null.tagSet: AbstractScalarDecoder(), + univ.ObjectIdentifier.tagSet: AbstractScalarDecoder(), + univ.Enumerated.tagSet: AbstractScalarDecoder(), + univ.Real.tagSet: AbstractScalarDecoder(), + univ.Sequence.tagSet: SequenceOrSetDecoder(), # conflicts with SequenceOf + univ.Set.tagSet: SequenceOrSetDecoder(), # conflicts with SetOf + univ.Choice.tagSet: ChoiceDecoder(), # conflicts with Any + # character string types + char.UTF8String.tagSet: AbstractScalarDecoder(), + char.NumericString.tagSet: AbstractScalarDecoder(), + char.PrintableString.tagSet: AbstractScalarDecoder(), + char.TeletexString.tagSet: AbstractScalarDecoder(), + char.VideotexString.tagSet: AbstractScalarDecoder(), + char.IA5String.tagSet: AbstractScalarDecoder(), + char.GraphicString.tagSet: AbstractScalarDecoder(), + char.VisibleString.tagSet: AbstractScalarDecoder(), + char.GeneralString.tagSet: AbstractScalarDecoder(), + char.UniversalString.tagSet: AbstractScalarDecoder(), + char.BMPString.tagSet: AbstractScalarDecoder(), + # useful types + useful.ObjectDescriptor.tagSet: AbstractScalarDecoder(), + useful.GeneralizedTime.tagSet: AbstractScalarDecoder(), + useful.UTCTime.tagSet: AbstractScalarDecoder() +} + +# Put in ambiguous & non-ambiguous types for faster codec lookup +typeMap = { + univ.Integer.typeId: AbstractScalarDecoder(), + univ.Boolean.typeId: AbstractScalarDecoder(), + univ.BitString.typeId: BitStringDecoder(), + univ.OctetString.typeId: AbstractScalarDecoder(), + univ.Null.typeId: AbstractScalarDecoder(), + univ.ObjectIdentifier.typeId: AbstractScalarDecoder(), + univ.Enumerated.typeId: AbstractScalarDecoder(), + univ.Real.typeId: AbstractScalarDecoder(), + # ambiguous base types + univ.Set.typeId: SequenceOrSetDecoder(), + univ.SetOf.typeId: SequenceOfOrSetOfDecoder(), + univ.Sequence.typeId: SequenceOrSetDecoder(), + univ.SequenceOf.typeId: SequenceOfOrSetOfDecoder(), + univ.Choice.typeId: ChoiceDecoder(), + univ.Any.typeId: AbstractScalarDecoder(), + # character string types + char.UTF8String.typeId: AbstractScalarDecoder(), + char.NumericString.typeId: AbstractScalarDecoder(), + char.PrintableString.typeId: AbstractScalarDecoder(), + char.TeletexString.typeId: AbstractScalarDecoder(), + char.VideotexString.typeId: AbstractScalarDecoder(), + char.IA5String.typeId: AbstractScalarDecoder(), + char.GraphicString.typeId: AbstractScalarDecoder(), + char.VisibleString.typeId: AbstractScalarDecoder(), + char.GeneralString.typeId: AbstractScalarDecoder(), + char.UniversalString.typeId: AbstractScalarDecoder(), + char.BMPString.typeId: AbstractScalarDecoder(), + # useful types + useful.ObjectDescriptor.typeId: AbstractScalarDecoder(), + useful.GeneralizedTime.typeId: AbstractScalarDecoder(), + useful.UTCTime.typeId: AbstractScalarDecoder() +} + + +class Decoder(object): + + # noinspection PyDefaultArgument + def __init__(self, tagMap, typeMap): + self.__tagMap = tagMap + self.__typeMap = typeMap + + def __call__(self, pyObject, asn1Spec, **options): + + if LOG: + debug.scope.push(type(pyObject).__name__) + LOG('decoder called at scope %s, working with type %s' % (debug.scope, type(pyObject).__name__)) + + if asn1Spec is None or not isinstance(asn1Spec, base.Asn1Item): + raise error.PyAsn1Error('asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)' % asn1Spec.__class__.__name__) + + try: + valueDecoder = self.__typeMap[asn1Spec.typeId] + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(asn1Spec.tagSet.baseTag, asn1Spec.tagSet.baseTag) + + try: + valueDecoder = self.__tagMap[baseTagSet] + except KeyError: + raise error.PyAsn1Error('Unknown ASN.1 tag %s' % asn1Spec.tagSet) + + if LOG: + LOG('calling decoder %s on Python type %s <%s>' % (type(valueDecoder).__name__, type(pyObject).__name__, repr(pyObject))) + + value = valueDecoder(pyObject, asn1Spec, self, **options) + + if LOG: + LOG('decoder %s produced ASN.1 type %s <%s>' % (type(valueDecoder).__name__, type(value).__name__, repr(value))) + debug.scope.pop() + + return value + + +#: Turns Python objects of built-in types into ASN.1 objects. +#: +#: Takes Python objects of built-in types and turns them into a tree of +#: ASN.1 objects (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which +#: may be a scalar or an arbitrary nested structure. +#: +#: Parameters +#: ---------- +#: pyObject: :py:class:`object` +#: A scalar or nested Python objects +#: +#: Keyword Args +#: ------------ +#: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A pyasn1 type object to act as a template guiding the decoder. It is required +#: for successful interpretation of Python objects mapping into their ASN.1 +#: representations. +#: +#: Returns +#: ------- +#: : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative +#: A scalar or constructed pyasn1 object +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On decoding errors +#: +#: Examples +#: -------- +#: Decode native Python object into ASN.1 objects with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> s, _ = decode([1, 2, 3], asn1Spec=seq) +#: >>> str(s) +#: SequenceOf: +#: 1 2 3 +#: +decode = Decoder(tagMap, typeMap) diff --git a/Lambdas/Websocket Authorizer/pyasn1/codec/native/encoder.py b/Lambdas/Websocket Authorizer/pyasn1/codec/native/encoder.py new file mode 100644 index 0000000..4318abd --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/codec/native/encoder.py @@ -0,0 +1,256 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +try: + from collections import OrderedDict + +except ImportError: + OrderedDict = dict + +from pyasn1 import debug +from pyasn1 import error +from pyasn1.type import base +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ +from pyasn1.type import useful + +__all__ = ['encode'] + +LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_ENCODER) + + +class AbstractItemEncoder(object): + def encode(self, value, encodeFun, **options): + raise error.PyAsn1Error('Not implemented') + + +class BooleanEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return bool(value) + + +class IntegerEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return int(value) + + +class BitStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class OctetStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return value.asOctets() + + +class TextStringEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class NullEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return None + + +class ObjectIdentifierEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return str(value) + + +class RealEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return float(value) + + +class SetEncoder(AbstractItemEncoder): + protoDict = dict + + def encode(self, value, encodeFun, **options): + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + + namedTypes = value.componentType + substrate = self.protoDict() + + for idx, (key, subValue) in enumerate(value.items()): + if namedTypes and namedTypes[idx].isOptional and not value[idx].isValue: + continue + substrate[key] = encodeFun(subValue, **options) + return substrate + + +class SequenceEncoder(SetEncoder): + protoDict = OrderedDict + + +class SequenceOfEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + inconsistency = value.isInconsistent + if inconsistency: + raise inconsistency + return [encodeFun(x, **options) for x in value] + + +class ChoiceEncoder(SequenceEncoder): + pass + + +class AnyEncoder(AbstractItemEncoder): + def encode(self, value, encodeFun, **options): + return value.asOctets() + + +tagMap = { + univ.Boolean.tagSet: BooleanEncoder(), + univ.Integer.tagSet: IntegerEncoder(), + univ.BitString.tagSet: BitStringEncoder(), + univ.OctetString.tagSet: OctetStringEncoder(), + univ.Null.tagSet: NullEncoder(), + univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), + univ.Enumerated.tagSet: IntegerEncoder(), + univ.Real.tagSet: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.SequenceOf.tagSet: SequenceOfEncoder(), + univ.SetOf.tagSet: SequenceOfEncoder(), + univ.Choice.tagSet: ChoiceEncoder(), + # character string types + char.UTF8String.tagSet: TextStringEncoder(), + char.NumericString.tagSet: TextStringEncoder(), + char.PrintableString.tagSet: TextStringEncoder(), + char.TeletexString.tagSet: TextStringEncoder(), + char.VideotexString.tagSet: TextStringEncoder(), + char.IA5String.tagSet: TextStringEncoder(), + char.GraphicString.tagSet: TextStringEncoder(), + char.VisibleString.tagSet: TextStringEncoder(), + char.GeneralString.tagSet: TextStringEncoder(), + char.UniversalString.tagSet: TextStringEncoder(), + char.BMPString.tagSet: TextStringEncoder(), + # useful types + useful.ObjectDescriptor.tagSet: OctetStringEncoder(), + useful.GeneralizedTime.tagSet: OctetStringEncoder(), + useful.UTCTime.tagSet: OctetStringEncoder() +} + + +# Put in ambiguous & non-ambiguous types for faster codec lookup +typeMap = { + univ.Boolean.typeId: BooleanEncoder(), + univ.Integer.typeId: IntegerEncoder(), + univ.BitString.typeId: BitStringEncoder(), + univ.OctetString.typeId: OctetStringEncoder(), + univ.Null.typeId: NullEncoder(), + univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(), + univ.Enumerated.typeId: IntegerEncoder(), + univ.Real.typeId: RealEncoder(), + # Sequence & Set have same tags as SequenceOf & SetOf + univ.Set.typeId: SetEncoder(), + univ.SetOf.typeId: SequenceOfEncoder(), + univ.Sequence.typeId: SequenceEncoder(), + univ.SequenceOf.typeId: SequenceOfEncoder(), + univ.Choice.typeId: ChoiceEncoder(), + univ.Any.typeId: AnyEncoder(), + # character string types + char.UTF8String.typeId: OctetStringEncoder(), + char.NumericString.typeId: OctetStringEncoder(), + char.PrintableString.typeId: OctetStringEncoder(), + char.TeletexString.typeId: OctetStringEncoder(), + char.VideotexString.typeId: OctetStringEncoder(), + char.IA5String.typeId: OctetStringEncoder(), + char.GraphicString.typeId: OctetStringEncoder(), + char.VisibleString.typeId: OctetStringEncoder(), + char.GeneralString.typeId: OctetStringEncoder(), + char.UniversalString.typeId: OctetStringEncoder(), + char.BMPString.typeId: OctetStringEncoder(), + # useful types + useful.ObjectDescriptor.typeId: OctetStringEncoder(), + useful.GeneralizedTime.typeId: OctetStringEncoder(), + useful.UTCTime.typeId: OctetStringEncoder() +} + + +class Encoder(object): + + # noinspection PyDefaultArgument + def __init__(self, tagMap, typeMap={}): + self.__tagMap = tagMap + self.__typeMap = typeMap + + def __call__(self, value, **options): + if not isinstance(value, base.Asn1Item): + raise error.PyAsn1Error('value is not valid (should be an instance of an ASN.1 Item)') + + if LOG: + debug.scope.push(type(value).__name__) + LOG('encoder called for type %s <%s>' % (type(value).__name__, value.prettyPrint())) + + tagSet = value.tagSet + + try: + concreteEncoder = self.__typeMap[value.typeId] + + except KeyError: + # use base type for codec lookup to recover untagged types + baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) + + try: + concreteEncoder = self.__tagMap[baseTagSet] + + except KeyError: + raise error.PyAsn1Error('No encoder for %s' % (value,)) + + if LOG: + LOG('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet)) + + pyObject = concreteEncoder.encode(value, self, **options) + + if LOG: + LOG('encoder %s produced: %s' % (type(concreteEncoder).__name__, repr(pyObject))) + debug.scope.pop() + + return pyObject + + +#: Turns ASN.1 object into a Python built-in type object(s). +#: +#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: walks all its components recursively and produces a Python built-in type or a tree +#: of those. +#: +#: One exception is that instead of :py:class:`dict`, the :py:class:`OrderedDict` +#: can be produced (whenever available) to preserve ordering of the components +#: in ASN.1 SEQUENCE. +#: +#: Parameters +#: ---------- +# asn1Value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: pyasn1 object to encode (or a tree of them) +#: +#: Returns +#: ------- +#: : :py:class:`object` +#: Python built-in type instance (or a tree of them) +#: +#: Raises +#: ------ +#: ~pyasn1.error.PyAsn1Error +#: On encoding errors +#: +#: Examples +#: -------- +#: Encode ASN.1 value object into native Python types +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: [1, 2, 3] +#: +encode = Encoder(tagMap, typeMap) diff --git a/Lambdas/Websocket Authorizer/pyasn1/compat/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/compat/__init__.py new file mode 100644 index 0000000..8c3066b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/compat/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/Lambdas/Websocket Authorizer/pyasn1/compat/binary.py b/Lambdas/Websocket Authorizer/pyasn1/compat/binary.py new file mode 100644 index 0000000..addbdc9 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/compat/binary.py @@ -0,0 +1,33 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from sys import version_info + +if version_info[0:2] < (2, 6): + def bin(value): + bitstring = [] + + if value > 0: + prefix = '0b' + elif value < 0: + prefix = '-0b' + value = abs(value) + else: + prefix = '0b0' + + while value: + if value & 1 == 1: + bitstring.append('1') + else: + bitstring.append('0') + + value >>= 1 + + bitstring.reverse() + + return prefix + ''.join(bitstring) +else: + bin = bin diff --git a/Lambdas/Websocket Authorizer/pyasn1/compat/calling.py b/Lambdas/Websocket Authorizer/pyasn1/compat/calling.py new file mode 100644 index 0000000..778a3d1 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/compat/calling.py @@ -0,0 +1,20 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from sys import version_info + +__all__ = ['callable'] + + +if (2, 7) < version_info[:2] < (3, 2): + import collections + + def callable(x): + return isinstance(x, collections.Callable) + +else: + + callable = callable diff --git a/Lambdas/Websocket Authorizer/pyasn1/compat/dateandtime.py b/Lambdas/Websocket Authorizer/pyasn1/compat/dateandtime.py new file mode 100644 index 0000000..5e471bf --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/compat/dateandtime.py @@ -0,0 +1,22 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import time +from datetime import datetime +from sys import version_info + +__all__ = ['strptime'] + + +if version_info[:2] <= (2, 4): + + def strptime(text, dateFormat): + return datetime(*(time.strptime(text, dateFormat)[0:6])) + +else: + + def strptime(text, dateFormat): + return datetime.strptime(text, dateFormat) diff --git a/Lambdas/Websocket Authorizer/pyasn1/compat/integer.py b/Lambdas/Websocket Authorizer/pyasn1/compat/integer.py new file mode 100644 index 0000000..4b31791 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/compat/integer.py @@ -0,0 +1,110 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +try: + import platform + + implementation = platform.python_implementation() + +except (ImportError, AttributeError): + implementation = 'CPython' + +from pyasn1.compat.octets import oct2int, null, ensureString + +if sys.version_info[0:2] < (3, 2) or implementation != 'CPython': + from binascii import a2b_hex, b2a_hex + + if sys.version_info[0] > 2: + long = int + + def from_bytes(octets, signed=False): + if not octets: + return 0 + + value = long(b2a_hex(ensureString(octets)), 16) + + if signed and oct2int(octets[0]) & 0x80: + return value - (1 << len(octets) * 8) + + return value + + def to_bytes(value, signed=False, length=0): + if value < 0: + if signed: + bits = bitLength(value) + + # two's complement form + maxValue = 1 << bits + valueToEncode = (value + maxValue) % maxValue + + else: + raise OverflowError('can\'t convert negative int to unsigned') + elif value == 0 and length == 0: + return null + else: + bits = 0 + valueToEncode = value + + hexValue = hex(valueToEncode)[2:] + if hexValue.endswith('L'): + hexValue = hexValue[:-1] + + if len(hexValue) & 1: + hexValue = '0' + hexValue + + # padding may be needed for two's complement encoding + if value != valueToEncode or length: + hexLength = len(hexValue) * 4 + + padLength = max(length, bits) + + if padLength > hexLength: + hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue + elif length and hexLength - length > 7: + raise OverflowError('int too big to convert') + + firstOctet = int(hexValue[:2], 16) + + if signed: + if firstOctet & 0x80: + if value >= 0: + hexValue = '00' + hexValue + elif value < 0: + hexValue = 'ff' + hexValue + + octets_value = a2b_hex(hexValue) + + return octets_value + + def bitLength(number): + # bits in unsigned number + hexValue = hex(abs(number)) + bits = len(hexValue) - 2 + if hexValue.endswith('L'): + bits -= 1 + if bits & 1: + bits += 1 + bits *= 4 + # TODO: strip lhs zeros + return bits + +else: + + def from_bytes(octets, signed=False): + return int.from_bytes(bytes(octets), 'big', signed=signed) + + def to_bytes(value, signed=False, length=0): + length = max(value.bit_length(), length) + + if signed and length % 8 == 0: + length += 1 + + return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed) + + def bitLength(number): + return int(number).bit_length() diff --git a/Lambdas/Websocket Authorizer/pyasn1/compat/octets.py b/Lambdas/Websocket Authorizer/pyasn1/compat/octets.py new file mode 100644 index 0000000..99d23bb --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/compat/octets.py @@ -0,0 +1,46 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from sys import version_info + +if version_info[0] <= 2: + int2oct = chr + # noinspection PyPep8 + ints2octs = lambda s: ''.join([int2oct(x) for x in s]) + null = '' + oct2int = ord + # TODO: refactor to return a sequence of ints + # noinspection PyPep8 + octs2ints = lambda s: [oct2int(x) for x in s] + # noinspection PyPep8 + str2octs = lambda x: x + # noinspection PyPep8 + octs2str = lambda x: x + # noinspection PyPep8 + isOctetsType = lambda s: isinstance(s, str) + # noinspection PyPep8 + isStringType = lambda s: isinstance(s, (str, unicode)) + # noinspection PyPep8 + ensureString = str +else: + ints2octs = bytes + # noinspection PyPep8 + int2oct = lambda x: ints2octs((x,)) + null = ints2octs() + # noinspection PyPep8 + oct2int = lambda x: x + # noinspection PyPep8 + octs2ints = lambda x: x + # noinspection PyPep8 + str2octs = lambda x: x.encode('iso-8859-1') + # noinspection PyPep8 + octs2str = lambda x: x.decode('iso-8859-1') + # noinspection PyPep8 + isOctetsType = lambda s: isinstance(s, bytes) + # noinspection PyPep8 + isStringType = lambda s: isinstance(s, str) + # noinspection PyPep8 + ensureString = bytes diff --git a/Lambdas/Websocket Authorizer/pyasn1/compat/string.py b/Lambdas/Websocket Authorizer/pyasn1/compat/string.py new file mode 100644 index 0000000..b9bc8c3 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/compat/string.py @@ -0,0 +1,26 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from sys import version_info + +if version_info[:2] <= (2, 5): + + def partition(string, sep): + try: + a, c = string.split(sep, 1) + + except ValueError: + a, b, c = string, '', '' + + else: + b = sep + + return a, b, c + +else: + + def partition(string, sep): + return string.partition(sep) diff --git a/Lambdas/Websocket Authorizer/pyasn1/debug.py b/Lambdas/Websocket Authorizer/pyasn1/debug.py new file mode 100644 index 0000000..8707aa8 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/debug.py @@ -0,0 +1,157 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import logging +import sys + +from pyasn1 import __version__ +from pyasn1 import error +from pyasn1.compat.octets import octs2ints + +__all__ = ['Debug', 'setLogger', 'hexdump'] + +DEBUG_NONE = 0x0000 +DEBUG_ENCODER = 0x0001 +DEBUG_DECODER = 0x0002 +DEBUG_ALL = 0xffff + +FLAG_MAP = { + 'none': DEBUG_NONE, + 'encoder': DEBUG_ENCODER, + 'decoder': DEBUG_DECODER, + 'all': DEBUG_ALL +} + +LOGGEE_MAP = {} + + +class Printer(object): + # noinspection PyShadowingNames + def __init__(self, logger=None, handler=None, formatter=None): + if logger is None: + logger = logging.getLogger('pyasn1') + + logger.setLevel(logging.DEBUG) + + if handler is None: + handler = logging.StreamHandler() + + if formatter is None: + formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') + + handler.setFormatter(formatter) + handler.setLevel(logging.DEBUG) + logger.addHandler(handler) + + self.__logger = logger + + def __call__(self, msg): + self.__logger.debug(msg) + + def __str__(self): + return '' + + +if hasattr(logging, 'NullHandler'): + NullHandler = logging.NullHandler + +else: + # Python 2.6 and older + class NullHandler(logging.Handler): + def emit(self, record): + pass + + +class Debug(object): + defaultPrinter = Printer() + + def __init__(self, *flags, **options): + self._flags = DEBUG_NONE + + if 'loggerName' in options: + # route our logs to parent logger + self._printer = Printer( + logger=logging.getLogger(options['loggerName']), + handler=NullHandler() + ) + + elif 'printer' in options: + self._printer = options.get('printer') + + else: + self._printer = self.defaultPrinter + + self._printer('running pyasn1 %s, debug flags %s' % (__version__, ', '.join(flags))) + + for flag in flags: + inverse = flag and flag[0] in ('!', '~') + if inverse: + flag = flag[1:] + try: + if inverse: + self._flags &= ~FLAG_MAP[flag] + else: + self._flags |= FLAG_MAP[flag] + except KeyError: + raise error.PyAsn1Error('bad debug flag %s' % flag) + + self._printer("debug category '%s' %s" % (flag, inverse and 'disabled' or 'enabled')) + + def __str__(self): + return 'logger %s, flags %x' % (self._printer, self._flags) + + def __call__(self, msg): + self._printer(msg) + + def __and__(self, flag): + return self._flags & flag + + def __rand__(self, flag): + return flag & self._flags + +_LOG = DEBUG_NONE + + +def setLogger(userLogger): + global _LOG + + if userLogger: + _LOG = userLogger + else: + _LOG = DEBUG_NONE + + # Update registered logging clients + for module, (name, flags) in LOGGEE_MAP.items(): + setattr(module, name, _LOG & flags and _LOG or DEBUG_NONE) + + +def registerLoggee(module, name='LOG', flags=DEBUG_NONE): + LOGGEE_MAP[sys.modules[module]] = name, flags + setLogger(_LOG) + return _LOG + + +def hexdump(octets): + return ' '.join( + ['%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x) + for n, x in zip(range(len(octets)), octs2ints(octets))] + ) + + +class Scope(object): + def __init__(self): + self._list = [] + + def __str__(self): return '.'.join(self._list) + + def push(self, token): + self._list.append(token) + + def pop(self): + return self._list.pop() + + +scope = Scope() diff --git a/Lambdas/Websocket Authorizer/pyasn1/error.py b/Lambdas/Websocket Authorizer/pyasn1/error.py new file mode 100644 index 0000000..4f48db2 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/error.py @@ -0,0 +1,75 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# + + +class PyAsn1Error(Exception): + """Base pyasn1 exception + + `PyAsn1Error` is the base exception class (based on + :class:`Exception`) that represents all possible ASN.1 related + errors. + """ + + +class ValueConstraintError(PyAsn1Error): + """ASN.1 type constraints violation exception + + The `ValueConstraintError` exception indicates an ASN.1 value + constraint violation. + + It might happen on value object instantiation (for scalar types) or on + serialization (for constructed types). + """ + + +class SubstrateUnderrunError(PyAsn1Error): + """ASN.1 data structure deserialization error + + The `SubstrateUnderrunError` exception indicates insufficient serialised + data on input of a de-serialization codec. + """ + + +class PyAsn1UnicodeError(PyAsn1Error, UnicodeError): + """Unicode text processing error + + The `PyAsn1UnicodeError` exception is a base class for errors relating to + unicode text de/serialization. + + Apart from inheriting from :class:`PyAsn1Error`, it also inherits from + :class:`UnicodeError` to help the caller catching unicode-related errors. + """ + def __init__(self, message, unicode_error=None): + if isinstance(unicode_error, UnicodeError): + UnicodeError.__init__(self, *unicode_error.args) + PyAsn1Error.__init__(self, message) + + +class PyAsn1UnicodeDecodeError(PyAsn1UnicodeError, UnicodeDecodeError): + """Unicode text decoding error + + The `PyAsn1UnicodeDecodeError` exception represents a failure to + deserialize unicode text. + + Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits + from :class:`UnicodeDecodeError` to help the caller catching unicode-related + errors. + """ + + +class PyAsn1UnicodeEncodeError(PyAsn1UnicodeError, UnicodeEncodeError): + """Unicode text encoding error + + The `PyAsn1UnicodeEncodeError` exception represents a failure to + serialize unicode text. + + Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits + from :class:`UnicodeEncodeError` to help the caller catching + unicode-related errors. + """ + + diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/__init__.py b/Lambdas/Websocket Authorizer/pyasn1/type/__init__.py new file mode 100644 index 0000000..8c3066b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/base.py b/Lambdas/Websocket Authorizer/pyasn1/type/base.py new file mode 100644 index 0000000..994f1c9 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/base.py @@ -0,0 +1,707 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import error +from pyasn1.compat import calling +from pyasn1.type import constraint +from pyasn1.type import tag +from pyasn1.type import tagmap + +__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type', + 'ConstructedAsn1Type'] + + +class Asn1Item(object): + @classmethod + def getTypeId(cls, increment=1): + try: + Asn1Item._typeCounter += increment + except AttributeError: + Asn1Item._typeCounter = increment + return Asn1Item._typeCounter + + +class Asn1Type(Asn1Item): + """Base class for all classes representing ASN.1 types. + + In the user code, |ASN.1| class is normally used only for telling + ASN.1 objects from others. + + Note + ---- + For as long as ASN.1 is concerned, a way to compare ASN.1 types + is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. + """ + #: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing + #: ASN.1 tag(s) associated with |ASN.1| type. + tagSet = tag.TagSet() + + #: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + #: object imposing constraints on initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = None + + def __init__(self, **kwargs): + readOnly = { + 'tagSet': self.tagSet, + 'subtypeSpec': self.subtypeSpec + } + + readOnly.update(kwargs) + + self.__dict__.update(readOnly) + + self._readOnly = readOnly + + def __setattr__(self, name, value): + if name[0] != '_' and name in self._readOnly: + raise error.PyAsn1Error('read-only instance attribute "%s"' % name) + + self.__dict__[name] = value + + def __str__(self): + return self.prettyPrint() + + @property + def readOnly(self): + return self._readOnly + + @property + def effectiveTagSet(self): + """For |ASN.1| type is equivalent to *tagSet* + """ + return self.tagSet # used by untagged types + + @property + def tagMap(self): + """Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object. + """ + return tagmap.TagMap({self.tagSet: self}) + + def isSameTypeWith(self, other, matchTags=True, matchConstraints=True): + """Examine |ASN.1| type for equality with other ASN.1 type. + + ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints + (:py:mod:`~pyasn1.type.constraint`) are examined when carrying + out ASN.1 types comparison. + + Python class inheritance relationship is NOT considered. + + Parameters + ---------- + other: a pyasn1 type object + Class instance representing ASN.1 type. + + Returns + ------- + : :class:`bool` + :obj:`True` if *other* is |ASN.1| type, + :obj:`False` otherwise. + """ + return (self is other or + (not matchTags or self.tagSet == other.tagSet) and + (not matchConstraints or self.subtypeSpec == other.subtypeSpec)) + + def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True): + """Examine |ASN.1| type for subtype relationship with other ASN.1 type. + + ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints + (:py:mod:`~pyasn1.type.constraint`) are examined when carrying + out ASN.1 types comparison. + + Python class inheritance relationship is NOT considered. + + Parameters + ---------- + other: a pyasn1 type object + Class instance representing ASN.1 type. + + Returns + ------- + : :class:`bool` + :obj:`True` if *other* is a subtype of |ASN.1| type, + :obj:`False` otherwise. + """ + return (not matchTags or + (self.tagSet.isSuperTagSetOf(other.tagSet)) and + (not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec))) + + @staticmethod + def isNoValue(*values): + for value in values: + if value is not noValue: + return False + return True + + def prettyPrint(self, scope=0): + raise NotImplementedError() + + # backward compatibility + + def getTagSet(self): + return self.tagSet + + def getEffectiveTagSet(self): + return self.effectiveTagSet + + def getTagMap(self): + return self.tagMap + + def getSubtypeSpec(self): + return self.subtypeSpec + + # backward compatibility + def hasValue(self): + return self.isValue + +# Backward compatibility +Asn1ItemBase = Asn1Type + + +class NoValue(object): + """Create a singleton instance of NoValue class. + + The *NoValue* sentinel object represents an instance of ASN.1 schema + object as opposed to ASN.1 value object. + + Only ASN.1 schema-related operations can be performed on ASN.1 + schema objects. + + Warning + ------- + Any operation attempted on the *noValue* object will raise the + *PyAsn1Error* exception. + """ + skipMethods = set( + ('__slots__', + # attributes + '__getattribute__', + '__getattr__', + '__setattr__', + '__delattr__', + # class instance + '__class__', + '__init__', + '__del__', + '__new__', + '__repr__', + '__qualname__', + '__objclass__', + 'im_class', + '__sizeof__', + # pickle protocol + '__reduce__', + '__reduce_ex__', + '__getnewargs__', + '__getinitargs__', + '__getstate__', + '__setstate__') + ) + + _instance = None + + def __new__(cls): + if cls._instance is None: + def getPlug(name): + def plug(self, *args, **kw): + raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name) + return plug + + op_names = [name + for typ in (str, int, list, dict) + for name in dir(typ) + if (name not in cls.skipMethods and + name.startswith('__') and + name.endswith('__') and + calling.callable(getattr(typ, name)))] + + for name in set(op_names): + setattr(cls, name, getPlug(name)) + + cls._instance = object.__new__(cls) + + return cls._instance + + def __getattr__(self, attr): + if attr in self.skipMethods: + raise AttributeError('Attribute %s not present' % attr) + + raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr) + + def __repr__(self): + return '<%s object>' % self.__class__.__name__ + + +noValue = NoValue() + + +class SimpleAsn1Type(Asn1Type): + """Base class for all simple classes representing ASN.1 types. + + ASN.1 distinguishes types by their ability to hold other objects. + Scalar types are known as *simple* in ASN.1. + + In the user code, |ASN.1| class is normally used only for telling + ASN.1 objects from others. + + Note + ---- + For as long as ASN.1 is concerned, a way to compare ASN.1 types + is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. + """ + #: Default payload value + defaultValue = noValue + + def __init__(self, value=noValue, **kwargs): + Asn1Type.__init__(self, **kwargs) + if value is noValue: + value = self.defaultValue + else: + value = self.prettyIn(value) + try: + self.subtypeSpec(value) + + except error.PyAsn1Error: + exType, exValue, exTb = sys.exc_info() + raise exType('%s at %s' % (exValue, self.__class__.__name__)) + + self._value = value + + def __repr__(self): + representation = '%s %s object' % ( + self.__class__.__name__, self.isValue and 'value' or 'schema') + + for attr, value in self.readOnly.items(): + if value: + representation += ', %s %s' % (attr, value) + + if self.isValue: + value = self.prettyPrint() + if len(value) > 32: + value = value[:16] + '...' + value[-16:] + representation += ', payload [%s]' % value + + return '<%s>' % representation + + def __eq__(self, other): + return self is other and True or self._value == other + + def __ne__(self, other): + return self._value != other + + def __lt__(self, other): + return self._value < other + + def __le__(self, other): + return self._value <= other + + def __gt__(self, other): + return self._value > other + + def __ge__(self, other): + return self._value >= other + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self._value and True or False + else: + def __bool__(self): + return self._value and True or False + + def __hash__(self): + return hash(self._value) + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just + ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema + features, this object can also be used like a Python built-in object + (e.g. :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a normal value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + """ + return self._value is not noValue + + def clone(self, value=noValue, **kwargs): + """Create a modified version of |ASN.1| schema or value object. + + The `clone()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all arguments + of the `clone()` method are optional. + + Whatever arguments are supplied, they are used to create a copy + of `self` taking precedence over the ones used to instantiate `self`. + + Note + ---- + Due to the immutable nature of the |ASN.1| object, if no arguments + are supplied, no new |ASN.1| object will be created and `self` will + be returned instead. + """ + if value is noValue: + if not kwargs: + return self + + value = self._value + + initializers = self.readOnly.copy() + initializers.update(kwargs) + + return self.__class__(value, **initializers) + + def subtype(self, value=noValue, **kwargs): + """Create a specialization of |ASN.1| schema or value object. + + The subtype relationship between ASN.1 types has no correlation with + subtype relationship between Python types. ASN.1 type is mainly identified + by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range + constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`). + These ASN.1 type properties are implemented as |ASN.1| attributes. + + The `subtype()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all parameters + of the `subtype()` method are optional. + + With the exception of the arguments described below, the rest of + supplied arguments they are used to create a copy of `self` taking + precedence over the ones used to instantiate `self`. + + The following arguments to `subtype()` create a ASN.1 subtype out of + |ASN.1| type: + + Other Parameters + ---------------- + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the `self`'s, then + use the result as new object's ASN.1 constraints. + + Returns + ------- + : + new instance of |ASN.1| schema or value object + + Note + ---- + Due to the immutable nature of the |ASN.1| object, if no arguments + are supplied, no new |ASN.1| object will be created and `self` will + be returned instead. + """ + if value is noValue: + if not kwargs: + return self + + value = self._value + + initializers = self.readOnly.copy() + + implicitTag = kwargs.pop('implicitTag', None) + if implicitTag is not None: + initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) + + explicitTag = kwargs.pop('explicitTag', None) + if explicitTag is not None: + initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) + + for arg, option in kwargs.items(): + initializers[arg] += option + + return self.__class__(value, **initializers) + + def prettyIn(self, value): + return value + + def prettyOut(self, value): + return str(value) + + def prettyPrint(self, scope=0): + return self.prettyOut(self._value) + + def prettyPrintType(self, scope=0): + return '%s -> %s' % (self.tagSet, self.__class__.__name__) + +# Backward compatibility +AbstractSimpleAsn1Item = SimpleAsn1Type + +# +# Constructed types: +# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice +# * ASN1 types and values are represened by Python class instances +# * Value initialization is made for defaulted components only +# * Primary method of component addressing is by-position. Data model for base +# type is Python sequence. Additional type-specific addressing methods +# may be implemented for particular types. +# * SequenceOf and SetOf types do not implement any additional methods +# * Sequence, Set and Choice types also implement by-identifier addressing +# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing +# * Sequence and Set types may include optional and defaulted +# components +# * Constructed types hold a reference to component types used for value +# verification and ordering. +# * Component type is a scalar type for SequenceOf/SetOf types and a list +# of types for Sequence/Set/Choice. +# + + +class ConstructedAsn1Type(Asn1Type): + """Base class for all constructed classes representing ASN.1 types. + + ASN.1 distinguishes types by their ability to hold other objects. + Those "nesting" types are known as *constructed* in ASN.1. + + In the user code, |ASN.1| class is normally used only for telling + ASN.1 objects from others. + + Note + ---- + For as long as ASN.1 is concerned, a way to compare ASN.1 types + is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods. + """ + + #: If :obj:`True`, requires exact component type matching, + #: otherwise subtype relation is only enforced + strictConstraints = False + + componentType = None + + # backward compatibility, unused + sizeSpec = constraint.ConstraintsIntersection() + + def __init__(self, **kwargs): + readOnly = { + 'componentType': self.componentType, + # backward compatibility, unused + 'sizeSpec': self.sizeSpec + } + + # backward compatibility: preserve legacy sizeSpec support + kwargs = self._moveSizeSpec(**kwargs) + + readOnly.update(kwargs) + + Asn1Type.__init__(self, **readOnly) + + def _moveSizeSpec(self, **kwargs): + # backward compatibility, unused + sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec) + if sizeSpec: + subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec) + if subtypeSpec: + subtypeSpec = sizeSpec + + else: + subtypeSpec += sizeSpec + + kwargs['subtypeSpec'] = subtypeSpec + + return kwargs + + def __repr__(self): + representation = '%s %s object' % ( + self.__class__.__name__, self.isValue and 'value' or 'schema' + ) + + for attr, value in self.readOnly.items(): + if value is not noValue: + representation += ', %s=%r' % (attr, value) + + if self.isValue and self.components: + representation += ', payload [%s]' % ', '.join( + [repr(x) for x in self.components]) + + return '<%s>' % representation + + def __eq__(self, other): + return self is other or self.components == other + + def __ne__(self, other): + return self.components != other + + def __lt__(self, other): + return self.components < other + + def __le__(self, other): + return self.components <= other + + def __gt__(self, other): + return self.components > other + + def __ge__(self, other): + return self.components >= other + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return bool(self.components) + else: + def __bool__(self): + return bool(self.components) + + @property + def components(self): + raise error.PyAsn1Error('Method not implemented') + + def _cloneComponentValues(self, myClone, cloneValueFlag): + pass + + def clone(self, **kwargs): + """Create a modified version of |ASN.1| schema object. + + The `clone()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all arguments + of the `clone()` method are optional. + + Whatever arguments are supplied, they are used to create a copy + of `self` taking precedence over the ones used to instantiate `self`. + + Possible values of `self` are never copied over thus `clone()` can + only create a new schema object. + + Returns + ------- + : + new instance of |ASN.1| type/value + + Note + ---- + Due to the mutable nature of the |ASN.1| object, even if no arguments + are supplied, a new |ASN.1| object will be created and returned. + """ + cloneValueFlag = kwargs.pop('cloneValueFlag', False) + + initializers = self.readOnly.copy() + initializers.update(kwargs) + + clone = self.__class__(**initializers) + + if cloneValueFlag: + self._cloneComponentValues(clone, cloneValueFlag) + + return clone + + def subtype(self, **kwargs): + """Create a specialization of |ASN.1| schema object. + + The `subtype()` method accepts the same set arguments as |ASN.1| + class takes on instantiation except that all parameters + of the `subtype()` method are optional. + + With the exception of the arguments described below, the rest of + supplied arguments they are used to create a copy of `self` taking + precedence over the ones used to instantiate `self`. + + The following arguments to `subtype()` create a ASN.1 subtype out of + |ASN.1| type. + + Other Parameters + ---------------- + implicitTag: :py:class:`~pyasn1.type.tag.Tag` + Implicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + explicitTag: :py:class:`~pyasn1.type.tag.Tag` + Explicitly apply given ASN.1 tag object to `self`'s + :py:class:`~pyasn1.type.tag.TagSet`, then use the result as + new object's ASN.1 tag(s). + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Add ASN.1 constraints object to one of the `self`'s, then + use the result as new object's ASN.1 constraints. + + + Returns + ------- + : + new instance of |ASN.1| type/value + + Note + ---- + Due to the mutable nature of the |ASN.1| object, even if no arguments + are supplied, a new |ASN.1| object will be created and returned. + """ + + initializers = self.readOnly.copy() + + cloneValueFlag = kwargs.pop('cloneValueFlag', False) + + implicitTag = kwargs.pop('implicitTag', None) + if implicitTag is not None: + initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag) + + explicitTag = kwargs.pop('explicitTag', None) + if explicitTag is not None: + initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag) + + for arg, option in kwargs.items(): + initializers[arg] += option + + clone = self.__class__(**initializers) + + if cloneValueFlag: + self._cloneComponentValues(clone, cloneValueFlag) + + return clone + + def getComponentByPosition(self, idx): + raise error.PyAsn1Error('Method not implemented') + + def setComponentByPosition(self, idx, value, verifyConstraints=True): + raise error.PyAsn1Error('Method not implemented') + + def setComponents(self, *args, **kwargs): + for idx, value in enumerate(args): + self[idx] = value + for k in kwargs: + self[k] = kwargs[k] + return self + + # backward compatibility + + def setDefaultComponents(self): + pass + + def getComponentType(self): + return self.componentType + + # backward compatibility, unused + def verifySizeSpec(self): + self.subtypeSpec(self) + + + # Backward compatibility +AbstractConstructedAsn1Item = ConstructedAsn1Type diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/char.py b/Lambdas/Websocket Authorizer/pyasn1/type/char.py new file mode 100644 index 0000000..06074da --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/char.py @@ -0,0 +1,335 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import error +from pyasn1.type import tag +from pyasn1.type import univ + +__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString', + 'IA5String', 'GraphicString', 'VisibleString', 'ISO646String', + 'GeneralString', 'UniversalString', 'BMPString', 'UTF8String'] + +NoValue = univ.NoValue +noValue = univ.noValue + + +class AbstractCharacterString(univ.OctetString): + """Creates |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, + its objects are immutable and duck-type Python 2 :class:`str` or Python 3 + :class:`bytes`. When used in octet-stream context, |ASN.1| type assumes + "|encoding|" encoding. + + Keyword Args + ------------ + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + :class:`unicode` object (Python 2) or :class:`str` (Python 3), + alternatively :class:`str` (Python 2) or :class:`bytes` (Python 3) + representing octet-stream of serialised unicode string + (note `encoding` parameter) or |ASN.1| class instance. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in octet-stream context. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + """ + + if sys.version_info[0] <= 2: + def __str__(self): + try: + # `str` is Py2 text representation + return self._value.encode(self.encoding) + + except UnicodeEncodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with codec " + "%s" % (self._value, self.encoding), exc + ) + + def __unicode__(self): + return unicode(self._value) + + def prettyIn(self, value): + try: + if isinstance(value, unicode): + return value + elif isinstance(value, str): + return value.decode(self.encoding) + elif isinstance(value, (tuple, list)): + return self.prettyIn(''.join([chr(x) for x in value])) + elif isinstance(value, univ.OctetString): + return value.asOctets().decode(self.encoding) + else: + return unicode(value) + + except (UnicodeDecodeError, LookupError): + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with codec " + "%s" % (value, self.encoding), exc + ) + + def asOctets(self, padding=True): + return str(self) + + def asNumbers(self, padding=True): + return tuple([ord(x) for x in str(self)]) + + else: + def __str__(self): + # `unicode` is Py3 text representation + return str(self._value) + + def __bytes__(self): + try: + return self._value.encode(self.encoding) + except UnicodeEncodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with codec " + "%s" % (self._value, self.encoding), exc + ) + + def prettyIn(self, value): + try: + if isinstance(value, str): + return value + elif isinstance(value, bytes): + return value.decode(self.encoding) + elif isinstance(value, (tuple, list)): + return self.prettyIn(bytes(value)) + elif isinstance(value, univ.OctetString): + return value.asOctets().decode(self.encoding) + else: + return str(value) + + except (UnicodeDecodeError, LookupError): + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with codec " + "%s" % (value, self.encoding), exc + ) + + def asOctets(self, padding=True): + return bytes(self) + + def asNumbers(self, padding=True): + return tuple(bytes(self)) + + # + # See OctetString.prettyPrint() for the explanation + # + + def prettyOut(self, value): + return value + + def prettyPrint(self, scope=0): + # first see if subclass has its own .prettyOut() + value = self.prettyOut(self._value) + + if value is not self._value: + return value + + return AbstractCharacterString.__str__(self) + + def __reversed__(self): + return reversed(self._value) + + +class NumericString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class PrintableString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class TeletexString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class T61String(TeletexString): + __doc__ = TeletexString.__doc__ + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class VideotexString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class IA5String(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class GraphicString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class VisibleString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26) + ) + encoding = 'us-ascii' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class ISO646String(VisibleString): + __doc__ = VisibleString.__doc__ + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + +class GeneralString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27) + ) + encoding = 'iso-8859-1' + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class UniversalString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28) + ) + encoding = "utf-32-be" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class BMPString(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30) + ) + encoding = "utf-16-be" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() + + +class UTF8String(AbstractCharacterString): + __doc__ = AbstractCharacterString.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = AbstractCharacterString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12) + ) + encoding = "utf-8" + + # Optimization for faster codec lookup + typeId = AbstractCharacterString.getTypeId() diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/constraint.py b/Lambdas/Websocket Authorizer/pyasn1/type/constraint.py new file mode 100644 index 0000000..b66627d --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/constraint.py @@ -0,0 +1,702 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +# Original concept and code by Mike C. Fletcher. +# +import sys + +from pyasn1.type import error + +__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint', + 'ValueRangeConstraint', 'ValueSizeConstraint', + 'PermittedAlphabetConstraint', 'InnerTypeConstraint', + 'ConstraintsExclusion', 'ConstraintsIntersection', + 'ConstraintsUnion'] + + +class AbstractConstraint(object): + + def __init__(self, *values): + self._valueMap = set() + self._setValues(values) + self.__hash = hash((self.__class__.__name__, self._values)) + + def __call__(self, value, idx=None): + if not self._values: + return + + try: + self._testValue(value, idx) + + except error.ValueConstraintError: + raise error.ValueConstraintError( + '%s failed at: %r' % (self, sys.exc_info()[1]) + ) + + def __repr__(self): + representation = '%s object' % (self.__class__.__name__) + + if self._values: + representation += ', consts %s' % ', '.join( + [repr(x) for x in self._values]) + + return '<%s>' % representation + + def __eq__(self, other): + return self is other and True or self._values == other + + def __ne__(self, other): + return self._values != other + + def __lt__(self, other): + return self._values < other + + def __le__(self, other): + return self._values <= other + + def __gt__(self, other): + return self._values > other + + def __ge__(self, other): + return self._values >= other + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self._values and True or False + else: + def __bool__(self): + return self._values and True or False + + def __hash__(self): + return self.__hash + + def _setValues(self, values): + self._values = values + + def _testValue(self, value, idx): + raise error.ValueConstraintError(value) + + # Constraints derivation logic + def getValueMap(self): + return self._valueMap + + def isSuperTypeOf(self, otherConstraint): + # TODO: fix possible comparison of set vs scalars here + return (otherConstraint is self or + not self._values or + otherConstraint == self or + self in otherConstraint.getValueMap()) + + def isSubTypeOf(self, otherConstraint): + return (otherConstraint is self or + not self or + otherConstraint == self or + otherConstraint in self._valueMap) + + +class SingleValueConstraint(AbstractConstraint): + """Create a SingleValueConstraint object. + + The SingleValueConstraint satisfies any value that + is present in the set of permitted values. + + The SingleValueConstraint object can be applied to + any ASN.1 type. + + Parameters + ---------- + *values: :class:`int` + Full set of values permitted by this constraint object. + + Examples + -------- + .. code-block:: python + + class DivisorOfSix(Integer): + ''' + ASN.1 specification: + + Divisor-Of-6 ::= INTEGER (1 | 2 | 3 | 6) + ''' + subtypeSpec = SingleValueConstraint(1, 2, 3, 6) + + # this will succeed + divisor_of_six = DivisorOfSix(1) + + # this will raise ValueConstraintError + divisor_of_six = DivisorOfSix(7) + """ + def _setValues(self, values): + self._values = values + self._set = set(values) + + def _testValue(self, value, idx): + if value not in self._set: + raise error.ValueConstraintError(value) + + +class ContainedSubtypeConstraint(AbstractConstraint): + """Create a ContainedSubtypeConstraint object. + + The ContainedSubtypeConstraint satisfies any value that + is present in the set of permitted values and also + satisfies included constraints. + + The ContainedSubtypeConstraint object can be applied to + any ASN.1 type. + + Parameters + ---------- + *values: + Full set of values and constraint objects permitted + by this constraint object. + + Examples + -------- + .. code-block:: python + + class DivisorOfEighteen(Integer): + ''' + ASN.1 specification: + + Divisors-of-18 ::= INTEGER (INCLUDES Divisors-of-6 | 9 | 18) + ''' + subtypeSpec = ContainedSubtypeConstraint( + SingleValueConstraint(1, 2, 3, 6), 9, 18 + ) + + # this will succeed + divisor_of_eighteen = DivisorOfEighteen(9) + + # this will raise ValueConstraintError + divisor_of_eighteen = DivisorOfEighteen(10) + """ + def _testValue(self, value, idx): + for constraint in self._values: + if isinstance(constraint, AbstractConstraint): + constraint(value, idx) + elif value not in self._set: + raise error.ValueConstraintError(value) + + +class ValueRangeConstraint(AbstractConstraint): + """Create a ValueRangeConstraint object. + + The ValueRangeConstraint satisfies any value that + falls in the range of permitted values. + + The ValueRangeConstraint object can only be applied + to :class:`~pyasn1.type.univ.Integer` and + :class:`~pyasn1.type.univ.Real` types. + + Parameters + ---------- + start: :class:`int` + Minimum permitted value in the range (inclusive) + + end: :class:`int` + Maximum permitted value in the range (inclusive) + + Examples + -------- + .. code-block:: python + + class TeenAgeYears(Integer): + ''' + ASN.1 specification: + + TeenAgeYears ::= INTEGER (13 .. 19) + ''' + subtypeSpec = ValueRangeConstraint(13, 19) + + # this will succeed + teen_year = TeenAgeYears(18) + + # this will raise ValueConstraintError + teen_year = TeenAgeYears(20) + """ + def _testValue(self, value, idx): + if value < self.start or value > self.stop: + raise error.ValueConstraintError(value) + + def _setValues(self, values): + if len(values) != 2: + raise error.PyAsn1Error( + '%s: bad constraint values' % (self.__class__.__name__,) + ) + self.start, self.stop = values + if self.start > self.stop: + raise error.PyAsn1Error( + '%s: screwed constraint values (start > stop): %s > %s' % ( + self.__class__.__name__, + self.start, self.stop + ) + ) + AbstractConstraint._setValues(self, values) + + +class ValueSizeConstraint(ValueRangeConstraint): + """Create a ValueSizeConstraint object. + + The ValueSizeConstraint satisfies any value for + as long as its size falls within the range of + permitted sizes. + + The ValueSizeConstraint object can be applied + to :class:`~pyasn1.type.univ.BitString`, + :class:`~pyasn1.type.univ.OctetString` (including + all :ref:`character ASN.1 types `), + :class:`~pyasn1.type.univ.SequenceOf` + and :class:`~pyasn1.type.univ.SetOf` types. + + Parameters + ---------- + minimum: :class:`int` + Minimum permitted size of the value (inclusive) + + maximum: :class:`int` + Maximum permitted size of the value (inclusive) + + Examples + -------- + .. code-block:: python + + class BaseballTeamRoster(SetOf): + ''' + ASN.1 specification: + + BaseballTeamRoster ::= SET SIZE (1..25) OF PlayerNames + ''' + componentType = PlayerNames() + subtypeSpec = ValueSizeConstraint(1, 25) + + # this will succeed + team = BaseballTeamRoster() + team.extend(['Jan', 'Matej']) + encode(team) + + # this will raise ValueConstraintError + team = BaseballTeamRoster() + team.extend(['Jan'] * 26) + encode(team) + + Note + ---- + Whenever ValueSizeConstraint is applied to mutable types + (e.g. :class:`~pyasn1.type.univ.SequenceOf`, + :class:`~pyasn1.type.univ.SetOf`), constraint + validation only happens at the serialisation phase rather + than schema instantiation phase (as it is with immutable + types). + """ + def _testValue(self, value, idx): + valueSize = len(value) + if valueSize < self.start or valueSize > self.stop: + raise error.ValueConstraintError(value) + + +class PermittedAlphabetConstraint(SingleValueConstraint): + """Create a PermittedAlphabetConstraint object. + + The PermittedAlphabetConstraint satisfies any character + string for as long as all its characters are present in + the set of permitted characters. + + The PermittedAlphabetConstraint object can only be applied + to the :ref:`character ASN.1 types ` such as + :class:`~pyasn1.type.char.IA5String`. + + Parameters + ---------- + *alphabet: :class:`str` + Full set of characters permitted by this constraint object. + + Examples + -------- + .. code-block:: python + + class BooleanValue(IA5String): + ''' + ASN.1 specification: + + BooleanValue ::= IA5String (FROM ('T' | 'F')) + ''' + subtypeSpec = PermittedAlphabetConstraint('T', 'F') + + # this will succeed + truth = BooleanValue('T') + truth = BooleanValue('TF') + + # this will raise ValueConstraintError + garbage = BooleanValue('TAF') + """ + def _setValues(self, values): + self._values = values + self._set = set(values) + + def _testValue(self, value, idx): + if not self._set.issuperset(value): + raise error.ValueConstraintError(value) + + +class ComponentPresentConstraint(AbstractConstraint): + """Create a ComponentPresentConstraint object. + + The ComponentPresentConstraint is only satisfied when the value + is not `None`. + + The ComponentPresentConstraint object is typically used with + `WithComponentsConstraint`. + + Examples + -------- + .. code-block:: python + + present = ComponentPresentConstraint() + + # this will succeed + present('whatever') + + # this will raise ValueConstraintError + present(None) + """ + def _setValues(self, values): + self._values = ('',) + + if values: + raise error.PyAsn1Error('No arguments expected') + + def _testValue(self, value, idx): + if value is None: + raise error.ValueConstraintError( + 'Component is not present:') + + +class ComponentAbsentConstraint(AbstractConstraint): + """Create a ComponentAbsentConstraint object. + + The ComponentAbsentConstraint is only satisfied when the value + is `None`. + + The ComponentAbsentConstraint object is typically used with + `WithComponentsConstraint`. + + Examples + -------- + .. code-block:: python + + absent = ComponentAbsentConstraint() + + # this will succeed + absent(None) + + # this will raise ValueConstraintError + absent('whatever') + """ + def _setValues(self, values): + self._values = ('',) + + if values: + raise error.PyAsn1Error('No arguments expected') + + def _testValue(self, value, idx): + if value is not None: + raise error.ValueConstraintError( + 'Component is not absent: %r' % value) + + +class WithComponentsConstraint(AbstractConstraint): + """Create a WithComponentsConstraint object. + + The `WithComponentsConstraint` satisfies any mapping object that has + constrained fields present or absent, what is indicated by + `ComponentPresentConstraint` and `ComponentAbsentConstraint` + objects respectively. + + The `WithComponentsConstraint` object is typically applied + to :class:`~pyasn1.type.univ.Set` or + :class:`~pyasn1.type.univ.Sequence` types. + + Parameters + ---------- + *fields: :class:`tuple` + Zero or more tuples of (`field`, `constraint`) indicating constrained + fields. + + Notes + ----- + On top of the primary use of `WithComponentsConstraint` (ensuring presence + or absence of particular components of a :class:`~pyasn1.type.univ.Set` or + :class:`~pyasn1.type.univ.Sequence`), it is also possible to pass any other + constraint objects or their combinations. In case of scalar fields, these + constraints will be verified in addition to the constraints belonging to + scalar components themselves. However, formally, these additional + constraints do not change the type of these ASN.1 objects. + + Examples + -------- + + .. code-block:: python + + class Item(Sequence): # Set is similar + ''' + ASN.1 specification: + + Item ::= SEQUENCE { + id INTEGER OPTIONAL, + name OCTET STRING OPTIONAL + } WITH COMPONENTS id PRESENT, name ABSENT | id ABSENT, name PRESENT + ''' + componentType = NamedTypes( + OptionalNamedType('id', Integer()), + OptionalNamedType('name', OctetString()) + ) + withComponents = ConstraintsUnion( + WithComponentsConstraint( + ('id', ComponentPresentConstraint()), + ('name', ComponentAbsentConstraint()) + ), + WithComponentsConstraint( + ('id', ComponentAbsentConstraint()), + ('name', ComponentPresentConstraint()) + ) + ) + + item = Item() + + # This will succeed + item['id'] = 1 + + # This will succeed + item.reset() + item['name'] = 'John' + + # This will fail (on encoding) + item.reset() + descr['id'] = 1 + descr['name'] = 'John' + """ + def _testValue(self, value, idx): + for field, constraint in self._values: + constraint(value.get(field)) + + def _setValues(self, values): + AbstractConstraint._setValues(self, values) + + +# This is a bit kludgy, meaning two op modes within a single constraint +class InnerTypeConstraint(AbstractConstraint): + """Value must satisfy the type and presence constraints""" + + def _testValue(self, value, idx): + if self.__singleTypeConstraint: + self.__singleTypeConstraint(value) + elif self.__multipleTypeConstraint: + if idx not in self.__multipleTypeConstraint: + raise error.ValueConstraintError(value) + constraint, status = self.__multipleTypeConstraint[idx] + if status == 'ABSENT': # XXX presence is not checked! + raise error.ValueConstraintError(value) + constraint(value) + + def _setValues(self, values): + self.__multipleTypeConstraint = {} + self.__singleTypeConstraint = None + for v in values: + if isinstance(v, tuple): + self.__multipleTypeConstraint[v[0]] = v[1], v[2] + else: + self.__singleTypeConstraint = v + AbstractConstraint._setValues(self, values) + + +# Logic operations on constraints + +class ConstraintsExclusion(AbstractConstraint): + """Create a ConstraintsExclusion logic operator object. + + The ConstraintsExclusion logic operator succeeds when the + value does *not* satisfy the operand constraint. + + The ConstraintsExclusion object can be applied to + any constraint and logic operator object. + + Parameters + ---------- + constraint: + Constraint or logic operator object. + + Examples + -------- + .. code-block:: python + + class Lipogramme(IA5STRING): + ''' + ASN.1 specification: + + Lipogramme ::= + IA5String (FROM (ALL EXCEPT ("e"|"E"))) + ''' + subtypeSpec = ConstraintsExclusion( + PermittedAlphabetConstraint('e', 'E') + ) + + # this will succeed + lipogramme = Lipogramme('A work of fiction?') + + # this will raise ValueConstraintError + lipogramme = Lipogramme('Eel') + + Warning + ------- + The above example involving PermittedAlphabetConstraint might + not work due to the way how PermittedAlphabetConstraint works. + The other constraints might work with ConstraintsExclusion + though. + """ + def _testValue(self, value, idx): + try: + self._values[0](value, idx) + except error.ValueConstraintError: + return + else: + raise error.ValueConstraintError(value) + + def _setValues(self, values): + if len(values) != 1: + raise error.PyAsn1Error('Single constraint expected') + + AbstractConstraint._setValues(self, values) + + +class AbstractConstraintSet(AbstractConstraint): + + def __getitem__(self, idx): + return self._values[idx] + + def __iter__(self): + return iter(self._values) + + def __add__(self, value): + return self.__class__(*(self._values + (value,))) + + def __radd__(self, value): + return self.__class__(*((value,) + self._values)) + + def __len__(self): + return len(self._values) + + # Constraints inclusion in sets + + def _setValues(self, values): + self._values = values + for constraint in values: + if constraint: + self._valueMap.add(constraint) + self._valueMap.update(constraint.getValueMap()) + + +class ConstraintsIntersection(AbstractConstraintSet): + """Create a ConstraintsIntersection logic operator object. + + The ConstraintsIntersection logic operator only succeeds + if *all* its operands succeed. + + The ConstraintsIntersection object can be applied to + any constraint and logic operator objects. + + The ConstraintsIntersection object duck-types the immutable + container object like Python :py:class:`tuple`. + + Parameters + ---------- + *constraints: + Constraint or logic operator objects. + + Examples + -------- + .. code-block:: python + + class CapitalAndSmall(IA5String): + ''' + ASN.1 specification: + + CapitalAndSmall ::= + IA5String (FROM ("A".."Z"|"a".."z")) + ''' + subtypeSpec = ConstraintsIntersection( + PermittedAlphabetConstraint('A', 'Z'), + PermittedAlphabetConstraint('a', 'z') + ) + + # this will succeed + capital_and_small = CapitalAndSmall('Hello') + + # this will raise ValueConstraintError + capital_and_small = CapitalAndSmall('hello') + """ + def _testValue(self, value, idx): + for constraint in self._values: + constraint(value, idx) + + +class ConstraintsUnion(AbstractConstraintSet): + """Create a ConstraintsUnion logic operator object. + + The ConstraintsUnion logic operator succeeds if + *at least* a single operand succeeds. + + The ConstraintsUnion object can be applied to + any constraint and logic operator objects. + + The ConstraintsUnion object duck-types the immutable + container object like Python :py:class:`tuple`. + + Parameters + ---------- + *constraints: + Constraint or logic operator objects. + + Examples + -------- + .. code-block:: python + + class CapitalOrSmall(IA5String): + ''' + ASN.1 specification: + + CapitalOrSmall ::= + IA5String (FROM ("A".."Z") | FROM ("a".."z")) + ''' + subtypeSpec = ConstraintsUnion( + PermittedAlphabetConstraint('A', 'Z'), + PermittedAlphabetConstraint('a', 'z') + ) + + # this will succeed + capital_or_small = CapitalAndSmall('Hello') + + # this will raise ValueConstraintError + capital_or_small = CapitalOrSmall('hello!') + """ + def _testValue(self, value, idx): + for constraint in self._values: + try: + constraint(value, idx) + except error.ValueConstraintError: + pass + else: + return + + raise error.ValueConstraintError( + 'all of %s failed for "%s"' % (self._values, value) + ) + +# TODO: +# refactor InnerTypeConstraint +# add tests for type check +# implement other constraint types +# make constraint validation easy to skip diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/error.py b/Lambdas/Websocket Authorizer/pyasn1/type/error.py new file mode 100644 index 0000000..80fcf3b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/error.py @@ -0,0 +1,11 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1.error import PyAsn1Error + + +class ValueConstraintError(PyAsn1Error): + pass diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/namedtype.py b/Lambdas/Websocket Authorizer/pyasn1/type/namedtype.py new file mode 100644 index 0000000..cbc1429 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/namedtype.py @@ -0,0 +1,561 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1 import error +from pyasn1.type import tag +from pyasn1.type import tagmap + +__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType', + 'NamedTypes'] + +try: + any + +except NameError: + any = lambda x: bool(filter(bool, x)) + + +class NamedType(object): + """Create named field object for a constructed ASN.1 type. + + The |NamedType| object represents a single name and ASN.1 type of a constructed ASN.1 type. + + |NamedType| objects are immutable and duck-type Python :class:`tuple` objects + holding *name* and *asn1Object* components. + + Parameters + ---------- + name: :py:class:`str` + Field name + + asn1Object: + ASN.1 type object + """ + isOptional = False + isDefaulted = False + + def __init__(self, name, asn1Object, openType=None): + self.__name = name + self.__type = asn1Object + self.__nameAndType = name, asn1Object + self.__openType = openType + + def __repr__(self): + representation = '%s=%r' % (self.name, self.asn1Object) + + if self.openType: + representation += ', open type %r' % self.openType + + return '<%s object, type %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return self.__nameAndType == other + + def __ne__(self, other): + return self.__nameAndType != other + + def __lt__(self, other): + return self.__nameAndType < other + + def __le__(self, other): + return self.__nameAndType <= other + + def __gt__(self, other): + return self.__nameAndType > other + + def __ge__(self, other): + return self.__nameAndType >= other + + def __hash__(self): + return hash(self.__nameAndType) + + def __getitem__(self, idx): + return self.__nameAndType[idx] + + def __iter__(self): + return iter(self.__nameAndType) + + @property + def name(self): + return self.__name + + @property + def asn1Object(self): + return self.__type + + @property + def openType(self): + return self.__openType + + # Backward compatibility + + def getName(self): + return self.name + + def getType(self): + return self.asn1Object + + +class OptionalNamedType(NamedType): + __doc__ = NamedType.__doc__ + + isOptional = True + + +class DefaultedNamedType(NamedType): + __doc__ = NamedType.__doc__ + + isDefaulted = True + + +class NamedTypes(object): + """Create a collection of named fields for a constructed ASN.1 type. + + The NamedTypes object represents a collection of named fields of a constructed ASN.1 type. + + *NamedTypes* objects are immutable and duck-type Python :class:`dict` objects + holding *name* as keys and ASN.1 type object as values. + + Parameters + ---------- + *namedTypes: :class:`~pyasn1.type.namedtype.NamedType` + + Examples + -------- + + .. code-block:: python + + class Description(Sequence): + ''' + ASN.1 specification: + + Description ::= SEQUENCE { + surname IA5String, + first-name IA5String OPTIONAL, + age INTEGER DEFAULT 40 + } + ''' + componentType = NamedTypes( + NamedType('surname', IA5String()), + OptionalNamedType('first-name', IA5String()), + DefaultedNamedType('age', Integer(40)) + ) + + descr = Description() + descr['surname'] = 'Smith' + descr['first-name'] = 'John' + """ + def __init__(self, *namedTypes, **kwargs): + self.__namedTypes = namedTypes + self.__namedTypesLen = len(self.__namedTypes) + self.__minTagSet = self.__computeMinTagSet() + self.__nameToPosMap = self.__computeNameToPosMap() + self.__tagToPosMap = self.__computeTagToPosMap() + self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {} + self.__uniqueTagMap = self.__computeTagMaps(unique=True) + self.__nonUniqueTagMap = self.__computeTagMaps(unique=False) + self.__hasOptionalOrDefault = any([True for namedType in self.__namedTypes + if namedType.isDefaulted or namedType.isOptional]) + self.__hasOpenTypes = any([True for namedType in self.__namedTypes + if namedType.openType]) + + self.__requiredComponents = frozenset( + [idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted] + ) + self.__keys = frozenset([namedType.name for namedType in self.__namedTypes]) + self.__values = tuple([namedType.asn1Object for namedType in self.__namedTypes]) + self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes]) + + def __repr__(self): + representation = ', '.join(['%r' % x for x in self.__namedTypes]) + return '<%s object, types %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return self.__namedTypes == other + + def __ne__(self, other): + return self.__namedTypes != other + + def __lt__(self, other): + return self.__namedTypes < other + + def __le__(self, other): + return self.__namedTypes <= other + + def __gt__(self, other): + return self.__namedTypes > other + + def __ge__(self, other): + return self.__namedTypes >= other + + def __hash__(self): + return hash(self.__namedTypes) + + def __getitem__(self, idx): + try: + return self.__namedTypes[idx] + + except TypeError: + return self.__namedTypes[self.__nameToPosMap[idx]] + + def __contains__(self, key): + return key in self.__nameToPosMap + + def __iter__(self): + return (x[0] for x in self.__namedTypes) + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self.__namedTypesLen > 0 + else: + def __bool__(self): + return self.__namedTypesLen > 0 + + def __len__(self): + return self.__namedTypesLen + + # Python dict protocol + + def values(self): + return self.__values + + def keys(self): + return self.__keys + + def items(self): + return self.__items + + def clone(self): + return self.__class__(*self.__namedTypes) + + class PostponedError(object): + def __init__(self, errorMsg): + self.__errorMsg = errorMsg + + def __getitem__(self, item): + raise error.PyAsn1Error(self.__errorMsg) + + def __computeTagToPosMap(self): + tagToPosMap = {} + for idx, namedType in enumerate(self.__namedTypes): + tagMap = namedType.asn1Object.tagMap + if isinstance(tagMap, NamedTypes.PostponedError): + return tagMap + if not tagMap: + continue + for _tagSet in tagMap.presentTypes: + if _tagSet in tagToPosMap: + return NamedTypes.PostponedError('Duplicate component tag %s at %s' % (_tagSet, namedType)) + tagToPosMap[_tagSet] = idx + + return tagToPosMap + + def __computeNameToPosMap(self): + nameToPosMap = {} + for idx, namedType in enumerate(self.__namedTypes): + if namedType.name in nameToPosMap: + return NamedTypes.PostponedError('Duplicate component name %s at %s' % (namedType.name, namedType)) + nameToPosMap[namedType.name] = idx + + return nameToPosMap + + def __computeAmbiguousTypes(self): + ambiguousTypes = {} + partialAmbiguousTypes = () + for idx, namedType in reversed(tuple(enumerate(self.__namedTypes))): + if namedType.isOptional or namedType.isDefaulted: + partialAmbiguousTypes = (namedType,) + partialAmbiguousTypes + else: + partialAmbiguousTypes = (namedType,) + if len(partialAmbiguousTypes) == len(self.__namedTypes): + ambiguousTypes[idx] = self + else: + ambiguousTypes[idx] = NamedTypes(*partialAmbiguousTypes, **dict(terminal=True)) + return ambiguousTypes + + def getTypeByPosition(self, idx): + """Return ASN.1 type object by its position in fields set. + + Parameters + ---------- + idx: :py:class:`int` + Field index + + Returns + ------- + : + ASN.1 type + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If given position is out of fields range + """ + try: + return self.__namedTypes[idx].asn1Object + + except IndexError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByType(self, tagSet): + """Return field position by its ASN.1 type. + + Parameters + ---------- + tagSet: :class:`~pysnmp.type.tag.TagSet` + ASN.1 tag set distinguishing one ASN.1 type from others. + + Returns + ------- + : :py:class:`int` + ASN.1 type position in fields set + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If *tagSet* is not present or ASN.1 types are not unique within callee *NamedTypes* + """ + try: + return self.__tagToPosMap[tagSet] + + except KeyError: + raise error.PyAsn1Error('Type %s not found' % (tagSet,)) + + def getNameByPosition(self, idx): + """Return field name by its position in fields set. + + Parameters + ---------- + idx: :py:class:`idx` + Field index + + Returns + ------- + : :py:class:`str` + Field name + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If given field name is not present in callee *NamedTypes* + """ + try: + return self.__namedTypes[idx].name + + except IndexError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByName(self, name): + """Return field position by filed name. + + Parameters + ---------- + name: :py:class:`str` + Field name + + Returns + ------- + : :py:class:`int` + Field position in fields set + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If *name* is not present or not unique within callee *NamedTypes* + """ + try: + return self.__nameToPosMap[name] + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + def getTagMapNearPosition(self, idx): + """Return ASN.1 types that are allowed at or past given field position. + + Some ASN.1 serialisation allow for skipping optional and defaulted fields. + Some constructed ASN.1 types allow reordering of the fields. When recovering + such objects it may be important to know which types can possibly be + present at any given position in the field sets. + + Parameters + ---------- + idx: :py:class:`int` + Field index + + Returns + ------- + : :class:`~pyasn1.type.tagmap.TagMap` + Map if ASN.1 types allowed at given field position + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If given position is out of fields range + """ + try: + return self.__ambiguousTypes[idx].tagMap + + except KeyError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionNearType(self, tagSet, idx): + """Return the closest field position where given ASN.1 type is allowed. + + Some ASN.1 serialisation allow for skipping optional and defaulted fields. + Some constructed ASN.1 types allow reordering of the fields. When recovering + such objects it may be important to know at which field position, in field set, + given *tagSet* is allowed at or past *idx* position. + + Parameters + ---------- + tagSet: :class:`~pyasn1.type.tag.TagSet` + ASN.1 type which field position to look up + + idx: :py:class:`int` + Field position at or past which to perform ASN.1 type look up + + Returns + ------- + : :py:class:`int` + Field position in fields set + + Raises + ------ + ~pyasn1.error.PyAsn1Error + If *tagSet* is not present or not unique within callee *NamedTypes* + or *idx* is out of fields range + """ + try: + return idx + self.__ambiguousTypes[idx].getPositionByType(tagSet) + + except KeyError: + raise error.PyAsn1Error('Type position out of range') + + def __computeMinTagSet(self): + minTagSet = None + for namedType in self.__namedTypes: + asn1Object = namedType.asn1Object + + try: + tagSet = asn1Object.minTagSet + + except AttributeError: + tagSet = asn1Object.tagSet + + if minTagSet is None or tagSet < minTagSet: + minTagSet = tagSet + + return minTagSet or tag.TagSet() + + @property + def minTagSet(self): + """Return the minimal TagSet among ASN.1 type in callee *NamedTypes*. + + Some ASN.1 types/serialisation protocols require ASN.1 types to be + arranged based on their numerical tag value. The *minTagSet* property + returns that. + + Returns + ------- + : :class:`~pyasn1.type.tagset.TagSet` + Minimal TagSet among ASN.1 types in callee *NamedTypes* + """ + return self.__minTagSet + + def __computeTagMaps(self, unique): + presentTypes = {} + skipTypes = {} + defaultType = None + for namedType in self.__namedTypes: + tagMap = namedType.asn1Object.tagMap + if isinstance(tagMap, NamedTypes.PostponedError): + return tagMap + for tagSet in tagMap: + if unique and tagSet in presentTypes: + return NamedTypes.PostponedError('Non-unique tagSet %s of %s at %s' % (tagSet, namedType, self)) + presentTypes[tagSet] = namedType.asn1Object + skipTypes.update(tagMap.skipTypes) + + if defaultType is None: + defaultType = tagMap.defaultType + elif tagMap.defaultType is not None: + return NamedTypes.PostponedError('Duplicate default ASN.1 type at %s' % (self,)) + + return tagmap.TagMap(presentTypes, skipTypes, defaultType) + + @property + def tagMap(self): + """Return a *TagMap* object from tags and types recursively. + + Return a :class:`~pyasn1.type.tagmap.TagMap` object by + combining tags from *TagMap* objects of children types and + associating them with their immediate child type. + + Example + ------- + .. code-block:: python + + OuterType ::= CHOICE { + innerType INTEGER + } + + Calling *.tagMap* on *OuterType* will yield a map like this: + + .. code-block:: python + + Integer.tagSet -> Choice + """ + return self.__nonUniqueTagMap + + @property + def tagMapUnique(self): + """Return a *TagMap* object from unique tags and types recursively. + + Return a :class:`~pyasn1.type.tagmap.TagMap` object by + combining tags from *TagMap* objects of children types and + associating them with their immediate child type. + + Example + ------- + .. code-block:: python + + OuterType ::= CHOICE { + innerType INTEGER + } + + Calling *.tagMapUnique* on *OuterType* will yield a map like this: + + .. code-block:: python + + Integer.tagSet -> Choice + + Note + ---- + + Duplicate *TagSet* objects found in the tree of children + types would cause error. + """ + return self.__uniqueTagMap + + @property + def hasOptionalOrDefault(self): + return self.__hasOptionalOrDefault + + @property + def hasOpenTypes(self): + return self.__hasOpenTypes + + @property + def namedTypes(self): + return tuple(self.__namedTypes) + + @property + def requiredComponents(self): + return self.__requiredComponents diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/namedval.py b/Lambdas/Websocket Authorizer/pyasn1/type/namedval.py new file mode 100644 index 0000000..4247597 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/namedval.py @@ -0,0 +1,192 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +# ASN.1 named integers +# +from pyasn1 import error + +__all__ = ['NamedValues'] + + +class NamedValues(object): + """Create named values object. + + The |NamedValues| object represents a collection of string names + associated with numeric IDs. These objects are used for giving + names to otherwise numerical values. + + |NamedValues| objects are immutable and duck-type Python + :class:`dict` object mapping ID to name and vice-versa. + + Parameters + ---------- + *args: variable number of two-element :py:class:`tuple` + + name: :py:class:`str` + Value label + + value: :py:class:`int` + Numeric value + + Keyword Args + ------------ + name: :py:class:`str` + Value label + + value: :py:class:`int` + Numeric value + + Examples + -------- + + .. code-block:: pycon + + >>> nv = NamedValues('a', 'b', ('c', 0), d=1) + >>> nv + >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3} + >>> nv[0] + 'c' + >>> nv['a'] + 2 + """ + def __init__(self, *args, **kwargs): + self.__names = {} + self.__numbers = {} + + anonymousNames = [] + + for namedValue in args: + if isinstance(namedValue, (tuple, list)): + try: + name, number = namedValue + + except ValueError: + raise error.PyAsn1Error('Not a proper attribute-value pair %r' % (namedValue,)) + + else: + anonymousNames.append(namedValue) + continue + + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + if number in self.__numbers: + raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) + + self.__names[name] = number + self.__numbers[number] = name + + for name, number in kwargs.items(): + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + if number in self.__numbers: + raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) + + self.__names[name] = number + self.__numbers[number] = name + + if anonymousNames: + + number = self.__numbers and max(self.__numbers) + 1 or 0 + + for name in anonymousNames: + + if name in self.__names: + raise error.PyAsn1Error('Duplicate name %s' % (name,)) + + self.__names[name] = number + self.__numbers[number] = name + + number += 1 + + def __repr__(self): + representation = ', '.join(['%s=%d' % x for x in self.items()]) + + if len(representation) > 64: + representation = representation[:32] + '...' + representation[-32:] + + return '<%s object, enums %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return dict(self) == other + + def __ne__(self, other): + return dict(self) != other + + def __lt__(self, other): + return dict(self) < other + + def __le__(self, other): + return dict(self) <= other + + def __gt__(self, other): + return dict(self) > other + + def __ge__(self, other): + return dict(self) >= other + + def __hash__(self): + return hash(self.items()) + + # Python dict protocol (read-only) + + def __getitem__(self, key): + try: + return self.__numbers[key] + + except KeyError: + return self.__names[key] + + def __len__(self): + return len(self.__names) + + def __contains__(self, key): + return key in self.__names or key in self.__numbers + + def __iter__(self): + return iter(self.__names) + + def values(self): + return iter(self.__numbers) + + def keys(self): + return iter(self.__names) + + def items(self): + for name in self.__names: + yield name, self.__names[name] + + # support merging + + def __add__(self, namedValues): + return self.__class__(*tuple(self.items()) + tuple(namedValues.items())) + + # XXX clone/subtype? + + def clone(self, *args, **kwargs): + new = self.__class__(*args, **kwargs) + return self + new + + # legacy protocol + + def getName(self, value): + if value in self.__numbers: + return self.__numbers[value] + + def getValue(self, name): + if name in self.__names: + return self.__names[name] + + def getValues(self, *names): + try: + return [self.__names[name] for name in names] + + except KeyError: + raise error.PyAsn1Error( + 'Unknown bit identifier(s): %s' % (set(names).difference(self.__names),) + ) diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/opentype.py b/Lambdas/Websocket Authorizer/pyasn1/type/opentype.py new file mode 100644 index 0000000..29645f0 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/opentype.py @@ -0,0 +1,104 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# + +__all__ = ['OpenType'] + + +class OpenType(object): + """Create ASN.1 type map indexed by a value + + The *OpenType* object models an untyped field of a constructed ASN.1 + type. In ASN.1 syntax it is usually represented by the + `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`, + `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically + used together with :class:`~pyasn1.type.univ.Any` object. + + OpenType objects duck-type a read-only Python :class:`dict` objects, + however the passed `typeMap` is not copied, but stored by reference. + That means the user can manipulate `typeMap` at run time having this + reflected on *OpenType* object behavior. + + The |OpenType| class models an untyped field of a constructed ASN.1 + type. In ASN.1 syntax it is usually represented by the + `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`, + `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically + used with :class:`~pyasn1.type.univ.Any` type. + + Parameters + ---------- + name: :py:class:`str` + Field name + + typeMap: :py:class:`dict` + A map of value->ASN.1 type. It's stored by reference and can be + mutated later to register new mappings. + + Examples + -------- + + For untyped scalars: + + .. code-block:: python + + openType = OpenType( + 'id', {1: Integer(), + 2: OctetString()} + ) + Sequence( + componentType=NamedTypes( + NamedType('id', Integer()), + NamedType('blob', Any(), openType=openType) + ) + ) + + For untyped `SET OF` or `SEQUENCE OF` vectors: + + .. code-block:: python + + openType = OpenType( + 'id', {1: Integer(), + 2: OctetString()} + ) + Sequence( + componentType=NamedTypes( + NamedType('id', Integer()), + NamedType('blob', SetOf(componentType=Any()), + openType=openType) + ) + ) + """ + + def __init__(self, name, typeMap=None): + self.__name = name + if typeMap is None: + self.__typeMap = {} + else: + self.__typeMap = typeMap + + @property + def name(self): + return self.__name + + # Python dict protocol + + def values(self): + return self.__typeMap.values() + + def keys(self): + return self.__typeMap.keys() + + def items(self): + return self.__typeMap.items() + + def __contains__(self, key): + return key in self.__typeMap + + def __getitem__(self, key): + return self.__typeMap[key] + + def __iter__(self): + return iter(self.__typeMap) diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/tag.py b/Lambdas/Websocket Authorizer/pyasn1/type/tag.py new file mode 100644 index 0000000..b88a734 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/tag.py @@ -0,0 +1,335 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error + +__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext', + 'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed', + 'tagCategoryImplicit', 'tagCategoryExplicit', + 'tagCategoryUntagged', 'Tag', 'TagSet'] + +#: Identifier for ASN.1 class UNIVERSAL +tagClassUniversal = 0x00 + +#: Identifier for ASN.1 class APPLICATION +tagClassApplication = 0x40 + +#: Identifier for ASN.1 class context-specific +tagClassContext = 0x80 + +#: Identifier for ASN.1 class private +tagClassPrivate = 0xC0 + +#: Identifier for "simple" ASN.1 structure (e.g. scalar) +tagFormatSimple = 0x00 + +#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components) +tagFormatConstructed = 0x20 + +tagCategoryImplicit = 0x01 +tagCategoryExplicit = 0x02 +tagCategoryUntagged = 0x04 + + +class Tag(object): + """Create ASN.1 tag + + Represents ASN.1 tag that can be attached to a ASN.1 type to make + types distinguishable from each other. + + *Tag* objects are immutable and duck-type Python :class:`tuple` objects + holding three integer components of a tag. + + Parameters + ---------- + tagClass: :py:class:`int` + Tag *class* value + + tagFormat: :py:class:`int` + Tag *format* value + + tagId: :py:class:`int` + Tag ID value + """ + def __init__(self, tagClass, tagFormat, tagId): + if tagId < 0: + raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId) + self.__tagClass = tagClass + self.__tagFormat = tagFormat + self.__tagId = tagId + self.__tagClassId = tagClass, tagId + self.__hash = hash(self.__tagClassId) + + def __repr__(self): + representation = '[%s:%s:%s]' % ( + self.__tagClass, self.__tagFormat, self.__tagId) + return '<%s object, tag %s>' % ( + self.__class__.__name__, representation) + + def __eq__(self, other): + return self.__tagClassId == other + + def __ne__(self, other): + return self.__tagClassId != other + + def __lt__(self, other): + return self.__tagClassId < other + + def __le__(self, other): + return self.__tagClassId <= other + + def __gt__(self, other): + return self.__tagClassId > other + + def __ge__(self, other): + return self.__tagClassId >= other + + def __hash__(self): + return self.__hash + + def __getitem__(self, idx): + if idx == 0: + return self.__tagClass + elif idx == 1: + return self.__tagFormat + elif idx == 2: + return self.__tagId + else: + raise IndexError() + + def __iter__(self): + yield self.__tagClass + yield self.__tagFormat + yield self.__tagId + + def __and__(self, otherTag): + return self.__class__(self.__tagClass & otherTag.tagClass, + self.__tagFormat & otherTag.tagFormat, + self.__tagId & otherTag.tagId) + + def __or__(self, otherTag): + return self.__class__(self.__tagClass | otherTag.tagClass, + self.__tagFormat | otherTag.tagFormat, + self.__tagId | otherTag.tagId) + + @property + def tagClass(self): + """ASN.1 tag class + + Returns + ------- + : :py:class:`int` + Tag class + """ + return self.__tagClass + + @property + def tagFormat(self): + """ASN.1 tag format + + Returns + ------- + : :py:class:`int` + Tag format + """ + return self.__tagFormat + + @property + def tagId(self): + """ASN.1 tag ID + + Returns + ------- + : :py:class:`int` + Tag ID + """ + return self.__tagId + + +class TagSet(object): + """Create a collection of ASN.1 tags + + Represents a combination of :class:`~pyasn1.type.tag.Tag` objects + that can be attached to a ASN.1 type to make types distinguishable + from each other. + + *TagSet* objects are immutable and duck-type Python :class:`tuple` objects + holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects. + + Parameters + ---------- + baseTag: :class:`~pyasn1.type.tag.Tag` + Base *Tag* object. This tag survives IMPLICIT tagging. + + *superTags: :class:`~pyasn1.type.tag.Tag` + Additional *Tag* objects taking part in subtyping. + + Examples + -------- + .. code-block:: python + + class OrderNumber(NumericString): + ''' + ASN.1 specification + + Order-number ::= + [APPLICATION 5] IMPLICIT NumericString + ''' + tagSet = NumericString.tagSet.tagImplicitly( + Tag(tagClassApplication, tagFormatSimple, 5) + ) + + orderNumber = OrderNumber('1234') + """ + def __init__(self, baseTag=(), *superTags): + self.__baseTag = baseTag + self.__superTags = superTags + self.__superTagsClassId = tuple( + [(superTag.tagClass, superTag.tagId) for superTag in superTags] + ) + self.__lenOfSuperTags = len(superTags) + self.__hash = hash(self.__superTagsClassId) + + def __repr__(self): + representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId) + for x in self.__superTags]) + if representation: + representation = 'tags ' + representation + else: + representation = 'untagged' + + return '<%s object, %s>' % (self.__class__.__name__, representation) + + def __add__(self, superTag): + return self.__class__(self.__baseTag, *self.__superTags + (superTag,)) + + def __radd__(self, superTag): + return self.__class__(self.__baseTag, *(superTag,) + self.__superTags) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.__class__(self.__baseTag, *self.__superTags[i]) + else: + return self.__superTags[i] + + def __eq__(self, other): + return self.__superTagsClassId == other + + def __ne__(self, other): + return self.__superTagsClassId != other + + def __lt__(self, other): + return self.__superTagsClassId < other + + def __le__(self, other): + return self.__superTagsClassId <= other + + def __gt__(self, other): + return self.__superTagsClassId > other + + def __ge__(self, other): + return self.__superTagsClassId >= other + + def __hash__(self): + return self.__hash + + def __len__(self): + return self.__lenOfSuperTags + + @property + def baseTag(self): + """Return base ASN.1 tag + + Returns + ------- + : :class:`~pyasn1.type.tag.Tag` + Base tag of this *TagSet* + """ + return self.__baseTag + + @property + def superTags(self): + """Return ASN.1 tags + + Returns + ------- + : :py:class:`tuple` + Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains + """ + return self.__superTags + + def tagExplicitly(self, superTag): + """Return explicitly tagged *TagSet* + + Create a new *TagSet* representing callee *TagSet* explicitly tagged + with passed tag(s). With explicit tagging mode, new tags are appended + to existing tag(s). + + Parameters + ---------- + superTag: :class:`~pyasn1.type.tag.Tag` + *Tag* object to tag this *TagSet* + + Returns + ------- + : :class:`~pyasn1.type.tag.TagSet` + New *TagSet* object + """ + if superTag.tagClass == tagClassUniversal: + raise error.PyAsn1Error("Can't tag with UNIVERSAL class tag") + if superTag.tagFormat != tagFormatConstructed: + superTag = Tag(superTag.tagClass, tagFormatConstructed, superTag.tagId) + return self + superTag + + def tagImplicitly(self, superTag): + """Return implicitly tagged *TagSet* + + Create a new *TagSet* representing callee *TagSet* implicitly tagged + with passed tag(s). With implicit tagging mode, new tag(s) replace the + last existing tag. + + Parameters + ---------- + superTag: :class:`~pyasn1.type.tag.Tag` + *Tag* object to tag this *TagSet* + + Returns + ------- + : :class:`~pyasn1.type.tag.TagSet` + New *TagSet* object + """ + if self.__superTags: + superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId) + return self[:-1] + superTag + + def isSuperTagSetOf(self, tagSet): + """Test type relationship against given *TagSet* + + The callee is considered to be a supertype of given *TagSet* + tag-wise if all tags in *TagSet* are present in the callee and + they are in the same order. + + Parameters + ---------- + tagSet: :class:`~pyasn1.type.tag.TagSet` + *TagSet* object to evaluate against the callee + + Returns + ------- + : :py:class:`bool` + :obj:`True` if callee is a supertype of *tagSet* + """ + if len(tagSet) < self.__lenOfSuperTags: + return False + return self.__superTags == tagSet[:self.__lenOfSuperTags] + + # Backward compatibility + + def getBaseTag(self): + return self.__baseTag + +def initTagSet(tag): + return TagSet(tag, tag) diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/tagmap.py b/Lambdas/Websocket Authorizer/pyasn1/type/tagmap.py new file mode 100644 index 0000000..6f5163b --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/tagmap.py @@ -0,0 +1,96 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +from pyasn1 import error + +__all__ = ['TagMap'] + + +class TagMap(object): + """Map *TagSet* objects to ASN.1 types + + Create an object mapping *TagSet* object to ASN.1 type. + + *TagMap* objects are immutable and duck-type read-only Python + :class:`dict` objects holding *TagSet* objects as keys and ASN.1 + type objects as values. + + Parameters + ---------- + presentTypes: :py:class:`dict` + Map of :class:`~pyasn1.type.tag.TagSet` to ASN.1 objects considered + as being unconditionally present in the *TagMap*. + + skipTypes: :py:class:`dict` + A collection of :class:`~pyasn1.type.tag.TagSet` objects considered + as absent in the *TagMap* even when *defaultType* is present. + + defaultType: ASN.1 type object + An ASN.1 type object callee *TagMap* returns for any *TagSet* key not present + in *presentTypes* (unless given key is present in *skipTypes*). + """ + def __init__(self, presentTypes=None, skipTypes=None, defaultType=None): + self.__presentTypes = presentTypes or {} + self.__skipTypes = skipTypes or {} + self.__defaultType = defaultType + + def __contains__(self, tagSet): + return (tagSet in self.__presentTypes or + self.__defaultType is not None and tagSet not in self.__skipTypes) + + def __getitem__(self, tagSet): + try: + return self.__presentTypes[tagSet] + except KeyError: + if self.__defaultType is None: + raise KeyError() + elif tagSet in self.__skipTypes: + raise error.PyAsn1Error('Key in negative map') + else: + return self.__defaultType + + def __iter__(self): + return iter(self.__presentTypes) + + def __repr__(self): + representation = '%s object' % self.__class__.__name__ + + if self.__presentTypes: + representation += ', present %s' % repr(self.__presentTypes) + + if self.__skipTypes: + representation += ', skip %s' % repr(self.__skipTypes) + + if self.__defaultType is not None: + representation += ', default %s' % repr(self.__defaultType) + + return '<%s>' % representation + + @property + def presentTypes(self): + """Return *TagSet* to ASN.1 type map present in callee *TagMap*""" + return self.__presentTypes + + @property + def skipTypes(self): + """Return *TagSet* collection unconditionally absent in callee *TagMap*""" + return self.__skipTypes + + @property + def defaultType(self): + """Return default ASN.1 type being returned for any missing *TagSet*""" + return self.__defaultType + + # Backward compatibility + + def getPosMap(self): + return self.presentTypes + + def getNegMap(self): + return self.skipTypes + + def getDef(self): + return self.defaultType diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/univ.py b/Lambdas/Websocket Authorizer/pyasn1/type/univ.py new file mode 100644 index 0000000..aa688b2 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/univ.py @@ -0,0 +1,3321 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import math +import sys + +from pyasn1 import error +from pyasn1.codec.ber import eoo +from pyasn1.compat import binary +from pyasn1.compat import integer +from pyasn1.compat import octets +from pyasn1.type import base +from pyasn1.type import constraint +from pyasn1.type import namedtype +from pyasn1.type import namedval +from pyasn1.type import tag +from pyasn1.type import tagmap + +NoValue = base.NoValue +noValue = NoValue() + +__all__ = ['Integer', 'Boolean', 'BitString', 'OctetString', 'Null', + 'ObjectIdentifier', 'Real', 'Enumerated', + 'SequenceOfAndSetOfBase', 'SequenceOf', 'SetOf', + 'SequenceAndSetBase', 'Sequence', 'Set', 'Choice', 'Any', + 'NoValue', 'noValue'] + +# "Simple" ASN.1 types (yet incomplete) + + +class Integer(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal or |ASN.1| class + instance. If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + + .. code-block:: python + + class ErrorCode(Integer): + ''' + ASN.1 specification: + + ErrorCode ::= + INTEGER { disk-full(1), no-disk(-1), + disk-not-formatted(2) } + + error ErrorCode ::= disk-full + ''' + namedValues = NamedValues( + ('disk-full', 1), ('no-disk', -1), + ('disk-not-formatted', 2) + ) + + error = ErrorCode('disk-full') + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + def __init__(self, value=noValue, **kwargs): + if 'namedValues' not in kwargs: + kwargs['namedValues'] = self.namedValues + + base.SimpleAsn1Type.__init__(self, value, **kwargs) + + def __and__(self, value): + return self.clone(self._value & value) + + def __rand__(self, value): + return self.clone(value & self._value) + + def __or__(self, value): + return self.clone(self._value | value) + + def __ror__(self, value): + return self.clone(value | self._value) + + def __xor__(self, value): + return self.clone(self._value ^ value) + + def __rxor__(self, value): + return self.clone(value ^ self._value) + + def __lshift__(self, value): + return self.clone(self._value << value) + + def __rshift__(self, value): + return self.clone(self._value >> value) + + def __add__(self, value): + return self.clone(self._value + value) + + def __radd__(self, value): + return self.clone(value + self._value) + + def __sub__(self, value): + return self.clone(self._value - value) + + def __rsub__(self, value): + return self.clone(value - self._value) + + def __mul__(self, value): + return self.clone(self._value * value) + + def __rmul__(self, value): + return self.clone(value * self._value) + + def __mod__(self, value): + return self.clone(self._value % value) + + def __rmod__(self, value): + return self.clone(value % self._value) + + def __pow__(self, value, modulo=None): + return self.clone(pow(self._value, value, modulo)) + + def __rpow__(self, value): + return self.clone(pow(value, self._value)) + + def __floordiv__(self, value): + return self.clone(self._value // value) + + def __rfloordiv__(self, value): + return self.clone(value // self._value) + + if sys.version_info[0] <= 2: + def __div__(self, value): + if isinstance(value, float): + return Real(self._value / value) + else: + return self.clone(self._value / value) + + def __rdiv__(self, value): + if isinstance(value, float): + return Real(value / self._value) + else: + return self.clone(value / self._value) + else: + def __truediv__(self, value): + return Real(self._value / value) + + def __rtruediv__(self, value): + return Real(value / self._value) + + def __divmod__(self, value): + return self.clone(divmod(self._value, value)) + + def __rdivmod__(self, value): + return self.clone(divmod(value, self._value)) + + __hash__ = base.SimpleAsn1Type.__hash__ + + def __int__(self): + return int(self._value) + + if sys.version_info[0] <= 2: + def __long__(self): + return long(self._value) + + def __float__(self): + return float(self._value) + + def __abs__(self): + return self.clone(abs(self._value)) + + def __index__(self): + return int(self._value) + + def __pos__(self): + return self.clone(+self._value) + + def __neg__(self): + return self.clone(-self._value) + + def __invert__(self): + return self.clone(~self._value) + + def __round__(self, n=0): + r = round(self._value, n) + if n: + return self.clone(r) + else: + return r + + def __floor__(self): + return math.floor(self._value) + + def __ceil__(self): + return math.ceil(self._value) + + if sys.version_info[0:2] > (2, 5): + def __trunc__(self): + return self.clone(math.trunc(self._value)) + + def __lt__(self, value): + return self._value < value + + def __le__(self, value): + return self._value <= value + + def __eq__(self, value): + return self._value == value + + def __ne__(self, value): + return self._value != value + + def __gt__(self, value): + return self._value > value + + def __ge__(self, value): + return self._value >= value + + def prettyIn(self, value): + try: + return int(value) + + except ValueError: + try: + return self.namedValues[value] + + except KeyError: + raise error.PyAsn1Error( + 'Can\'t coerce %r into integer: %s' % (value, sys.exc_info()[1]) + ) + + def prettyOut(self, value): + try: + return str(self.namedValues[value]) + + except KeyError: + return str(value) + + # backward compatibility + + def getNamedValues(self): + return self.namedValues + + +class Boolean(Integer): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal or |ASN.1| class + instance. If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s).Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class RoundResult(Boolean): + ''' + ASN.1 specification: + + RoundResult ::= BOOLEAN + + ok RoundResult ::= TRUE + ko RoundResult ::= FALSE + ''' + ok = RoundResult(True) + ko = RoundResult(False) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01), + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = Integer.subtypeSpec + constraint.SingleValueConstraint(0, 1) + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues(('False', 0), ('True', 1)) + + # Optimization for faster codec lookup + typeId = Integer.getTypeId() + +if sys.version_info[0] < 3: + SizedIntegerBase = long +else: + SizedIntegerBase = int + + +class SizedInteger(SizedIntegerBase): + bitLength = leadingZeroBits = None + + def setBitLength(self, bitLength): + self.bitLength = bitLength + self.leadingZeroBits = max(bitLength - integer.bitLength(self), 0) + return self + + def __len__(self): + if self.bitLength is None: + self.setBitLength(integer.bitLength(self)) + + return self.bitLength + + +class BitString(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type both Python :class:`tuple` (as a tuple + of bits) and :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal representing binary + or hexadecimal number or sequence of integer bits or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Rights(BitString): + ''' + ASN.1 specification: + + Rights ::= BIT STRING { user-read(0), user-write(1), + group-read(2), group-write(3), + other-read(4), other-write(5) } + + group1 Rights ::= { group-read, group-write } + group2 Rights ::= '0011'B + group3 Rights ::= '3'H + ''' + namedValues = NamedValues( + ('user-read', 0), ('user-write', 1), + ('group-read', 2), ('group-write', 3), + ('other-read', 4), ('other-write', 5) + ) + + group1 = Rights(('group-read', 'group-write')) + group2 = Rights('0011') + group3 = Rights(0x3) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + defaultBinValue = defaultHexValue = noValue + + def __init__(self, value=noValue, **kwargs): + if value is noValue: + if kwargs: + try: + value = self.fromBinaryString(kwargs.pop('binValue'), internalFormat=True) + + except KeyError: + pass + + try: + value = self.fromHexString(kwargs.pop('hexValue'), internalFormat=True) + + except KeyError: + pass + + if value is noValue: + if self.defaultBinValue is not noValue: + value = self.fromBinaryString(self.defaultBinValue, internalFormat=True) + + elif self.defaultHexValue is not noValue: + value = self.fromHexString(self.defaultHexValue, internalFormat=True) + + if 'namedValues' not in kwargs: + kwargs['namedValues'] = self.namedValues + + base.SimpleAsn1Type.__init__(self, value, **kwargs) + + def __str__(self): + return self.asBinary() + + def __eq__(self, other): + other = self.prettyIn(other) + return self is other or self._value == other and len(self._value) == len(other) + + def __ne__(self, other): + other = self.prettyIn(other) + return self._value != other or len(self._value) != len(other) + + def __lt__(self, other): + other = self.prettyIn(other) + return len(self._value) < len(other) or len(self._value) == len(other) and self._value < other + + def __le__(self, other): + other = self.prettyIn(other) + return len(self._value) <= len(other) or len(self._value) == len(other) and self._value <= other + + def __gt__(self, other): + other = self.prettyIn(other) + return len(self._value) > len(other) or len(self._value) == len(other) and self._value > other + + def __ge__(self, other): + other = self.prettyIn(other) + return len(self._value) >= len(other) or len(self._value) == len(other) and self._value >= other + + # Immutable sequence object protocol + + def __len__(self): + return len(self._value) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.clone([self[x] for x in range(*i.indices(len(self)))]) + else: + length = len(self._value) - 1 + if i > length or i < 0: + raise IndexError('bit index out of range') + return (self._value >> (length - i)) & 1 + + def __iter__(self): + length = len(self._value) + while length: + length -= 1 + yield (self._value >> length) & 1 + + def __reversed__(self): + return reversed(tuple(self)) + + # arithmetic operators + + def __add__(self, value): + value = self.prettyIn(value) + return self.clone(SizedInteger(self._value << len(value) | value).setBitLength(len(self._value) + len(value))) + + def __radd__(self, value): + value = self.prettyIn(value) + return self.clone(SizedInteger(value << len(self._value) | self._value).setBitLength(len(self._value) + len(value))) + + def __mul__(self, value): + bitString = self._value + while value > 1: + bitString <<= len(self._value) + bitString |= self._value + value -= 1 + return self.clone(bitString) + + def __rmul__(self, value): + return self * value + + def __lshift__(self, count): + return self.clone(SizedInteger(self._value << count).setBitLength(len(self._value) + count)) + + def __rshift__(self, count): + return self.clone(SizedInteger(self._value >> count).setBitLength(max(0, len(self._value) - count))) + + def __int__(self): + return self._value + + def __float__(self): + return float(self._value) + + if sys.version_info[0] < 3: + def __long__(self): + return self._value + + def asNumbers(self): + """Get |ASN.1| value as a sequence of 8-bit integers. + + If |ASN.1| object length is not a multiple of 8, result + will be left-padded with zeros. + """ + return tuple(octets.octs2ints(self.asOctets())) + + def asOctets(self): + """Get |ASN.1| value as a sequence of octets. + + If |ASN.1| object length is not a multiple of 8, result + will be left-padded with zeros. + """ + return integer.to_bytes(self._value, length=len(self)) + + def asInteger(self): + """Get |ASN.1| value as a single integer value. + """ + return self._value + + def asBinary(self): + """Get |ASN.1| value as a text string of bits. + """ + binString = binary.bin(self._value)[2:] + return '0' * (len(self._value) - len(binString)) + binString + + @classmethod + def fromHexString(cls, value, internalFormat=False, prepend=None): + """Create a |ASN.1| object initialized from the hex string. + + Parameters + ---------- + value: :class:`str` + Text string like 'DEADBEEF' + """ + try: + value = SizedInteger(value, 16).setBitLength(len(value) * 4) + + except ValueError: + raise error.PyAsn1Error('%s.fromHexString() error: %s' % (cls.__name__, sys.exc_info()[1])) + + if prepend is not None: + value = SizedInteger( + (SizedInteger(prepend) << len(value)) | value + ).setBitLength(len(prepend) + len(value)) + + if not internalFormat: + value = cls(value) + + return value + + @classmethod + def fromBinaryString(cls, value, internalFormat=False, prepend=None): + """Create a |ASN.1| object initialized from a string of '0' and '1'. + + Parameters + ---------- + value: :class:`str` + Text string like '1010111' + """ + try: + value = SizedInteger(value or '0', 2).setBitLength(len(value)) + + except ValueError: + raise error.PyAsn1Error('%s.fromBinaryString() error: %s' % (cls.__name__, sys.exc_info()[1])) + + if prepend is not None: + value = SizedInteger( + (SizedInteger(prepend) << len(value)) | value + ).setBitLength(len(prepend) + len(value)) + + if not internalFormat: + value = cls(value) + + return value + + @classmethod + def fromOctetString(cls, value, internalFormat=False, prepend=None, padding=0): + """Create a |ASN.1| object initialized from a string. + + Parameters + ---------- + value: :class:`str` (Py2) or :class:`bytes` (Py3) + Text string like '\\\\x01\\\\xff' (Py2) or b'\\\\x01\\\\xff' (Py3) + """ + value = SizedInteger(integer.from_bytes(value) >> padding).setBitLength(len(value) * 8 - padding) + + if prepend is not None: + value = SizedInteger( + (SizedInteger(prepend) << len(value)) | value + ).setBitLength(len(prepend) + len(value)) + + if not internalFormat: + value = cls(value) + + return value + + def prettyIn(self, value): + if isinstance(value, SizedInteger): + return value + elif octets.isStringType(value): + if not value: + return SizedInteger(0).setBitLength(0) + + elif value[0] == '\'': # "'1011'B" -- ASN.1 schema representation (deprecated) + if value[-2:] == '\'B': + return self.fromBinaryString(value[1:-2], internalFormat=True) + elif value[-2:] == '\'H': + return self.fromHexString(value[1:-2], internalFormat=True) + else: + raise error.PyAsn1Error( + 'Bad BIT STRING value notation %s' % (value,) + ) + + elif self.namedValues and not value.isdigit(): # named bits like 'Urgent, Active' + names = [x.strip() for x in value.split(',')] + + try: + + bitPositions = [self.namedValues[name] for name in names] + + except KeyError: + raise error.PyAsn1Error('unknown bit name(s) in %r' % (names,)) + + rightmostPosition = max(bitPositions) + + number = 0 + for bitPosition in bitPositions: + number |= 1 << (rightmostPosition - bitPosition) + + return SizedInteger(number).setBitLength(rightmostPosition + 1) + + elif value.startswith('0x'): + return self.fromHexString(value[2:], internalFormat=True) + + elif value.startswith('0b'): + return self.fromBinaryString(value[2:], internalFormat=True) + + else: # assume plain binary string like '1011' + return self.fromBinaryString(value, internalFormat=True) + + elif isinstance(value, (tuple, list)): + return self.fromBinaryString(''.join([b and '1' or '0' for b in value]), internalFormat=True) + + elif isinstance(value, BitString): + return SizedInteger(value).setBitLength(len(value)) + + elif isinstance(value, intTypes): + return SizedInteger(value) + + else: + raise error.PyAsn1Error( + 'Bad BitString initializer type \'%s\'' % (value,) + ) + + +try: + # noinspection PyStatementEffect + all + +except NameError: # Python 2.4 + # noinspection PyShadowingBuiltins + def all(iterable): + for element in iterable: + if not element: + return False + return True + + +class OctetString(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python 2 :class:`str` or + Python 3 :class:`bytes`. When used in Unicode context, |ASN.1| type + assumes "|encoding|" serialisation. + + Keyword Args + ------------ + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively + class:`unicode` object (Python 2) or :class:`str` (Python 3) + representing character string to be serialised into octets + (note `encoding` parameter) or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in text string context. + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Icon(OctetString): + ''' + ASN.1 specification: + + Icon ::= OCTET STRING + + icon1 Icon ::= '001100010011001000110011'B + icon2 Icon ::= '313233'H + ''' + icon1 = Icon.fromBinaryString('001100010011001000110011') + icon2 = Icon.fromHexString('313233') + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + defaultBinValue = defaultHexValue = noValue + encoding = 'iso-8859-1' + + def __init__(self, value=noValue, **kwargs): + if kwargs: + if value is noValue: + try: + value = self.fromBinaryString(kwargs.pop('binValue')) + + except KeyError: + pass + + try: + value = self.fromHexString(kwargs.pop('hexValue')) + + except KeyError: + pass + + if value is noValue: + if self.defaultBinValue is not noValue: + value = self.fromBinaryString(self.defaultBinValue) + + elif self.defaultHexValue is not noValue: + value = self.fromHexString(self.defaultHexValue) + + if 'encoding' not in kwargs: + kwargs['encoding'] = self.encoding + + base.SimpleAsn1Type.__init__(self, value, **kwargs) + + if sys.version_info[0] <= 2: + def prettyIn(self, value): + if isinstance(value, str): + return value + + elif isinstance(value, unicode): + try: + return value.encode(self.encoding) + + except (LookupError, UnicodeEncodeError): + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with codec " + "%s" % (value, self.encoding), exc + ) + + elif isinstance(value, (tuple, list)): + try: + return ''.join([chr(x) for x in value]) + + except ValueError: + raise error.PyAsn1Error( + "Bad %s initializer '%s'" % (self.__class__.__name__, value) + ) + + else: + return str(value) + + def __str__(self): + return str(self._value) + + def __unicode__(self): + try: + return self._value.decode(self.encoding) + + except UnicodeDecodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with codec " + "%s" % (self._value, self.encoding), exc + ) + + def asOctets(self): + return str(self._value) + + def asNumbers(self): + return tuple([ord(x) for x in self._value]) + + else: + def prettyIn(self, value): + if isinstance(value, bytes): + return value + + elif isinstance(value, str): + try: + return value.encode(self.encoding) + + except UnicodeEncodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeEncodeError( + "Can't encode string '%s' with '%s' " + "codec" % (value, self.encoding), exc + ) + elif isinstance(value, OctetString): # a shortcut, bytes() would work the same way + return value.asOctets() + + elif isinstance(value, base.SimpleAsn1Type): # this mostly targets Integer objects + return self.prettyIn(str(value)) + + elif isinstance(value, (tuple, list)): + return self.prettyIn(bytes(value)) + + else: + return bytes(value) + + def __str__(self): + try: + return self._value.decode(self.encoding) + + except UnicodeDecodeError: + exc = sys.exc_info()[1] + raise error.PyAsn1UnicodeDecodeError( + "Can't decode string '%s' with '%s' codec at " + "'%s'" % (self._value, self.encoding, + self.__class__.__name__), exc + ) + + def __bytes__(self): + return bytes(self._value) + + def asOctets(self): + return bytes(self._value) + + def asNumbers(self): + return tuple(self._value) + + # + # Normally, `.prettyPrint()` is called from `__str__()`. Historically, + # OctetString.prettyPrint() used to return hexified payload + # representation in cases when non-printable content is present. At the + # same time `str()` used to produce either octet-stream (Py2) or + # text (Py3) representations. + # + # Therefore `OctetString.__str__()` -> `.prettyPrint()` call chain is + # reversed to preserve the original behaviour. + # + # Eventually we should deprecate `.prettyPrint()` / `.prettyOut()` harness + # and end up with just `__str__()` producing hexified representation while + # both text and octet-stream representation should only be requested via + # the `.asOctets()` method. + # + # Note: ASN.1 OCTET STRING is never mean to contain text! + # + + def prettyOut(self, value): + return value + + def prettyPrint(self, scope=0): + # first see if subclass has its own .prettyOut() + value = self.prettyOut(self._value) + + if value is not self._value: + return value + + numbers = self.asNumbers() + + for x in numbers: + # hexify if needed + if x < 32 or x > 126: + return '0x' + ''.join(('%.2x' % x for x in numbers)) + else: + # this prevents infinite recursion + return OctetString.__str__(self) + + @staticmethod + def fromBinaryString(value): + """Create a |ASN.1| object initialized from a string of '0' and '1'. + + Parameters + ---------- + value: :class:`str` + Text string like '1010111' + """ + bitNo = 8 + byte = 0 + r = [] + for v in value: + if bitNo: + bitNo -= 1 + else: + bitNo = 7 + r.append(byte) + byte = 0 + if v in ('0', '1'): + v = int(v) + else: + raise error.PyAsn1Error( + 'Non-binary OCTET STRING initializer %s' % (v,) + ) + byte |= v << bitNo + + r.append(byte) + + return octets.ints2octs(r) + + @staticmethod + def fromHexString(value): + """Create a |ASN.1| object initialized from the hex string. + + Parameters + ---------- + value: :class:`str` + Text string like 'DEADBEEF' + """ + r = [] + p = [] + for v in value: + if p: + r.append(int(p + v, 16)) + p = None + else: + p = v + if p: + r.append(int(p + '0', 16)) + + return octets.ints2octs(r) + + # Immutable sequence object protocol + + def __len__(self): + return len(self._value) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.clone(self._value[i]) + else: + return self._value[i] + + def __iter__(self): + return iter(self._value) + + def __contains__(self, value): + return value in self._value + + def __add__(self, value): + return self.clone(self._value + self.prettyIn(value)) + + def __radd__(self, value): + return self.clone(self.prettyIn(value) + self._value) + + def __mul__(self, value): + return self.clone(self._value * value) + + def __rmul__(self, value): + return self * value + + def __int__(self): + return int(self._value) + + def __float__(self): + return float(self._value) + + def __reversed__(self): + return reversed(self._value) + + +class Null(OctetString): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`str` objects + (always empty). + + Keyword Args + ------------ + value: :class:`str` or |ASN.1| object + Python empty :class:`str` literal or any object that evaluates to :obj:`False` + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Ack(Null): + ''' + ASN.1 specification: + + Ack ::= NULL + ''' + ack = Ack('') + """ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) + ) + subtypeSpec = OctetString.subtypeSpec + constraint.SingleValueConstraint(octets.str2octs('')) + + # Optimization for faster codec lookup + typeId = OctetString.getTypeId() + + def prettyIn(self, value): + if value: + return value + + return octets.str2octs('') + +if sys.version_info[0] <= 2: + intTypes = (int, long) +else: + intTypes = (int,) + +numericTypes = intTypes + (float,) + + +class ObjectIdentifier(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`tuple` objects + (tuple of non-negative integers). + + Keyword Args + ------------ + value: :class:`tuple`, :class:`str` or |ASN.1| object + Python sequence of :class:`int` or :class:`str` literal or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class ID(ObjectIdentifier): + ''' + ASN.1 specification: + + ID ::= OBJECT IDENTIFIER + + id-edims ID ::= { joint-iso-itu-t mhs-motif(6) edims(7) } + id-bp ID ::= { id-edims 11 } + ''' + id_edims = ID('2.6.7') + id_bp = id_edims + (11,) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + def __add__(self, other): + return self.clone(self._value + other) + + def __radd__(self, other): + return self.clone(other + self._value) + + def asTuple(self): + return self._value + + # Sequence object protocol + + def __len__(self): + return len(self._value) + + def __getitem__(self, i): + if i.__class__ is slice: + return self.clone(self._value[i]) + else: + return self._value[i] + + def __iter__(self): + return iter(self._value) + + def __contains__(self, value): + return value in self._value + + def index(self, suboid): + return self._value.index(suboid) + + def isPrefixOf(self, other): + """Indicate if this |ASN.1| object is a prefix of other |ASN.1| object. + + Parameters + ---------- + other: |ASN.1| object + |ASN.1| object + + Returns + ------- + : :class:`bool` + :obj:`True` if this |ASN.1| object is a parent (e.g. prefix) of the other |ASN.1| object + or :obj:`False` otherwise. + """ + l = len(self) + if l <= len(other): + if self._value[:l] == other[:l]: + return True + return False + + def prettyIn(self, value): + if isinstance(value, ObjectIdentifier): + return tuple(value) + elif octets.isStringType(value): + if '-' in value: + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + try: + return tuple([int(subOid) for subOid in value.split('.') if subOid]) + except ValueError: + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + + try: + tupleOfInts = tuple([int(subOid) for subOid in value if subOid >= 0]) + + except (ValueError, TypeError): + raise error.PyAsn1Error( + 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) + ) + + if len(tupleOfInts) == len(value): + return tupleOfInts + + raise error.PyAsn1Error('Malformed Object ID %s at %s' % (value, self.__class__.__name__)) + + def prettyOut(self, value): + return '.'.join([str(x) for x in value]) + + +class Real(base.SimpleAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`float` objects. + Additionally, |ASN.1| objects behave like a :class:`tuple` in which case its + elements are mantissa, base and exponent. + + Keyword Args + ------------ + value: :class:`tuple`, :class:`float` or |ASN.1| object + Python sequence of :class:`int` (representing mantissa, base and + exponent) or :class:`float` instance or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Pi(Real): + ''' + ASN.1 specification: + + Pi ::= REAL + + pi Pi ::= { mantissa 314159, base 10, exponent -5 } + + ''' + pi = Pi((314159, 10, -5)) + """ + binEncBase = None # binEncBase = 16 is recommended for large numbers + + try: + _plusInf = float('inf') + _minusInf = float('-inf') + _inf = _plusInf, _minusInf + + except ValueError: + # Infinity support is platform and Python dependent + _plusInf = _minusInf = None + _inf = () + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = base.SimpleAsn1Type.getTypeId() + + @staticmethod + def __normalizeBase10(value): + m, b, e = value + while m and m % 10 == 0: + m /= 10 + e += 1 + return m, b, e + + def prettyIn(self, value): + if isinstance(value, tuple) and len(value) == 3: + if (not isinstance(value[0], numericTypes) or + not isinstance(value[1], intTypes) or + not isinstance(value[2], intTypes)): + raise error.PyAsn1Error('Lame Real value syntax: %s' % (value,)) + if (isinstance(value[0], float) and + self._inf and value[0] in self._inf): + return value[0] + if value[1] not in (2, 10): + raise error.PyAsn1Error( + 'Prohibited base for Real value: %s' % (value[1],) + ) + if value[1] == 10: + value = self.__normalizeBase10(value) + return value + elif isinstance(value, intTypes): + return self.__normalizeBase10((value, 10, 0)) + elif isinstance(value, float) or octets.isStringType(value): + if octets.isStringType(value): + try: + value = float(value) + except ValueError: + raise error.PyAsn1Error( + 'Bad real value syntax: %s' % (value,) + ) + if self._inf and value in self._inf: + return value + else: + e = 0 + while int(value) != value: + value *= 10 + e -= 1 + return self.__normalizeBase10((int(value), 10, e)) + elif isinstance(value, Real): + return tuple(value) + raise error.PyAsn1Error( + 'Bad real value syntax: %s' % (value,) + ) + + def prettyPrint(self, scope=0): + try: + return self.prettyOut(float(self)) + + except OverflowError: + return '' + + @property + def isPlusInf(self): + """Indicate PLUS-INFINITY object value + + Returns + ------- + : :class:`bool` + :obj:`True` if calling object represents plus infinity + or :obj:`False` otherwise. + + """ + return self._value == self._plusInf + + @property + def isMinusInf(self): + """Indicate MINUS-INFINITY object value + + Returns + ------- + : :class:`bool` + :obj:`True` if calling object represents minus infinity + or :obj:`False` otherwise. + """ + return self._value == self._minusInf + + @property + def isInf(self): + return self._value in self._inf + + def __add__(self, value): + return self.clone(float(self) + value) + + def __radd__(self, value): + return self + value + + def __mul__(self, value): + return self.clone(float(self) * value) + + def __rmul__(self, value): + return self * value + + def __sub__(self, value): + return self.clone(float(self) - value) + + def __rsub__(self, value): + return self.clone(value - float(self)) + + def __mod__(self, value): + return self.clone(float(self) % value) + + def __rmod__(self, value): + return self.clone(value % float(self)) + + def __pow__(self, value, modulo=None): + return self.clone(pow(float(self), value, modulo)) + + def __rpow__(self, value): + return self.clone(pow(value, float(self))) + + if sys.version_info[0] <= 2: + def __div__(self, value): + return self.clone(float(self) / value) + + def __rdiv__(self, value): + return self.clone(value / float(self)) + else: + def __truediv__(self, value): + return self.clone(float(self) / value) + + def __rtruediv__(self, value): + return self.clone(value / float(self)) + + def __divmod__(self, value): + return self.clone(float(self) // value) + + def __rdivmod__(self, value): + return self.clone(value // float(self)) + + def __int__(self): + return int(float(self)) + + if sys.version_info[0] <= 2: + def __long__(self): + return long(float(self)) + + def __float__(self): + if self._value in self._inf: + return self._value + else: + return float( + self._value[0] * pow(self._value[1], self._value[2]) + ) + + def __abs__(self): + return self.clone(abs(float(self))) + + def __pos__(self): + return self.clone(+float(self)) + + def __neg__(self): + return self.clone(-float(self)) + + def __round__(self, n=0): + r = round(float(self), n) + if n: + return self.clone(r) + else: + return r + + def __floor__(self): + return self.clone(math.floor(float(self))) + + def __ceil__(self): + return self.clone(math.ceil(float(self))) + + if sys.version_info[0:2] > (2, 5): + def __trunc__(self): + return self.clone(math.trunc(float(self))) + + def __lt__(self, value): + return float(self) < value + + def __le__(self, value): + return float(self) <= value + + def __eq__(self, value): + return float(self) == value + + def __ne__(self, value): + return float(self) != value + + def __gt__(self, value): + return float(self) > value + + def __ge__(self, value): + return float(self) >= value + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return bool(float(self)) + else: + def __bool__(self): + return bool(float(self)) + + __hash__ = base.SimpleAsn1Type.__hash__ + + def __getitem__(self, idx): + if self._value in self._inf: + raise error.PyAsn1Error('Invalid infinite value operation') + else: + return self._value[idx] + + # compatibility stubs + + def isPlusInfinity(self): + return self.isPlusInf + + def isMinusInfinity(self): + return self.isMinusInf + + def isInfinity(self): + return self.isInf + + +class Enumerated(Integer): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its + objects are immutable and duck-type Python :class:`int` objects. + + Keyword Args + ------------ + value: :class:`int`, :class:`str` or |ASN.1| object + Python :class:`int` or :class:`str` literal or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` + Object representing non-default symbolic aliases for numbers + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + + .. code-block:: python + + class RadioButton(Enumerated): + ''' + ASN.1 specification: + + RadioButton ::= ENUMERATED { button1(0), button2(1), + button3(2) } + + selected-by-default RadioButton ::= button1 + ''' + namedValues = NamedValues( + ('button1', 0), ('button2', 1), + ('button3', 2) + ) + + selected_by_default = RadioButton('button1') + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x0A) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Optimization for faster codec lookup + typeId = Integer.getTypeId() + + #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object + #: representing symbolic aliases for numbers + namedValues = namedval.NamedValues() + + +# "Structured" ASN.1 types + +class SequenceOfAndSetOfBase(base.ConstructedAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, + its objects are mutable and duck-type Python :class:`list` objects. + + Keyword Args + ------------ + componentType : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A pyasn1 object representing ASN.1 type allowed within |ASN.1| type + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type can only occur on explicit + `.isInconsistent` call. + + Examples + -------- + + .. code-block:: python + + class LotteryDraw(SequenceOf): # SetOf is similar + ''' + ASN.1 specification: + + LotteryDraw ::= SEQUENCE OF INTEGER + ''' + componentType = Integer() + + lotteryDraw = LotteryDraw() + lotteryDraw.extend([123, 456, 789]) + """ + def __init__(self, *args, **kwargs): + # support positional params for backward compatibility + if args: + for key, value in zip(('componentType', 'tagSet', + 'subtypeSpec'), args): + if key in kwargs: + raise error.PyAsn1Error('Conflicting positional and keyword params!') + kwargs['componentType'] = value + + self._componentValues = noValue + + base.ConstructedAsn1Type.__init__(self, **kwargs) + + # Python list protocol + + def __getitem__(self, idx): + try: + return self.getComponentByPosition(idx) + + except error.PyAsn1Error: + raise IndexError(sys.exc_info()[1]) + + def __setitem__(self, idx, value): + try: + self.setComponentByPosition(idx, value) + + except error.PyAsn1Error: + raise IndexError(sys.exc_info()[1]) + + def append(self, value): + if self._componentValues is noValue: + pos = 0 + + else: + pos = len(self._componentValues) + + self[pos] = value + + def count(self, value): + return list(self._componentValues.values()).count(value) + + def extend(self, values): + for value in values: + self.append(value) + + if self._componentValues is noValue: + self._componentValues = {} + + def index(self, value, start=0, stop=None): + if stop is None: + stop = len(self) + + indices, values = zip(*self._componentValues.items()) + + # TODO: remove when Py2.5 support is gone + values = list(values) + + try: + return indices[values.index(value, start, stop)] + + except error.PyAsn1Error: + raise ValueError(sys.exc_info()[1]) + + def reverse(self): + self._componentValues.reverse() + + def sort(self, key=None, reverse=False): + self._componentValues = dict( + enumerate(sorted(self._componentValues.values(), + key=key, reverse=reverse))) + + def __len__(self): + if self._componentValues is noValue or not self._componentValues: + return 0 + + return max(self._componentValues) + 1 + + def __iter__(self): + for idx in range(0, len(self)): + yield self.getComponentByPosition(idx) + + def _cloneComponentValues(self, myClone, cloneValueFlag): + for idx, componentValue in self._componentValues.items(): + if componentValue is not noValue: + if isinstance(componentValue, base.ConstructedAsn1Type): + myClone.setComponentByPosition( + idx, componentValue.clone(cloneValueFlag=cloneValueFlag) + ) + else: + myClone.setComponentByPosition(idx, componentValue.clone()) + + def getComponentByPosition(self, idx, default=noValue, instantiate=True): + """Return |ASN.1| type component value by position. + + Equivalent to Python sequence subscription operation (e.g. `[]`). + + Parameters + ---------- + idx : :class:`int` + Component index (zero-based). Must either refer to an existing + component or to N+1 component (if *componentType* is set). In the latter + case a new component type gets instantiated and appended to the |ASN.1| + sequence. + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically instantiated. + If :obj:`False` either existing component or the :class:`NoValue` object will be + returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + Instantiate |ASN.1| component type or return existing component value + + Examples + -------- + + .. code-block:: python + + # can also be SetOf + class MySequenceOf(SequenceOf): + componentType = OctetString() + + s = MySequenceOf() + + # returns component #0 with `.isValue` property False + s.getComponentByPosition(0) + + # returns None + s.getComponentByPosition(0, default=None) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + + # sets component #0 to OctetString() ASN.1 schema + # object and returns it + s.getComponentByPosition(0, instantiate=True) + + # sets component #0 to ASN.1 value object + s.setComponentByPosition(0, 'ABCD') + + # returns OctetString('ABCD') value object + s.getComponentByPosition(0, instantiate=False) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + """ + if isinstance(idx, slice): + indices = tuple(range(len(self))) + return [self.getComponentByPosition(subidx, default, instantiate) + for subidx in indices[idx]] + + if idx < 0: + idx = len(self) + idx + if idx < 0: + raise error.PyAsn1Error( + 'SequenceOf/SetOf index is out of range') + + try: + componentValue = self._componentValues[idx] + + except (KeyError, error.PyAsn1Error): + if not instantiate: + return default + + self.setComponentByPosition(idx) + + componentValue = self._componentValues[idx] + + if default is noValue or componentValue.isValue: + return componentValue + else: + return default + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`) + or list.append() (when idx == len(self)). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to existing + component or to N+1 component. In the latter case a new component + type gets instantiated (if *componentType* is set, or given ASN.1 + object is taken otherwise) and appended to the |ASN.1| sequence. + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints: :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer + IndexError + When idx > len(self) + """ + if isinstance(idx, slice): + indices = tuple(range(len(self))) + startIdx = indices and indices[idx][0] or 0 + for subIdx, subValue in enumerate(value): + self.setComponentByPosition( + startIdx + subIdx, subValue, verifyConstraints, + matchTags, matchConstraints) + return self + + if idx < 0: + idx = len(self) + idx + if idx < 0: + raise error.PyAsn1Error( + 'SequenceOf/SetOf index is out of range') + + componentType = self.componentType + + if self._componentValues is noValue: + componentValues = {} + + else: + componentValues = self._componentValues + + currentValue = componentValues.get(idx, noValue) + + if value is noValue: + if componentType is not None: + value = componentType.clone() + + elif currentValue is noValue: + raise error.PyAsn1Error('Component type not defined') + + elif not isinstance(value, base.Asn1Item): + if (componentType is not None and + isinstance(componentType, base.SimpleAsn1Type)): + value = componentType.clone(value=value) + + elif (currentValue is not noValue and + isinstance(currentValue, base.SimpleAsn1Type)): + value = currentValue.clone(value=value) + + else: + raise error.PyAsn1Error( + 'Non-ASN.1 value %r and undefined component' + ' type at %r' % (value, self)) + + elif componentType is not None and (matchTags or matchConstraints): + subtypeChecker = ( + self.strictConstraints and + componentType.isSameTypeWith or + componentType.isSuperTypeOf) + + if not subtypeChecker(value, verifyConstraints and matchTags, + verifyConstraints and matchConstraints): + # TODO: we should wrap componentType with UnnamedType to carry + # additional properties associated with componentType + if componentType.typeId != Any.typeId: + raise error.PyAsn1Error( + 'Component value is tag-incompatible: %r vs ' + '%r' % (value, componentType)) + + componentValues[idx] = value + + self._componentValues = componentValues + + return self + + @property + def componentTagMap(self): + if self.componentType is not None: + return self.componentType.tagMap + + @property + def components(self): + return [self._componentValues[idx] + for idx in sorted(self._componentValues)] + + def clear(self): + """Remove all components and become an empty |ASN.1| value object. + + Has the same effect on |ASN.1| object as it does on :class:`list` + built-in. + """ + self._componentValues = {} + return self + + def reset(self): + """Remove all components and become a |ASN.1| schema object. + + See :meth:`isValue` property for more information on the + distinction between value and schema objects. + """ + self._componentValues = noValue + return self + + def prettyPrint(self, scope=0): + scope += 1 + representation = self.__class__.__name__ + ':\n' + + if not self.isValue: + return representation + + for idx, componentValue in enumerate(self): + representation += ' ' * scope + if (componentValue is noValue and + self.componentType is not None): + representation += '' + else: + representation += componentValue.prettyPrint(scope) + + return representation + + def prettyPrintType(self, scope=0): + scope += 1 + representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) + if self.componentType is not None: + representation += ' ' * scope + representation += self.componentType.prettyPrintType(scope) + return representation + '\n' + ' ' * (scope - 1) + '}' + + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object + (e.g. :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a normal value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + """ + if self._componentValues is noValue: + return False + + if len(self._componentValues) != len(self): + return False + + for componentValue in self._componentValues.values(): + if componentValue is noValue or not componentValue.isValue: + return False + + return True + + @property + def isInconsistent(self): + """Run necessary checks to ensure |ASN.1| object consistency. + + Default action is to verify |ASN.1| object against constraints imposed + by `subtypeSpec`. + + Raises + ------ + :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found + """ + if self.componentType is noValue or not self.subtypeSpec: + return False + + if self._componentValues is noValue: + return True + + mapping = {} + + for idx, value in self._componentValues.items(): + # Absent fields are not in the mapping + if value is noValue: + continue + + mapping[idx] = value + + try: + # Represent SequenceOf/SetOf as a bare dict to constraints chain + self.subtypeSpec(mapping) + + except error.PyAsn1Error: + exc = sys.exc_info()[1] + return exc + + return False + +class SequenceOf(SequenceOfAndSetOfBase): + __doc__ = SequenceOfAndSetOfBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) + ) + + #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = None + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceOfAndSetOfBase.getTypeId() + + +class SetOf(SequenceOfAndSetOfBase): + __doc__ = SequenceOfAndSetOfBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ) + + #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = None + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceOfAndSetOfBase.getTypeId() + + +class SequenceAndSetBase(base.ConstructedAsn1Type): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, + its objects are mutable and duck-type Python :class:`dict` objects. + + Keyword Args + ------------ + componentType: :py:class:`~pyasn1.type.namedtype.NamedType` + Object holding named ASN.1 types allowed within this collection + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type can only occur on explicit + `.isInconsistent` call. + + Examples + -------- + + .. code-block:: python + + class Description(Sequence): # Set is similar + ''' + ASN.1 specification: + + Description ::= SEQUENCE { + surname IA5String, + first-name IA5String OPTIONAL, + age INTEGER DEFAULT 40 + } + ''' + componentType = NamedTypes( + NamedType('surname', IA5String()), + OptionalNamedType('first-name', IA5String()), + DefaultedNamedType('age', Integer(40)) + ) + + descr = Description() + descr['surname'] = 'Smith' + descr['first-name'] = 'John' + """ + #: Default :py:class:`~pyasn1.type.namedtype.NamedTypes` + #: object representing named ASN.1 types allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + + class DynamicNames(object): + """Fields names/positions mapping for component-less objects""" + def __init__(self): + self._keyToIdxMap = {} + self._idxToKeyMap = {} + + def __len__(self): + return len(self._keyToIdxMap) + + def __contains__(self, item): + return item in self._keyToIdxMap or item in self._idxToKeyMap + + def __iter__(self): + return (self._idxToKeyMap[idx] for idx in range(len(self._idxToKeyMap))) + + def __getitem__(self, item): + try: + return self._keyToIdxMap[item] + + except KeyError: + return self._idxToKeyMap[item] + + def getNameByPosition(self, idx): + try: + return self._idxToKeyMap[idx] + + except KeyError: + raise error.PyAsn1Error('Type position out of range') + + def getPositionByName(self, name): + try: + return self._keyToIdxMap[name] + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + def addField(self, idx): + self._keyToIdxMap['field-%d' % idx] = idx + self._idxToKeyMap[idx] = 'field-%d' % idx + + + def __init__(self, **kwargs): + base.ConstructedAsn1Type.__init__(self, **kwargs) + self._componentTypeLen = len(self.componentType) + if self._componentTypeLen: + self._componentValues = [] + else: + self._componentValues = noValue + self._dynamicNames = self._componentTypeLen or self.DynamicNames() + + def __getitem__(self, idx): + if octets.isStringType(idx): + try: + return self.getComponentByName(idx) + + except error.PyAsn1Error: + # duck-typing dict + raise KeyError(sys.exc_info()[1]) + + else: + try: + return self.getComponentByPosition(idx) + + except error.PyAsn1Error: + # duck-typing list + raise IndexError(sys.exc_info()[1]) + + def __setitem__(self, idx, value): + if octets.isStringType(idx): + try: + self.setComponentByName(idx, value) + + except error.PyAsn1Error: + # duck-typing dict + raise KeyError(sys.exc_info()[1]) + + else: + try: + self.setComponentByPosition(idx, value) + + except error.PyAsn1Error: + # duck-typing list + raise IndexError(sys.exc_info()[1]) + + def __contains__(self, key): + if self._componentTypeLen: + return key in self.componentType + else: + return key in self._dynamicNames + + def __len__(self): + return len(self._componentValues) + + def __iter__(self): + return iter(self.componentType or self._dynamicNames) + + # Python dict protocol + + def values(self): + for idx in range(self._componentTypeLen or len(self._dynamicNames)): + yield self[idx] + + def keys(self): + return iter(self) + + def items(self): + for idx in range(self._componentTypeLen or len(self._dynamicNames)): + if self._componentTypeLen: + yield self.componentType[idx].name, self[idx] + else: + yield self._dynamicNames[idx], self[idx] + + def update(self, *iterValue, **mappingValue): + for k, v in iterValue: + self[k] = v + for k in mappingValue: + self[k] = mappingValue[k] + + def clear(self): + """Remove all components and become an empty |ASN.1| value object. + + Has the same effect on |ASN.1| object as it does on :class:`dict` + built-in. + """ + self._componentValues = [] + self._dynamicNames = self.DynamicNames() + return self + + def reset(self): + """Remove all components and become a |ASN.1| schema object. + + See :meth:`isValue` property for more information on the + distinction between value and schema objects. + """ + self._componentValues = noValue + self._dynamicNames = self.DynamicNames() + return self + + @property + def components(self): + return self._componentValues + + def _cloneComponentValues(self, myClone, cloneValueFlag): + if self._componentValues is noValue: + return + + for idx, componentValue in enumerate(self._componentValues): + if componentValue is not noValue: + if isinstance(componentValue, base.ConstructedAsn1Type): + myClone.setComponentByPosition( + idx, componentValue.clone(cloneValueFlag=cloneValueFlag) + ) + else: + myClone.setComponentByPosition(idx, componentValue.clone()) + + def getComponentByName(self, name, default=noValue, instantiate=True): + """Returns |ASN.1| type component by name. + + Equivalent to Python :class:`dict` subscription operation (e.g. `[]`). + + Parameters + ---------- + name: :class:`str` + |ASN.1| type component name + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically + instantiated. + If :obj:`False` either existing component or the :class:`NoValue` + object will be returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + Instantiate |ASN.1| component type or return existing + component value + """ + if self._componentTypeLen: + idx = self.componentType.getPositionByName(name) + else: + try: + idx = self._dynamicNames.getPositionByName(name) + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + return self.getComponentByPosition(idx, default=default, instantiate=instantiate) + + def setComponentByName(self, name, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by name. + + Equivalent to Python :class:`dict` item assignment operation (e.g. `[]`). + + Parameters + ---------- + name: :class:`str` + |ASN.1| type component name + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints: :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + """ + if self._componentTypeLen: + idx = self.componentType.getPositionByName(name) + else: + try: + idx = self._dynamicNames.getPositionByName(name) + + except KeyError: + raise error.PyAsn1Error('Name %s not found' % (name,)) + + return self.setComponentByPosition( + idx, value, verifyConstraints, matchTags, matchConstraints + ) + + def getComponentByPosition(self, idx, default=noValue, instantiate=True): + """Returns |ASN.1| type component by index. + + Equivalent to Python sequence subscription operation (e.g. `[]`). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to an existing + component or (if *componentType* is set) new ASN.1 schema object gets + instantiated. + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically + instantiated. + If :obj:`False` either existing component or the :class:`NoValue` + object will be returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a PyASN1 object + + Examples + -------- + + .. code-block:: python + + # can also be Set + class MySequence(Sequence): + componentType = NamedTypes( + NamedType('id', OctetString()) + ) + + s = MySequence() + + # returns component #0 with `.isValue` property False + s.getComponentByPosition(0) + + # returns None + s.getComponentByPosition(0, default=None) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + + # sets component #0 to OctetString() ASN.1 schema + # object and returns it + s.getComponentByPosition(0, instantiate=True) + + # sets component #0 to ASN.1 value object + s.setComponentByPosition(0, 'ABCD') + + # returns OctetString('ABCD') value object + s.getComponentByPosition(0, instantiate=False) + + s.clear() + + # returns noValue + s.getComponentByPosition(0, instantiate=False) + """ + try: + if self._componentValues is noValue: + componentValue = noValue + + else: + componentValue = self._componentValues[idx] + + except IndexError: + componentValue = noValue + + if not instantiate: + if componentValue is noValue or not componentValue.isValue: + return default + else: + return componentValue + + if componentValue is noValue: + self.setComponentByPosition(idx) + + componentValue = self._componentValues[idx] + + if default is noValue or componentValue.isValue: + return componentValue + else: + return default + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`). + + Parameters + ---------- + idx : :class:`int` + Component index (zero-based). Must either refer to existing + component (if *componentType* is set) or to N+1 component + otherwise. In the latter case a new component of given ASN.1 + type gets instantiated and appended to |ASN.1| sequence. + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints : :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + """ + componentType = self.componentType + componentTypeLen = self._componentTypeLen + + if self._componentValues is noValue: + componentValues = [] + + else: + componentValues = self._componentValues + + try: + currentValue = componentValues[idx] + + except IndexError: + currentValue = noValue + if componentTypeLen: + if componentTypeLen < idx: + raise error.PyAsn1Error('component index out of range') + + componentValues = [noValue] * componentTypeLen + + if value is noValue: + if componentTypeLen: + value = componentType.getTypeByPosition(idx) + if isinstance(value, base.ConstructedAsn1Type): + value = value.clone(cloneValueFlag=componentType[idx].isDefaulted) + + elif currentValue is noValue: + raise error.PyAsn1Error('Component type not defined') + + elif not isinstance(value, base.Asn1Item): + if componentTypeLen: + subComponentType = componentType.getTypeByPosition(idx) + if isinstance(subComponentType, base.SimpleAsn1Type): + value = subComponentType.clone(value=value) + + else: + raise error.PyAsn1Error('%s can cast only scalar values' % componentType.__class__.__name__) + + elif currentValue is not noValue and isinstance(currentValue, base.SimpleAsn1Type): + value = currentValue.clone(value=value) + + else: + raise error.PyAsn1Error('%s undefined component type' % componentType.__class__.__name__) + + elif ((verifyConstraints or matchTags or matchConstraints) and + componentTypeLen): + subComponentType = componentType.getTypeByPosition(idx) + if subComponentType is not noValue: + subtypeChecker = (self.strictConstraints and + subComponentType.isSameTypeWith or + subComponentType.isSuperTypeOf) + + if not subtypeChecker(value, verifyConstraints and matchTags, + verifyConstraints and matchConstraints): + if not componentType[idx].openType: + raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) + + if componentTypeLen or idx in self._dynamicNames: + componentValues[idx] = value + + elif len(componentValues) == idx: + componentValues.append(value) + self._dynamicNames.addField(idx) + + else: + raise error.PyAsn1Error('Component index out of range') + + self._componentValues = componentValues + + return self + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. + :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a + normal value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + + It is sufficient for |ASN.1| objects to have all non-optional and non-defaulted + components being value objects to be considered as a value objects as a whole. + In other words, even having one or more optional components not turned into + value objects, |ASN.1| object is still considered as a value object. Defaulted + components are normally value objects by default. + """ + if self._componentValues is noValue: + return False + + componentType = self.componentType + + if componentType: + for idx, subComponentType in enumerate(componentType.namedTypes): + if subComponentType.isDefaulted or subComponentType.isOptional: + continue + + if not self._componentValues: + return False + + componentValue = self._componentValues[idx] + if componentValue is noValue or not componentValue.isValue: + return False + + else: + for componentValue in self._componentValues: + if componentValue is noValue or not componentValue.isValue: + return False + + return True + + @property + def isInconsistent(self): + """Run necessary checks to ensure |ASN.1| object consistency. + + Default action is to verify |ASN.1| object against constraints imposed + by `subtypeSpec`. + + Raises + ------ + :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found + """ + if self.componentType is noValue or not self.subtypeSpec: + return False + + if self._componentValues is noValue: + return True + + mapping = {} + + for idx, value in enumerate(self._componentValues): + # Absent fields are not in the mapping + if value is noValue: + continue + + name = self.componentType.getNameByPosition(idx) + + mapping[name] = value + + try: + # Represent Sequence/Set as a bare dict to constraints chain + self.subtypeSpec(mapping) + + except error.PyAsn1Error: + exc = sys.exc_info()[1] + return exc + + return False + + def prettyPrint(self, scope=0): + """Return an object representation string. + + Returns + ------- + : :class:`str` + Human-friendly object representation. + """ + scope += 1 + representation = self.__class__.__name__ + ':\n' + for idx, componentValue in enumerate(self._componentValues): + if componentValue is not noValue and componentValue.isValue: + representation += ' ' * scope + if self.componentType: + representation += self.componentType.getNameByPosition(idx) + else: + representation += self._dynamicNames.getNameByPosition(idx) + representation = '%s=%s\n' % ( + representation, componentValue.prettyPrint(scope) + ) + return representation + + def prettyPrintType(self, scope=0): + scope += 1 + representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) + for idx, componentType in enumerate(self.componentType.values() or self._componentValues): + representation += ' ' * scope + if self.componentType: + representation += '"%s"' % self.componentType.getNameByPosition(idx) + else: + representation += '"%s"' % self._dynamicNames.getNameByPosition(idx) + representation = '%s = %s\n' % ( + representation, componentType.prettyPrintType(scope) + ) + return representation + '\n' + ' ' * (scope - 1) + '}' + + # backward compatibility + + def setDefaultComponents(self): + return self + + def getComponentType(self): + if self._componentTypeLen: + return self.componentType + + def getNameByPosition(self, idx): + if self._componentTypeLen: + return self.componentType[idx].name + +class Sequence(SequenceAndSetBase): + __doc__ = SequenceAndSetBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) + ) + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object imposing size constraint on |ASN.1| objects + componentType = namedtype.NamedTypes() + + # Disambiguation ASN.1 types identification + typeId = SequenceAndSetBase.getTypeId() + + # backward compatibility + + def getComponentTagMapNearPosition(self, idx): + if self.componentType: + return self.componentType.getTagMapNearPosition(idx) + + def getComponentPositionNearType(self, tagSet, idx): + if self.componentType: + return self.componentType.getPositionNearType(tagSet, idx) + else: + return idx + + +class Set(SequenceAndSetBase): + __doc__ = SequenceAndSetBase.__doc__ + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.initTagSet( + tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) + ) + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = SequenceAndSetBase.getTypeId() + + def getComponent(self, innerFlag=False): + return self + + def getComponentByType(self, tagSet, default=noValue, + instantiate=True, innerFlag=False): + """Returns |ASN.1| type component by ASN.1 tag. + + Parameters + ---------- + tagSet : :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tags to identify one of + |ASN.1| object component + + Keyword Args + ------------ + default: :class:`object` + If set and requested component is a schema object, return the `default` + object instead of the requested component. + + instantiate: :class:`bool` + If :obj:`True` (default), inner component will be automatically + instantiated. + If :obj:`False` either existing component or the :class:`noValue` + object will be returned. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a pyasn1 object + """ + componentValue = self.getComponentByPosition( + self.componentType.getPositionByType(tagSet), + default=default, instantiate=instantiate + ) + if innerFlag and isinstance(componentValue, Set): + # get inner component by inner tagSet + return componentValue.getComponent(innerFlag=True) + else: + # get outer component by inner tagSet + return componentValue + + def setComponentByType(self, tagSet, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True, + innerFlag=False): + """Assign |ASN.1| type component by ASN.1 tag. + + Parameters + ---------- + tagSet : :py:class:`~pyasn1.type.tag.TagSet` + Object representing ASN.1 tags to identify one of + |ASN.1| object component + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. + If `value` is not given, schema object will be set as a component. + + verifyConstraints : :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + innerFlag: :class:`bool` + If :obj:`True`, search for matching *tagSet* recursively. + + Returns + ------- + self + """ + idx = self.componentType.getPositionByType(tagSet) + + if innerFlag: # set inner component by inner tagSet + componentType = self.componentType.getTypeByPosition(idx) + + if componentType.tagSet: + return self.setComponentByPosition( + idx, value, verifyConstraints, matchTags, matchConstraints + ) + else: + componentType = self.getComponentByPosition(idx) + return componentType.setComponentByType( + tagSet, value, verifyConstraints, matchTags, matchConstraints, innerFlag=innerFlag + ) + else: # set outer component by inner tagSet + return self.setComponentByPosition( + idx, value, verifyConstraints, matchTags, matchConstraints + ) + + @property + def componentTagMap(self): + if self.componentType: + return self.componentType.tagMapUnique + + +class Choice(Set): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, + its objects are mutable and duck-type Python :class:`list` objects. + + Keyword Args + ------------ + componentType: :py:class:`~pyasn1.type.namedtype.NamedType` + Object holding named ASN.1 types allowed within this collection + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type can only occur on explicit + `.isInconsistent` call. + + Examples + -------- + + .. code-block:: python + + class Afters(Choice): + ''' + ASN.1 specification: + + Afters ::= CHOICE { + cheese [0] IA5String, + dessert [1] IA5String + } + ''' + componentType = NamedTypes( + NamedType('cheese', IA5String().subtype( + implicitTag=Tag(tagClassContext, tagFormatSimple, 0) + ), + NamedType('dessert', IA5String().subtype( + implicitTag=Tag(tagClassContext, tagFormatSimple, 1) + ) + ) + + afters = Afters() + afters['cheese'] = 'Mascarpone' + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.TagSet() # untagged + + #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) + #: object representing ASN.1 type allowed within |ASN.1| type + componentType = namedtype.NamedTypes() + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection( + constraint.ValueSizeConstraint(1, 1) + ) + + # Disambiguation ASN.1 types identification + typeId = Set.getTypeId() + + _currentIdx = None + + def __eq__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] == other + return NotImplemented + + def __ne__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] != other + return NotImplemented + + def __lt__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] < other + return NotImplemented + + def __le__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] <= other + return NotImplemented + + def __gt__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] > other + return NotImplemented + + def __ge__(self, other): + if self._componentValues: + return self._componentValues[self._currentIdx] >= other + return NotImplemented + + if sys.version_info[0] <= 2: + def __nonzero__(self): + return self._componentValues and True or False + else: + def __bool__(self): + return self._componentValues and True or False + + def __len__(self): + return self._currentIdx is not None and 1 or 0 + + def __contains__(self, key): + if self._currentIdx is None: + return False + return key == self.componentType[self._currentIdx].getName() + + def __iter__(self): + if self._currentIdx is None: + raise StopIteration + yield self.componentType[self._currentIdx].getName() + + # Python dict protocol + + def values(self): + if self._currentIdx is not None: + yield self._componentValues[self._currentIdx] + + def keys(self): + if self._currentIdx is not None: + yield self.componentType[self._currentIdx].getName() + + def items(self): + if self._currentIdx is not None: + yield self.componentType[self._currentIdx].getName(), self[self._currentIdx] + + def checkConsistency(self): + if self._currentIdx is None: + raise error.PyAsn1Error('Component not chosen') + + def _cloneComponentValues(self, myClone, cloneValueFlag): + try: + component = self.getComponent() + except error.PyAsn1Error: + pass + else: + if isinstance(component, Choice): + tagSet = component.effectiveTagSet + else: + tagSet = component.tagSet + if isinstance(component, base.ConstructedAsn1Type): + myClone.setComponentByType( + tagSet, component.clone(cloneValueFlag=cloneValueFlag) + ) + else: + myClone.setComponentByType(tagSet, component.clone()) + + def getComponentByPosition(self, idx, default=noValue, instantiate=True): + __doc__ = Set.__doc__ + + if self._currentIdx is None or self._currentIdx != idx: + return Set.getComponentByPosition(self, idx, default=default, + instantiate=instantiate) + + return self._componentValues[idx] + + def setComponentByPosition(self, idx, value=noValue, + verifyConstraints=True, + matchTags=True, + matchConstraints=True): + """Assign |ASN.1| type component by position. + + Equivalent to Python sequence item assignment operation (e.g. `[]`). + + Parameters + ---------- + idx: :class:`int` + Component index (zero-based). Must either refer to existing + component or to N+1 component. In the latter case a new component + type gets instantiated (if *componentType* is set, or given ASN.1 + object is taken otherwise) and appended to the |ASN.1| sequence. + + Keyword Args + ------------ + value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative + A Python value to initialize |ASN.1| component with (if *componentType* is set) + or ASN.1 value object to assign to |ASN.1| component. Once a new value is + set to *idx* component, previous value is dropped. + If `value` is not given, schema object will be set as a component. + + verifyConstraints : :class:`bool` + If :obj:`False`, skip constraints validation + + matchTags: :class:`bool` + If :obj:`False`, skip component tags matching + + matchConstraints: :class:`bool` + If :obj:`False`, skip component constraints matching + + Returns + ------- + self + """ + oldIdx = self._currentIdx + Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints) + self._currentIdx = idx + if oldIdx is not None and oldIdx != idx: + self._componentValues[oldIdx] = noValue + return self + + @property + def effectiveTagSet(self): + """Return a :class:`~pyasn1.type.tag.TagSet` object of the currently initialized component or self (if |ASN.1| is tagged).""" + if self.tagSet: + return self.tagSet + else: + component = self.getComponent() + return component.effectiveTagSet + + @property + def tagMap(self): + """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping + ASN.1 tags to ASN.1 objects contained within callee. + """ + if self.tagSet: + return Set.tagMap.fget(self) + else: + return self.componentType.tagMapUnique + + def getComponent(self, innerFlag=False): + """Return currently assigned component of the |ASN.1| object. + + Returns + ------- + : :py:class:`~pyasn1.type.base.PyAsn1Item` + a PyASN1 object + """ + if self._currentIdx is None: + raise error.PyAsn1Error('Component not chosen') + else: + c = self._componentValues[self._currentIdx] + if innerFlag and isinstance(c, Choice): + return c.getComponent(innerFlag) + else: + return c + + def getName(self, innerFlag=False): + """Return the name of currently assigned component of the |ASN.1| object. + + Returns + ------- + : :py:class:`str` + |ASN.1| component name + """ + if self._currentIdx is None: + raise error.PyAsn1Error('Component not chosen') + else: + if innerFlag: + c = self._componentValues[self._currentIdx] + if isinstance(c, Choice): + return c.getName(innerFlag) + return self.componentType.getNameByPosition(self._currentIdx) + + @property + def isValue(self): + """Indicate that |ASN.1| object represents ASN.1 value. + + If *isValue* is :obj:`False` then this object represents just ASN.1 schema. + + If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, + this object can also be used like a Python built-in object (e.g. + :class:`int`, :class:`str`, :class:`dict` etc.). + + Returns + ------- + : :class:`bool` + :obj:`False` if object represents just ASN.1 schema. + :obj:`True` if object represents ASN.1 schema and can be used as a normal + value. + + Note + ---- + There is an important distinction between PyASN1 schema and value objects. + The PyASN1 schema objects can only participate in ASN.1 schema-related + operations (e.g. defining or testing the structure of the data). Most + obvious uses of ASN.1 schema is to guide serialisation codecs whilst + encoding/decoding serialised ASN.1 contents. + + The PyASN1 value objects can **additionally** participate in many operations + involving regular Python objects (e.g. arithmetic, comprehension etc). + """ + if self._currentIdx is None: + return False + + componentValue = self._componentValues[self._currentIdx] + + return componentValue is not noValue and componentValue.isValue + + def clear(self): + self._currentIdx = None + return Set.clear(self) + + # compatibility stubs + + def getMinTagSet(self): + return self.minTagSet + + +class Any(OctetString): + """Create |ASN.1| schema or value object. + + |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, + its objects are immutable and duck-type Python 2 :class:`str` or Python 3 + :class:`bytes`. When used in Unicode context, |ASN.1| type assumes + "|encoding|" serialisation. + + Keyword Args + ------------ + value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object + :class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively + :class:`unicode` object (Python 2) or :class:`str` (Python 3) + representing character string to be serialised into octets (note + `encoding` parameter) or |ASN.1| object. + If `value` is not given, schema object will be created. + + tagSet: :py:class:`~pyasn1.type.tag.TagSet` + Object representing non-default ASN.1 tag(s) + + subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` + Object representing non-default ASN.1 subtype constraint(s). Constraints + verification for |ASN.1| type occurs automatically on object + instantiation. + + encoding: :py:class:`str` + Unicode codec ID to encode/decode :class:`unicode` (Python 2) or + :class:`str` (Python 3) the payload when |ASN.1| object is used + in text string context. + + binValue: :py:class:`str` + Binary string initializer to use instead of the *value*. + Example: '10110011'. + + hexValue: :py:class:`str` + Hexadecimal string initializer to use instead of the *value*. + Example: 'DEADBEEF'. + + Raises + ------ + ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error + On constraint violation or bad initializer. + + Examples + -------- + .. code-block:: python + + class Error(Sequence): + ''' + ASN.1 specification: + + Error ::= SEQUENCE { + code INTEGER, + parameter ANY DEFINED BY code -- Either INTEGER or REAL + } + ''' + componentType=NamedTypes( + NamedType('code', Integer()), + NamedType('parameter', Any(), + openType=OpenType('code', {1: Integer(), + 2: Real()})) + ) + + error = Error() + error['code'] = 1 + error['parameter'] = Integer(1234) + """ + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) + #: associated with |ASN.1| type. + tagSet = tag.TagSet() # untagged + + #: Set (on class, not on instance) or return a + #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object + #: imposing constraints on |ASN.1| type initialization values. + subtypeSpec = constraint.ConstraintsIntersection() + + # Disambiguation ASN.1 types identification + typeId = OctetString.getTypeId() + + @property + def tagMap(self): + """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping + ASN.1 tags to ASN.1 objects contained within callee. + """ + try: + return self._tagMap + + except AttributeError: + self._tagMap = tagmap.TagMap( + {self.tagSet: self}, + {eoo.endOfOctets.tagSet: eoo.endOfOctets}, + self + ) + + return self._tagMap + +# XXX +# coercion rules? diff --git a/Lambdas/Websocket Authorizer/pyasn1/type/useful.py b/Lambdas/Websocket Authorizer/pyasn1/type/useful.py new file mode 100644 index 0000000..7536b95 --- /dev/null +++ b/Lambdas/Websocket Authorizer/pyasn1/type/useful.py @@ -0,0 +1,191 @@ +# +# This file is part of pyasn1 software. +# +# Copyright (c) 2005-2019, Ilya Etingof +# License: http://snmplabs.com/pyasn1/license.html +# +import datetime + +from pyasn1 import error +from pyasn1.compat import dateandtime +from pyasn1.compat import string +from pyasn1.type import char +from pyasn1.type import tag +from pyasn1.type import univ + +__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime'] + +NoValue = univ.NoValue +noValue = univ.noValue + + +class ObjectDescriptor(char.GraphicString): + __doc__ = char.GraphicString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects + tagSet = char.GraphicString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7) + ) + + # Optimization for faster codec lookup + typeId = char.GraphicString.getTypeId() + + +class TimeMixIn(object): + + _yearsDigits = 4 + _hasSubsecond = False + _optionalMinutes = False + _shortTZ = False + + class FixedOffset(datetime.tzinfo): + """Fixed offset in minutes east from UTC.""" + + # defaulted arguments required + # https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html + def __init__(self, offset=0, name='UTC'): + self.__offset = datetime.timedelta(minutes=offset) + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return datetime.timedelta(0) + + UTC = FixedOffset() + + @property + def asDateTime(self): + """Create :py:class:`datetime.datetime` object from a |ASN.1| object. + + Returns + ------- + : + new instance of :py:class:`datetime.datetime` object + """ + text = str(self) + if text.endswith('Z'): + tzinfo = TimeMixIn.UTC + text = text[:-1] + + elif '-' in text or '+' in text: + if '+' in text: + text, plusminus, tz = string.partition(text, '+') + else: + text, plusminus, tz = string.partition(text, '-') + + if self._shortTZ and len(tz) == 2: + tz += '00' + + if len(tz) != 4: + raise error.PyAsn1Error('malformed time zone offset %s' % tz) + + try: + minutes = int(tz[:2]) * 60 + int(tz[2:]) + if plusminus == '-': + minutes *= -1 + + except ValueError: + raise error.PyAsn1Error('unknown time specification %s' % self) + + tzinfo = TimeMixIn.FixedOffset(minutes, '?') + + else: + tzinfo = None + + if '.' in text or ',' in text: + if '.' in text: + text, _, ms = string.partition(text, '.') + else: + text, _, ms = string.partition(text, ',') + + try: + ms = int(ms) * 1000 + + except ValueError: + raise error.PyAsn1Error('bad sub-second time specification %s' % self) + + else: + ms = 0 + + if self._optionalMinutes and len(text) - self._yearsDigits == 6: + text += '0000' + elif len(text) - self._yearsDigits == 8: + text += '00' + + try: + dt = dateandtime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') + + except ValueError: + raise error.PyAsn1Error('malformed datetime format %s' % self) + + return dt.replace(microsecond=ms, tzinfo=tzinfo) + + @classmethod + def fromDateTime(cls, dt): + """Create |ASN.1| object from a :py:class:`datetime.datetime` object. + + Parameters + ---------- + dt: :py:class:`datetime.datetime` object + The `datetime.datetime` object to initialize the |ASN.1| object + from + + Returns + ------- + : + new instance of |ASN.1| value + """ + text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') + if cls._hasSubsecond: + text += '.%d' % (dt.microsecond // 1000) + + if dt.utcoffset(): + seconds = dt.utcoffset().seconds + if seconds < 0: + text += '-' + else: + text += '+' + text += '%.2d%.2d' % (seconds // 3600, seconds % 3600) + else: + text += 'Z' + + return cls(text) + + +class GeneralizedTime(char.VisibleString, TimeMixIn): + __doc__ = char.VisibleString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects + tagSet = char.VisibleString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24) + ) + + # Optimization for faster codec lookup + typeId = char.VideotexString.getTypeId() + + _yearsDigits = 4 + _hasSubsecond = True + _optionalMinutes = True + _shortTZ = True + + +class UTCTime(char.VisibleString, TimeMixIn): + __doc__ = char.VisibleString.__doc__ + + #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects + tagSet = char.VisibleString.tagSet.tagImplicitly( + tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23) + ) + + # Optimization for faster codec lookup + typeId = char.VideotexString.getTypeId() + + _yearsDigits = 2 + _hasSubsecond = False + _optionalMinutes = False + _shortTZ = False diff --git a/Lambdas/Websocket Authorizer/rsa/__init__.py b/Lambdas/Websocket Authorizer/rsa/__init__.py new file mode 100644 index 0000000..9b05c6c --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/__init__.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""RSA module + +Module for calculating large primes, and RSA encryption, decryption, signing +and verification. Includes generating public and private keys. + +WARNING: this implementation does not use compression of the cleartext input to +prevent repetitions, or other common security improvements. Use with care. + +""" + +from rsa.key import newkeys, PrivateKey, PublicKey +from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ + VerificationError, find_signature_hash, sign_hash, compute_hash + +__author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" +__date__ = "2018-09-16" +__version__ = '4.0' + +# Do doctest if we're run directly +if __name__ == "__main__": + import doctest + + doctest.testmod() + +__all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify", 'PublicKey', + 'PrivateKey', 'DecryptionError', 'VerificationError', + 'compute_hash', 'sign_hash'] diff --git a/Lambdas/Websocket Authorizer/rsa/_compat.py b/Lambdas/Websocket Authorizer/rsa/_compat.py new file mode 100644 index 0000000..71197a5 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/_compat.py @@ -0,0 +1,162 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Python compatibility wrappers.""" + +from __future__ import absolute_import + +import itertools +import sys +from struct import pack + +MAX_INT = sys.maxsize +MAX_INT64 = (1 << 63) - 1 +MAX_INT32 = (1 << 31) - 1 +MAX_INT16 = (1 << 15) - 1 + +PY2 = sys.version_info[0] == 2 + +# Determine the word size of the processor. +if MAX_INT == MAX_INT64: + # 64-bit processor. + MACHINE_WORD_SIZE = 64 +elif MAX_INT == MAX_INT32: + # 32-bit processor. + MACHINE_WORD_SIZE = 32 +else: + # Else we just assume 64-bit processor keeping up with modern times. + MACHINE_WORD_SIZE = 64 + +if PY2: + integer_types = (int, long) + range = xrange + zip = itertools.izip +else: + integer_types = (int, ) + range = range + zip = zip + + +def write_to_stdout(data): + """Writes bytes to stdout + + :type data: bytes + """ + if PY2: + sys.stdout.write(data) + else: + # On Py3 we must use the buffer interface to write bytes. + sys.stdout.buffer.write(data) + + +def is_bytes(obj): + """ + Determines whether the given value is a byte string. + + :param obj: + The value to test. + :returns: + ``True`` if ``value`` is a byte string; ``False`` otherwise. + """ + return isinstance(obj, bytes) + + +def is_integer(obj): + """ + Determines whether the given value is an integer. + + :param obj: + The value to test. + :returns: + ``True`` if ``value`` is an integer; ``False`` otherwise. + """ + return isinstance(obj, integer_types) + + +def byte(num): + """ + Converts a number between 0 and 255 (both inclusive) to a base-256 (byte) + representation. + + Use it as a replacement for ``chr`` where you are expecting a byte + because this will work on all current versions of Python:: + + :param num: + An unsigned integer between 0 and 255 (both inclusive). + :returns: + A single byte. + """ + return pack("B", num) + + +def xor_bytes(b1, b2): + """ + Returns the bitwise XOR result between two bytes objects, b1 ^ b2. + + Bitwise XOR operation is commutative, so order of parameters doesn't + generate different results. If parameters have different length, extra + length of the largest one is ignored. + + :param b1: + First bytes object. + :param b2: + Second bytes object. + :returns: + Bytes object, result of XOR operation. + """ + if PY2: + return ''.join(byte(ord(x) ^ ord(y)) for x, y in zip(b1, b2)) + + return bytes(x ^ y for x, y in zip(b1, b2)) + + +def get_word_alignment(num, force_arch=64, + _machine_word_size=MACHINE_WORD_SIZE): + """ + Returns alignment details for the given number based on the platform + Python is running on. + + :param num: + Unsigned integral number. + :param force_arch: + If you don't want to use 64-bit unsigned chunks, set this to + anything other than 64. 32-bit chunks will be preferred then. + Default 64 will be used when on a 64-bit machine. + :param _machine_word_size: + (Internal) The machine word size used for alignment. + :returns: + 4-tuple:: + + (word_bits, word_bytes, + max_uint, packing_format_type) + """ + max_uint64 = 0xffffffffffffffff + max_uint32 = 0xffffffff + max_uint16 = 0xffff + max_uint8 = 0xff + + if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32: + # 64-bit unsigned integer. + return 64, 8, max_uint64, "Q" + elif num > max_uint16: + # 32-bit unsigned integer + return 32, 4, max_uint32, "L" + elif num > max_uint8: + # 16-bit unsigned integer. + return 16, 2, max_uint16, "H" + else: + # 8-bit unsigned integer. + return 8, 1, max_uint8, "B" diff --git a/Lambdas/Websocket Authorizer/rsa/asn1.py b/Lambdas/Websocket Authorizer/rsa/asn1.py new file mode 100644 index 0000000..b724b8f --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/asn1.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""ASN.1 definitions. + +Not all ASN.1-handling code use these definitions, but when it does, they should be here. +""" + +from pyasn1.type import univ, namedtype, tag + + +class PubKeyHeader(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('oid', univ.ObjectIdentifier()), + namedtype.NamedType('parameters', univ.Null()), + ) + + +class OpenSSLPubKey(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('header', PubKeyHeader()), + + # This little hack (the implicit tag) allows us to get a Bit String as Octet String + namedtype.NamedType('key', univ.OctetString().subtype( + implicitTag=tag.Tag(tagClass=0, tagFormat=0, tagId=3))), + ) + + +class AsnPubKey(univ.Sequence): + """ASN.1 contents of DER encoded public key: + + RSAPublicKey ::= SEQUENCE { + modulus INTEGER, -- n + publicExponent INTEGER, -- e + """ + + componentType = namedtype.NamedTypes( + namedtype.NamedType('modulus', univ.Integer()), + namedtype.NamedType('publicExponent', univ.Integer()), + ) diff --git a/Lambdas/Websocket Authorizer/rsa/cli.py b/Lambdas/Websocket Authorizer/rsa/cli.py new file mode 100644 index 0000000..6450af4 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/cli.py @@ -0,0 +1,288 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Commandline scripts. + +These scripts are called by the executables defined in setup.py. +""" + +from __future__ import with_statement, print_function + +import abc +import sys +from optparse import OptionParser + +import rsa +import rsa.pkcs1 + +HASH_METHODS = sorted(rsa.pkcs1.HASH_METHODS.keys()) + + +def keygen(): + """Key generator.""" + + # Parse the CLI options + parser = OptionParser(usage='usage: %prog [options] keysize', + description='Generates a new RSA keypair of "keysize" bits.') + + parser.add_option('--pubout', type='string', + help='Output filename for the public key. The public key is ' + 'not saved if this option is not present. You can use ' + 'pyrsa-priv2pub to create the public key file later.') + + parser.add_option('-o', '--out', type='string', + help='Output filename for the private key. The key is ' + 'written to stdout if this option is not present.') + + parser.add_option('--form', + help='key format of the private and public keys - default PEM', + choices=('PEM', 'DER'), default='PEM') + + (cli, cli_args) = parser.parse_args(sys.argv[1:]) + + if len(cli_args) != 1: + parser.print_help() + raise SystemExit(1) + + try: + keysize = int(cli_args[0]) + except ValueError: + parser.print_help() + print('Not a valid number: %s' % cli_args[0], file=sys.stderr) + raise SystemExit(1) + + print('Generating %i-bit key' % keysize, file=sys.stderr) + (pub_key, priv_key) = rsa.newkeys(keysize) + + # Save public key + if cli.pubout: + print('Writing public key to %s' % cli.pubout, file=sys.stderr) + data = pub_key.save_pkcs1(format=cli.form) + with open(cli.pubout, 'wb') as outfile: + outfile.write(data) + + # Save private key + data = priv_key.save_pkcs1(format=cli.form) + + if cli.out: + print('Writing private key to %s' % cli.out, file=sys.stderr) + with open(cli.out, 'wb') as outfile: + outfile.write(data) + else: + print('Writing private key to stdout', file=sys.stderr) + rsa._compat.write_to_stdout(data) + + +class CryptoOperation(object): + """CLI callable that operates with input, output, and a key.""" + + __metaclass__ = abc.ABCMeta + + keyname = 'public' # or 'private' + usage = 'usage: %%prog [options] %(keyname)s_key' + description = None + operation = 'decrypt' + operation_past = 'decrypted' + operation_progressive = 'decrypting' + input_help = 'Name of the file to %(operation)s. Reads from stdin if ' \ + 'not specified.' + output_help = 'Name of the file to write the %(operation_past)s file ' \ + 'to. Written to stdout if this option is not present.' + expected_cli_args = 1 + has_output = True + + key_class = rsa.PublicKey + + def __init__(self): + self.usage = self.usage % self.__class__.__dict__ + self.input_help = self.input_help % self.__class__.__dict__ + self.output_help = self.output_help % self.__class__.__dict__ + + @abc.abstractmethod + def perform_operation(self, indata, key, cli_args): + """Performs the program's operation. + + Implement in a subclass. + + :returns: the data to write to the output. + """ + + def __call__(self): + """Runs the program.""" + + (cli, cli_args) = self.parse_cli() + + key = self.read_key(cli_args[0], cli.keyform) + + indata = self.read_infile(cli.input) + + print(self.operation_progressive.title(), file=sys.stderr) + outdata = self.perform_operation(indata, key, cli_args) + + if self.has_output: + self.write_outfile(outdata, cli.output) + + def parse_cli(self): + """Parse the CLI options + + :returns: (cli_opts, cli_args) + """ + + parser = OptionParser(usage=self.usage, description=self.description) + + parser.add_option('-i', '--input', type='string', help=self.input_help) + + if self.has_output: + parser.add_option('-o', '--output', type='string', help=self.output_help) + + parser.add_option('--keyform', + help='Key format of the %s key - default PEM' % self.keyname, + choices=('PEM', 'DER'), default='PEM') + + (cli, cli_args) = parser.parse_args(sys.argv[1:]) + + if len(cli_args) != self.expected_cli_args: + parser.print_help() + raise SystemExit(1) + + return cli, cli_args + + def read_key(self, filename, keyform): + """Reads a public or private key.""" + + print('Reading %s key from %s' % (self.keyname, filename), file=sys.stderr) + with open(filename, 'rb') as keyfile: + keydata = keyfile.read() + + return self.key_class.load_pkcs1(keydata, keyform) + + def read_infile(self, inname): + """Read the input file""" + + if inname: + print('Reading input from %s' % inname, file=sys.stderr) + with open(inname, 'rb') as infile: + return infile.read() + + print('Reading input from stdin', file=sys.stderr) + return sys.stdin.read() + + def write_outfile(self, outdata, outname): + """Write the output file""" + + if outname: + print('Writing output to %s' % outname, file=sys.stderr) + with open(outname, 'wb') as outfile: + outfile.write(outdata) + else: + print('Writing output to stdout', file=sys.stderr) + rsa._compat.write_to_stdout(outdata) + + +class EncryptOperation(CryptoOperation): + """Encrypts a file.""" + + keyname = 'public' + description = ('Encrypts a file. The file must be shorter than the key ' + 'length in order to be encrypted.') + operation = 'encrypt' + operation_past = 'encrypted' + operation_progressive = 'encrypting' + + def perform_operation(self, indata, pub_key, cli_args=None): + """Encrypts files.""" + + return rsa.encrypt(indata, pub_key) + + +class DecryptOperation(CryptoOperation): + """Decrypts a file.""" + + keyname = 'private' + description = ('Decrypts a file. The original file must be shorter than ' + 'the key length in order to have been encrypted.') + operation = 'decrypt' + operation_past = 'decrypted' + operation_progressive = 'decrypting' + key_class = rsa.PrivateKey + + def perform_operation(self, indata, priv_key, cli_args=None): + """Decrypts files.""" + + return rsa.decrypt(indata, priv_key) + + +class SignOperation(CryptoOperation): + """Signs a file.""" + + keyname = 'private' + usage = 'usage: %%prog [options] private_key hash_method' + description = ('Signs a file, outputs the signature. Choose the hash ' + 'method from %s' % ', '.join(HASH_METHODS)) + operation = 'sign' + operation_past = 'signature' + operation_progressive = 'Signing' + key_class = rsa.PrivateKey + expected_cli_args = 2 + + output_help = ('Name of the file to write the signature to. Written ' + 'to stdout if this option is not present.') + + def perform_operation(self, indata, priv_key, cli_args): + """Signs files.""" + + hash_method = cli_args[1] + if hash_method not in HASH_METHODS: + raise SystemExit('Invalid hash method, choose one of %s' % + ', '.join(HASH_METHODS)) + + return rsa.sign(indata, priv_key, hash_method) + + +class VerifyOperation(CryptoOperation): + """Verify a signature.""" + + keyname = 'public' + usage = 'usage: %%prog [options] public_key signature_file' + description = ('Verifies a signature, exits with status 0 upon success, ' + 'prints an error message and exits with status 1 upon error.') + operation = 'verify' + operation_past = 'verified' + operation_progressive = 'Verifying' + key_class = rsa.PublicKey + expected_cli_args = 2 + has_output = False + + def perform_operation(self, indata, pub_key, cli_args): + """Verifies files.""" + + signature_file = cli_args[1] + + with open(signature_file, 'rb') as sigfile: + signature = sigfile.read() + + try: + rsa.verify(indata, signature, pub_key) + except rsa.VerificationError: + raise SystemExit('Verification failed.') + + print('Verification OK', file=sys.stderr) + + +encrypt = EncryptOperation() +decrypt = DecryptOperation() +sign = SignOperation() +verify = VerifyOperation() diff --git a/Lambdas/Websocket Authorizer/rsa/common.py b/Lambdas/Websocket Authorizer/rsa/common.py new file mode 100644 index 0000000..f7aa2d1 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/common.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from rsa._compat import zip + +"""Common functionality shared by several modules.""" + + +class NotRelativePrimeError(ValueError): + def __init__(self, a, b, d, msg=None): + super(NotRelativePrimeError, self).__init__( + msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d)) + self.a = a + self.b = b + self.d = d + + +def bit_size(num): + """ + Number of bits needed to represent a integer excluding any prefix + 0 bits. + + Usage:: + + >>> bit_size(1023) + 10 + >>> bit_size(1024) + 11 + >>> bit_size(1025) + 11 + + :param num: + Integer value. If num is 0, returns 0. Only the absolute value of the + number is considered. Therefore, signed integers will be abs(num) + before the number's bit length is determined. + :returns: + Returns the number of bits in the integer. + """ + + try: + return num.bit_length() + except AttributeError: + raise TypeError('bit_size(num) only supports integers, not %r' % type(num)) + + +def byte_size(number): + """ + Returns the number of bytes required to hold a specific long number. + + The number of bytes is rounded up. + + Usage:: + + >>> byte_size(1 << 1023) + 128 + >>> byte_size((1 << 1024) - 1) + 128 + >>> byte_size(1 << 1024) + 129 + + :param number: + An unsigned integer + :returns: + The number of bytes required to hold a specific long number. + """ + if number == 0: + return 1 + return ceil_div(bit_size(number), 8) + + +def ceil_div(num, div): + """ + Returns the ceiling function of a division between `num` and `div`. + + Usage:: + + >>> ceil_div(100, 7) + 15 + >>> ceil_div(100, 10) + 10 + >>> ceil_div(1, 4) + 1 + + :param num: Division's numerator, a number + :param div: Division's divisor, a number + + :return: Rounded up result of the division between the parameters. + """ + quanta, mod = divmod(num, div) + if mod: + quanta += 1 + return quanta + + +def extended_gcd(a, b): + """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb + """ + # r = gcd(a,b) i = multiplicitive inverse of a mod b + # or j = multiplicitive inverse of b mod a + # Neg return values for i or j are made positive mod b or a respectively + # Iterateive Version is faster and uses much less stack space + x = 0 + y = 1 + lx = 1 + ly = 0 + oa = a # Remember original a/b to remove + ob = b # negative values from return results + while b != 0: + q = a // b + (a, b) = (b, a % b) + (x, lx) = ((lx - (q * x)), x) + (y, ly) = ((ly - (q * y)), y) + if lx < 0: + lx += ob # If neg wrap modulo orignal b + if ly < 0: + ly += oa # If neg wrap modulo orignal a + return a, lx, ly # Return only positive values + + +def inverse(x, n): + """Returns the inverse of x % n under multiplication, a.k.a x^-1 (mod n) + + >>> inverse(7, 4) + 3 + >>> (inverse(143, 4) * 143) % 4 + 1 + """ + + (divider, inv, _) = extended_gcd(x, n) + + if divider != 1: + raise NotRelativePrimeError(x, n, divider) + + return inv + + +def crt(a_values, modulo_values): + """Chinese Remainder Theorem. + + Calculates x such that x = a[i] (mod m[i]) for each i. + + :param a_values: the a-values of the above equation + :param modulo_values: the m-values of the above equation + :returns: x such that x = a[i] (mod m[i]) for each i + + + >>> crt([2, 3], [3, 5]) + 8 + + >>> crt([2, 3, 2], [3, 5, 7]) + 23 + + >>> crt([2, 3, 0], [7, 11, 15]) + 135 + """ + + m = 1 + x = 0 + + for modulo in modulo_values: + m *= modulo + + for (m_i, a_i) in zip(modulo_values, a_values): + M_i = m // m_i + inv = inverse(M_i, m_i) + + x = (x + a_i * M_i * inv) % m + + return x + + +if __name__ == '__main__': + import doctest + + doctest.testmod() diff --git a/Lambdas/Websocket Authorizer/rsa/core.py b/Lambdas/Websocket Authorizer/rsa/core.py new file mode 100644 index 0000000..b3114d9 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/core.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Core mathematical operations. + +This is the actual core RSA implementation, which is only defined +mathematically on integers. +""" + +from rsa._compat import is_integer + + +def assert_int(var, name): + if is_integer(var): + return + + raise TypeError('%s should be an integer, not %s' % (name, var.__class__)) + + +def encrypt_int(message, ekey, n): + """Encrypts a message using encryption key 'ekey', working modulo n""" + + assert_int(message, 'message') + assert_int(ekey, 'ekey') + assert_int(n, 'n') + + if message < 0: + raise ValueError('Only non-negative numbers are supported') + + if message > n: + raise OverflowError("The message %i is too long for n=%i" % (message, n)) + + return pow(message, ekey, n) + + +def decrypt_int(cyphertext, dkey, n): + """Decrypts a cypher text using the decryption key 'dkey', working modulo n""" + + assert_int(cyphertext, 'cyphertext') + assert_int(dkey, 'dkey') + assert_int(n, 'n') + + message = pow(cyphertext, dkey, n) + return message diff --git a/Lambdas/Websocket Authorizer/rsa/key.py b/Lambdas/Websocket Authorizer/rsa/key.py new file mode 100644 index 0000000..1004412 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/key.py @@ -0,0 +1,791 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""RSA key generation code. + +Create new keys with the newkeys() function. It will give you a PublicKey and a +PrivateKey object. + +Loading and saving keys requires the pyasn1 module. This module is imported as +late as possible, such that other functionality will remain working in absence +of pyasn1. + +.. note:: + + Storing public and private keys via the `pickle` module is possible. + However, it is insecure to load a key from an untrusted source. + The pickle module is not secure against erroneous or maliciously + constructed data. Never unpickle data received from an untrusted + or unauthenticated source. + +""" + +import logging +import warnings + +from rsa._compat import range +import rsa.prime +import rsa.pem +import rsa.common +import rsa.randnum +import rsa.core + + +log = logging.getLogger(__name__) +DEFAULT_EXPONENT = 65537 + + +class AbstractKey(object): + """Abstract superclass for private and public keys.""" + + __slots__ = ('n', 'e') + + def __init__(self, n, e): + self.n = n + self.e = e + + @classmethod + def _load_pkcs1_pem(cls, keyfile): + """Loads a key in PKCS#1 PEM format, implement in a subclass. + + :param keyfile: contents of a PEM-encoded file that contains + the public key. + :type keyfile: bytes + + :return: the loaded key + :rtype: AbstractKey + """ + + @classmethod + def _load_pkcs1_der(cls, keyfile): + """Loads a key in PKCS#1 PEM format, implement in a subclass. + + :param keyfile: contents of a DER-encoded file that contains + the public key. + :type keyfile: bytes + + :return: the loaded key + :rtype: AbstractKey + """ + + def _save_pkcs1_pem(self): + """Saves the key in PKCS#1 PEM format, implement in a subclass. + + :returns: the PEM-encoded key. + :rtype: bytes + """ + + def _save_pkcs1_der(self): + """Saves the key in PKCS#1 DER format, implement in a subclass. + + :returns: the DER-encoded key. + :rtype: bytes + """ + + @classmethod + def load_pkcs1(cls, keyfile, format='PEM'): + """Loads a key in PKCS#1 DER or PEM format. + + :param keyfile: contents of a DER- or PEM-encoded file that contains + the key. + :type keyfile: bytes + :param format: the format of the file to load; 'PEM' or 'DER' + :type format: str + + :return: the loaded key + :rtype: AbstractKey + """ + + methods = { + 'PEM': cls._load_pkcs1_pem, + 'DER': cls._load_pkcs1_der, + } + + method = cls._assert_format_exists(format, methods) + return method(keyfile) + + @staticmethod + def _assert_format_exists(file_format, methods): + """Checks whether the given file format exists in 'methods'. + """ + + try: + return methods[file_format] + except KeyError: + formats = ', '.join(sorted(methods.keys())) + raise ValueError('Unsupported format: %r, try one of %s' % (file_format, + formats)) + + def save_pkcs1(self, format='PEM'): + """Saves the key in PKCS#1 DER or PEM format. + + :param format: the format to save; 'PEM' or 'DER' + :type format: str + :returns: the DER- or PEM-encoded key. + :rtype: bytes + """ + + methods = { + 'PEM': self._save_pkcs1_pem, + 'DER': self._save_pkcs1_der, + } + + method = self._assert_format_exists(format, methods) + return method() + + def blind(self, message, r): + """Performs blinding on the message using random number 'r'. + + :param message: the message, as integer, to blind. + :type message: int + :param r: the random number to blind with. + :type r: int + :return: the blinded message. + :rtype: int + + The blinding is such that message = unblind(decrypt(blind(encrypt(message))). + + See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 + """ + + return (message * pow(r, self.e, self.n)) % self.n + + def unblind(self, blinded, r): + """Performs blinding on the message using random number 'r'. + + :param blinded: the blinded message, as integer, to unblind. + :param r: the random number to unblind with. + :return: the original message. + + The blinding is such that message = unblind(decrypt(blind(encrypt(message))). + + See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 + """ + + return (rsa.common.inverse(r, self.n) * blinded) % self.n + + +class PublicKey(AbstractKey): + """Represents a public RSA key. + + This key is also known as the 'encryption key'. It contains the 'n' and 'e' + values. + + Supports attributes as well as dictionary-like access. Attribute access is + faster, though. + + >>> PublicKey(5, 3) + PublicKey(5, 3) + + >>> key = PublicKey(5, 3) + >>> key.n + 5 + >>> key['n'] + 5 + >>> key.e + 3 + >>> key['e'] + 3 + + """ + + __slots__ = ('n', 'e') + + def __getitem__(self, key): + return getattr(self, key) + + def __repr__(self): + return 'PublicKey(%i, %i)' % (self.n, self.e) + + def __getstate__(self): + """Returns the key as tuple for pickling.""" + return self.n, self.e + + def __setstate__(self, state): + """Sets the key from tuple.""" + self.n, self.e = state + + def __eq__(self, other): + if other is None: + return False + + if not isinstance(other, PublicKey): + return False + + return self.n == other.n and self.e == other.e + + def __ne__(self, other): + return not (self == other) + + def __hash__(self): + return hash((self.n, self.e)) + + @classmethod + def _load_pkcs1_der(cls, keyfile): + """Loads a key in PKCS#1 DER format. + + :param keyfile: contents of a DER-encoded file that contains the public + key. + :return: a PublicKey object + + First let's construct a DER encoded key: + + >>> import base64 + >>> b64der = 'MAwCBQCNGmYtAgMBAAE=' + >>> der = base64.standard_b64decode(b64der) + + This loads the file: + + >>> PublicKey._load_pkcs1_der(der) + PublicKey(2367317549, 65537) + + """ + + from pyasn1.codec.der import decoder + from rsa.asn1 import AsnPubKey + + (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey()) + return cls(n=int(priv['modulus']), e=int(priv['publicExponent'])) + + def _save_pkcs1_der(self): + """Saves the public key in PKCS#1 DER format. + + :returns: the DER-encoded public key. + :rtype: bytes + """ + + from pyasn1.codec.der import encoder + from rsa.asn1 import AsnPubKey + + # Create the ASN object + asn_key = AsnPubKey() + asn_key.setComponentByName('modulus', self.n) + asn_key.setComponentByName('publicExponent', self.e) + + return encoder.encode(asn_key) + + @classmethod + def _load_pkcs1_pem(cls, keyfile): + """Loads a PKCS#1 PEM-encoded public key file. + + The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and + after the "-----END RSA PUBLIC KEY-----" lines is ignored. + + :param keyfile: contents of a PEM-encoded file that contains the public + key. + :return: a PublicKey object + """ + + der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY') + return cls._load_pkcs1_der(der) + + def _save_pkcs1_pem(self): + """Saves a PKCS#1 PEM-encoded public key file. + + :return: contents of a PEM-encoded file that contains the public key. + :rtype: bytes + """ + + der = self._save_pkcs1_der() + return rsa.pem.save_pem(der, 'RSA PUBLIC KEY') + + @classmethod + def load_pkcs1_openssl_pem(cls, keyfile): + """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL. + + These files can be recognised in that they start with BEGIN PUBLIC KEY + rather than BEGIN RSA PUBLIC KEY. + + The contents of the file before the "-----BEGIN PUBLIC KEY-----" and + after the "-----END PUBLIC KEY-----" lines is ignored. + + :param keyfile: contents of a PEM-encoded file that contains the public + key, from OpenSSL. + :type keyfile: bytes + :return: a PublicKey object + """ + + der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY') + return cls.load_pkcs1_openssl_der(der) + + @classmethod + def load_pkcs1_openssl_der(cls, keyfile): + """Loads a PKCS#1 DER-encoded public key file from OpenSSL. + + :param keyfile: contents of a DER-encoded file that contains the public + key, from OpenSSL. + :return: a PublicKey object + :rtype: bytes + + """ + + from rsa.asn1 import OpenSSLPubKey + from pyasn1.codec.der import decoder + from pyasn1.type import univ + + (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey()) + + if keyinfo['header']['oid'] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'): + raise TypeError("This is not a DER-encoded OpenSSL-compatible public key") + + return cls._load_pkcs1_der(keyinfo['key'][1:]) + + +class PrivateKey(AbstractKey): + """Represents a private RSA key. + + This key is also known as the 'decryption key'. It contains the 'n', 'e', + 'd', 'p', 'q' and other values. + + Supports attributes as well as dictionary-like access. Attribute access is + faster, though. + + >>> PrivateKey(3247, 65537, 833, 191, 17) + PrivateKey(3247, 65537, 833, 191, 17) + + exp1, exp2 and coef will be calculated: + + >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) + >>> pk.exp1 + 55063 + >>> pk.exp2 + 10095 + >>> pk.coef + 50797 + + """ + + __slots__ = ('n', 'e', 'd', 'p', 'q', 'exp1', 'exp2', 'coef') + + def __init__(self, n, e, d, p, q): + AbstractKey.__init__(self, n, e) + self.d = d + self.p = p + self.q = q + + # Calculate exponents and coefficient. + self.exp1 = int(d % (p - 1)) + self.exp2 = int(d % (q - 1)) + self.coef = rsa.common.inverse(q, p) + + def __getitem__(self, key): + return getattr(self, key) + + def __repr__(self): + return 'PrivateKey(%(n)i, %(e)i, %(d)i, %(p)i, %(q)i)' % self + + def __getstate__(self): + """Returns the key as tuple for pickling.""" + return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef + + def __setstate__(self, state): + """Sets the key from tuple.""" + self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state + + def __eq__(self, other): + if other is None: + return False + + if not isinstance(other, PrivateKey): + return False + + return (self.n == other.n and + self.e == other.e and + self.d == other.d and + self.p == other.p and + self.q == other.q and + self.exp1 == other.exp1 and + self.exp2 == other.exp2 and + self.coef == other.coef) + + def __ne__(self, other): + return not (self == other) + + def __hash__(self): + return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef)) + + def blinded_decrypt(self, encrypted): + """Decrypts the message using blinding to prevent side-channel attacks. + + :param encrypted: the encrypted message + :type encrypted: int + + :returns: the decrypted message + :rtype: int + """ + + blind_r = rsa.randnum.randint(self.n - 1) + blinded = self.blind(encrypted, blind_r) # blind before decrypting + decrypted = rsa.core.decrypt_int(blinded, self.d, self.n) + + return self.unblind(decrypted, blind_r) + + def blinded_encrypt(self, message): + """Encrypts the message using blinding to prevent side-channel attacks. + + :param message: the message to encrypt + :type message: int + + :returns: the encrypted message + :rtype: int + """ + + blind_r = rsa.randnum.randint(self.n - 1) + blinded = self.blind(message, blind_r) # blind before encrypting + encrypted = rsa.core.encrypt_int(blinded, self.d, self.n) + return self.unblind(encrypted, blind_r) + + @classmethod + def _load_pkcs1_der(cls, keyfile): + """Loads a key in PKCS#1 DER format. + + :param keyfile: contents of a DER-encoded file that contains the private + key. + :type keyfile: bytes + :return: a PrivateKey object + + First let's construct a DER encoded key: + + >>> import base64 + >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt' + >>> der = base64.standard_b64decode(b64der) + + This loads the file: + + >>> PrivateKey._load_pkcs1_der(der) + PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) + + """ + + from pyasn1.codec.der import decoder + (priv, _) = decoder.decode(keyfile) + + # ASN.1 contents of DER encoded private key: + # + # RSAPrivateKey ::= SEQUENCE { + # version Version, + # modulus INTEGER, -- n + # publicExponent INTEGER, -- e + # privateExponent INTEGER, -- d + # prime1 INTEGER, -- p + # prime2 INTEGER, -- q + # exponent1 INTEGER, -- d mod (p-1) + # exponent2 INTEGER, -- d mod (q-1) + # coefficient INTEGER, -- (inverse of q) mod p + # otherPrimeInfos OtherPrimeInfos OPTIONAL + # } + + if priv[0] != 0: + raise ValueError('Unable to read this file, version %s != 0' % priv[0]) + + as_ints = map(int, priv[1:6]) + key = cls(*as_ints) + + exp1, exp2, coef = map(int, priv[6:9]) + + if (key.exp1, key.exp2, key.coef) != (exp1, exp2, coef): + warnings.warn( + 'You have provided a malformed keyfile. Either the exponents ' + 'or the coefficient are incorrect. Using the correct values ' + 'instead.', + UserWarning, + ) + + return key + + def _save_pkcs1_der(self): + """Saves the private key in PKCS#1 DER format. + + :returns: the DER-encoded private key. + :rtype: bytes + """ + + from pyasn1.type import univ, namedtype + from pyasn1.codec.der import encoder + + class AsnPrivKey(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('version', univ.Integer()), + namedtype.NamedType('modulus', univ.Integer()), + namedtype.NamedType('publicExponent', univ.Integer()), + namedtype.NamedType('privateExponent', univ.Integer()), + namedtype.NamedType('prime1', univ.Integer()), + namedtype.NamedType('prime2', univ.Integer()), + namedtype.NamedType('exponent1', univ.Integer()), + namedtype.NamedType('exponent2', univ.Integer()), + namedtype.NamedType('coefficient', univ.Integer()), + ) + + # Create the ASN object + asn_key = AsnPrivKey() + asn_key.setComponentByName('version', 0) + asn_key.setComponentByName('modulus', self.n) + asn_key.setComponentByName('publicExponent', self.e) + asn_key.setComponentByName('privateExponent', self.d) + asn_key.setComponentByName('prime1', self.p) + asn_key.setComponentByName('prime2', self.q) + asn_key.setComponentByName('exponent1', self.exp1) + asn_key.setComponentByName('exponent2', self.exp2) + asn_key.setComponentByName('coefficient', self.coef) + + return encoder.encode(asn_key) + + @classmethod + def _load_pkcs1_pem(cls, keyfile): + """Loads a PKCS#1 PEM-encoded private key file. + + The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and + after the "-----END RSA PRIVATE KEY-----" lines is ignored. + + :param keyfile: contents of a PEM-encoded file that contains the private + key. + :type keyfile: bytes + :return: a PrivateKey object + """ + + der = rsa.pem.load_pem(keyfile, b'RSA PRIVATE KEY') + return cls._load_pkcs1_der(der) + + def _save_pkcs1_pem(self): + """Saves a PKCS#1 PEM-encoded private key file. + + :return: contents of a PEM-encoded file that contains the private key. + :rtype: bytes + """ + + der = self._save_pkcs1_der() + return rsa.pem.save_pem(der, b'RSA PRIVATE KEY') + + +def find_p_q(nbits, getprime_func=rsa.prime.getprime, accurate=True): + """Returns a tuple of two different primes of nbits bits each. + + The resulting p * q has exacty 2 * nbits bits, and the returned p and q + will not be equal. + + :param nbits: the number of bits in each of p and q. + :param getprime_func: the getprime function, defaults to + :py:func:`rsa.prime.getprime`. + + *Introduced in Python-RSA 3.1* + + :param accurate: whether to enable accurate mode or not. + :returns: (p, q), where p > q + + >>> (p, q) = find_p_q(128) + >>> from rsa import common + >>> common.bit_size(p * q) + 256 + + When not in accurate mode, the number of bits can be slightly less + + >>> (p, q) = find_p_q(128, accurate=False) + >>> from rsa import common + >>> common.bit_size(p * q) <= 256 + True + >>> common.bit_size(p * q) > 240 + True + + """ + + total_bits = nbits * 2 + + # Make sure that p and q aren't too close or the factoring programs can + # factor n. + shift = nbits // 16 + pbits = nbits + shift + qbits = nbits - shift + + # Choose the two initial primes + log.debug('find_p_q(%i): Finding p', nbits) + p = getprime_func(pbits) + log.debug('find_p_q(%i): Finding q', nbits) + q = getprime_func(qbits) + + def is_acceptable(p, q): + """Returns True iff p and q are acceptable: + + - p and q differ + - (p * q) has the right nr of bits (when accurate=True) + """ + + if p == q: + return False + + if not accurate: + return True + + # Make sure we have just the right amount of bits + found_size = rsa.common.bit_size(p * q) + return total_bits == found_size + + # Keep choosing other primes until they match our requirements. + change_p = False + while not is_acceptable(p, q): + # Change p on one iteration and q on the other + if change_p: + p = getprime_func(pbits) + else: + q = getprime_func(qbits) + + change_p = not change_p + + # We want p > q as described on + # http://www.di-mgt.com.au/rsa_alg.html#crt + return max(p, q), min(p, q) + + +def calculate_keys_custom_exponent(p, q, exponent): + """Calculates an encryption and a decryption key given p, q and an exponent, + and returns them as a tuple (e, d) + + :param p: the first large prime + :param q: the second large prime + :param exponent: the exponent for the key; only change this if you know + what you're doing, as the exponent influences how difficult your + private key can be cracked. A very common choice for e is 65537. + :type exponent: int + + """ + + phi_n = (p - 1) * (q - 1) + + try: + d = rsa.common.inverse(exponent, phi_n) + except rsa.common.NotRelativePrimeError as ex: + raise rsa.common.NotRelativePrimeError( + exponent, phi_n, ex.d, + msg="e (%d) and phi_n (%d) are not relatively prime (divider=%i)" % + (exponent, phi_n, ex.d)) + + if (exponent * d) % phi_n != 1: + raise ValueError("e (%d) and d (%d) are not mult. inv. modulo " + "phi_n (%d)" % (exponent, d, phi_n)) + + return exponent, d + + +def calculate_keys(p, q): + """Calculates an encryption and a decryption key given p and q, and + returns them as a tuple (e, d) + + :param p: the first large prime + :param q: the second large prime + + :return: tuple (e, d) with the encryption and decryption exponents. + """ + + return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT) + + +def gen_keys(nbits, getprime_func, accurate=True, exponent=DEFAULT_EXPONENT): + """Generate RSA keys of nbits bits. Returns (p, q, e, d). + + Note: this can take a long time, depending on the key size. + + :param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and + ``q`` will use ``nbits/2`` bits. + :param getprime_func: either :py:func:`rsa.prime.getprime` or a function + with similar signature. + :param exponent: the exponent for the key; only change this if you know + what you're doing, as the exponent influences how difficult your + private key can be cracked. A very common choice for e is 65537. + :type exponent: int + """ + + # Regenerate p and q values, until calculate_keys doesn't raise a + # ValueError. + while True: + (p, q) = find_p_q(nbits // 2, getprime_func, accurate) + try: + (e, d) = calculate_keys_custom_exponent(p, q, exponent=exponent) + break + except ValueError: + pass + + return p, q, e, d + + +def newkeys(nbits, accurate=True, poolsize=1, exponent=DEFAULT_EXPONENT): + """Generates public and private keys, and returns them as (pub, priv). + + The public key is also known as the 'encryption key', and is a + :py:class:`rsa.PublicKey` object. The private key is also known as the + 'decryption key' and is a :py:class:`rsa.PrivateKey` object. + + :param nbits: the number of bits required to store ``n = p*q``. + :param accurate: when True, ``n`` will have exactly the number of bits you + asked for. However, this makes key generation much slower. When False, + `n`` may have slightly less bits. + :param poolsize: the number of processes to use to generate the prime + numbers. If set to a number > 1, a parallel algorithm will be used. + This requires Python 2.6 or newer. + :param exponent: the exponent for the key; only change this if you know + what you're doing, as the exponent influences how difficult your + private key can be cracked. A very common choice for e is 65537. + :type exponent: int + + :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`) + + The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires + Python 2.6 or newer. + + """ + + if nbits < 16: + raise ValueError('Key too small') + + if poolsize < 1: + raise ValueError('Pool size (%i) should be >= 1' % poolsize) + + # Determine which getprime function to use + if poolsize > 1: + from rsa import parallel + import functools + + getprime_func = functools.partial(parallel.getprime, poolsize=poolsize) + else: + getprime_func = rsa.prime.getprime + + # Generate the key components + (p, q, e, d) = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent) + + # Create the key objects + n = p * q + + return ( + PublicKey(n, e), + PrivateKey(n, e, d, p, q) + ) + + +__all__ = ['PublicKey', 'PrivateKey', 'newkeys'] + +if __name__ == '__main__': + import doctest + + try: + for count in range(100): + (failures, tests) = doctest.testmod() + if failures: + break + + if (count % 10 == 0 and count) or count == 1: + print('%i times' % count) + except KeyboardInterrupt: + print('Aborted') + else: + print('Doctests done') diff --git a/Lambdas/Websocket Authorizer/rsa/machine_size.py b/Lambdas/Websocket Authorizer/rsa/machine_size.py new file mode 100644 index 0000000..2a871b8 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/machine_size.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Detection of 32-bit and 64-bit machines and byte alignment.""" + +import sys + +MAX_INT = sys.maxsize +MAX_INT64 = (1 << 63) - 1 +MAX_INT32 = (1 << 31) - 1 +MAX_INT16 = (1 << 15) - 1 + +# Determine the word size of the processor. +if MAX_INT == MAX_INT64: + # 64-bit processor. + MACHINE_WORD_SIZE = 64 +elif MAX_INT == MAX_INT32: + # 32-bit processor. + MACHINE_WORD_SIZE = 32 +else: + # Else we just assume 64-bit processor keeping up with modern times. + MACHINE_WORD_SIZE = 64 + + +def get_word_alignment(num, force_arch=64, + _machine_word_size=MACHINE_WORD_SIZE): + """ + Returns alignment details for the given number based on the platform + Python is running on. + + :param num: + Unsigned integral number. + :param force_arch: + If you don't want to use 64-bit unsigned chunks, set this to + anything other than 64. 32-bit chunks will be preferred then. + Default 64 will be used when on a 64-bit machine. + :param _machine_word_size: + (Internal) The machine word size used for alignment. + :returns: + 4-tuple:: + + (word_bits, word_bytes, + max_uint, packing_format_type) + """ + max_uint64 = 0xffffffffffffffff + max_uint32 = 0xffffffff + max_uint16 = 0xffff + max_uint8 = 0xff + + if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32: + # 64-bit unsigned integer. + return 64, 8, max_uint64, "Q" + elif num > max_uint16: + # 32-bit unsigned integer + return 32, 4, max_uint32, "L" + elif num > max_uint8: + # 16-bit unsigned integer. + return 16, 2, max_uint16, "H" + else: + # 8-bit unsigned integer. + return 8, 1, max_uint8, "B" diff --git a/Lambdas/Websocket Authorizer/rsa/parallel.py b/Lambdas/Websocket Authorizer/rsa/parallel.py new file mode 100644 index 0000000..a3fe312 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/parallel.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Functions for parallel computation on multiple cores. + +Introduced in Python-RSA 3.1. + +.. note:: + + Requires Python 2.6 or newer. + +""" + +from __future__ import print_function + +import multiprocessing as mp + +from rsa._compat import range +import rsa.prime +import rsa.randnum + + +def _find_prime(nbits, pipe): + while True: + integer = rsa.randnum.read_random_odd_int(nbits) + + # Test for primeness + if rsa.prime.is_prime(integer): + pipe.send(integer) + return + + +def getprime(nbits, poolsize): + """Returns a prime number that can be stored in 'nbits' bits. + + Works in multiple threads at the same time. + + >>> p = getprime(128, 3) + >>> rsa.prime.is_prime(p-1) + False + >>> rsa.prime.is_prime(p) + True + >>> rsa.prime.is_prime(p+1) + False + + >>> from rsa import common + >>> common.bit_size(p) == 128 + True + + """ + + (pipe_recv, pipe_send) = mp.Pipe(duplex=False) + + # Create processes + try: + procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send)) + for _ in range(poolsize)] + # Start processes + for p in procs: + p.start() + + result = pipe_recv.recv() + finally: + pipe_recv.close() + pipe_send.close() + + # Terminate processes + for p in procs: + p.terminate() + + return result + + +__all__ = ['getprime'] + +if __name__ == '__main__': + print('Running doctests 1000x or until failure') + import doctest + + for count in range(100): + (failures, tests) = doctest.testmod() + if failures: + break + + if count % 10 == 0 and count: + print('%i times' % count) + + print('Doctests done') diff --git a/Lambdas/Websocket Authorizer/rsa/pem.py b/Lambdas/Websocket Authorizer/rsa/pem.py new file mode 100644 index 0000000..2ddfae8 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/pem.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Functions that load and write PEM-encoded files.""" + +import base64 + +from rsa._compat import is_bytes, range + + +def _markers(pem_marker): + """ + Returns the start and end PEM markers, as bytes. + """ + + if not is_bytes(pem_marker): + pem_marker = pem_marker.encode('ascii') + + return (b'-----BEGIN ' + pem_marker + b'-----', + b'-----END ' + pem_marker + b'-----') + + +def load_pem(contents, pem_marker): + """Loads a PEM file. + + :param contents: the contents of the file to interpret + :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' + when your file has '-----BEGIN RSA PRIVATE KEY-----' and + '-----END RSA PRIVATE KEY-----' markers. + + :return: the base64-decoded content between the start and end markers. + + @raise ValueError: when the content is invalid, for example when the start + marker cannot be found. + + """ + + # We want bytes, not text. If it's text, it can be converted to ASCII bytes. + if not is_bytes(contents): + contents = contents.encode('ascii') + + (pem_start, pem_end) = _markers(pem_marker) + + pem_lines = [] + in_pem_part = False + + for line in contents.splitlines(): + line = line.strip() + + # Skip empty lines + if not line: + continue + + # Handle start marker + if line == pem_start: + if in_pem_part: + raise ValueError('Seen start marker "%s" twice' % pem_start) + + in_pem_part = True + continue + + # Skip stuff before first marker + if not in_pem_part: + continue + + # Handle end marker + if in_pem_part and line == pem_end: + in_pem_part = False + break + + # Load fields + if b':' in line: + continue + + pem_lines.append(line) + + # Do some sanity checks + if not pem_lines: + raise ValueError('No PEM start marker "%s" found' % pem_start) + + if in_pem_part: + raise ValueError('No PEM end marker "%s" found' % pem_end) + + # Base64-decode the contents + pem = b''.join(pem_lines) + return base64.standard_b64decode(pem) + + +def save_pem(contents, pem_marker): + """Saves a PEM file. + + :param contents: the contents to encode in PEM format + :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' + when your file has '-----BEGIN RSA PRIVATE KEY-----' and + '-----END RSA PRIVATE KEY-----' markers. + + :return: the base64-encoded content between the start and end markers, as bytes. + + """ + + (pem_start, pem_end) = _markers(pem_marker) + + b64 = base64.standard_b64encode(contents).replace(b'\n', b'') + pem_lines = [pem_start] + + for block_start in range(0, len(b64), 64): + block = b64[block_start:block_start + 64] + pem_lines.append(block) + + pem_lines.append(pem_end) + pem_lines.append(b'') + + return b'\n'.join(pem_lines) diff --git a/Lambdas/Websocket Authorizer/rsa/pkcs1.py b/Lambdas/Websocket Authorizer/rsa/pkcs1.py new file mode 100644 index 0000000..84f0e3b --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/pkcs1.py @@ -0,0 +1,439 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Functions for PKCS#1 version 1.5 encryption and signing + +This module implements certain functionality from PKCS#1 version 1.5. For a +very clear example, read http://www.di-mgt.com.au/rsa_alg.html#pkcs1schemes + +At least 8 bytes of random padding is used when encrypting a message. This makes +these methods much more secure than the ones in the ``rsa`` module. + +WARNING: this module leaks information when decryption fails. The exceptions +that are raised contain the Python traceback information, which can be used to +deduce where in the process the failure occurred. DO NOT PASS SUCH INFORMATION +to your users. +""" + +import hashlib +import os + +from rsa._compat import range +from rsa import common, transform, core + +# ASN.1 codes that describe the hash algorithm used. +HASH_ASN1 = { + 'MD5': b'\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10', + 'SHA-1': b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14', + 'SHA-224': b'\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c', + 'SHA-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20', + 'SHA-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30', + 'SHA-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40', +} + +HASH_METHODS = { + 'MD5': hashlib.md5, + 'SHA-1': hashlib.sha1, + 'SHA-224': hashlib.sha224, + 'SHA-256': hashlib.sha256, + 'SHA-384': hashlib.sha384, + 'SHA-512': hashlib.sha512, +} + + +class CryptoError(Exception): + """Base class for all exceptions in this module.""" + + +class DecryptionError(CryptoError): + """Raised when decryption fails.""" + + +class VerificationError(CryptoError): + """Raised when verification fails.""" + + +def _pad_for_encryption(message, target_length): + r"""Pads the message for encryption, returning the padded message. + + :return: 00 02 RANDOM_DATA 00 MESSAGE + + >>> block = _pad_for_encryption(b'hello', 16) + >>> len(block) + 16 + >>> block[0:2] + b'\x00\x02' + >>> block[-6:] + b'\x00hello' + + """ + + max_msglength = target_length - 11 + msglength = len(message) + + if msglength > max_msglength: + raise OverflowError('%i bytes needed for message, but there is only' + ' space for %i' % (msglength, max_msglength)) + + # Get random padding + padding = b'' + padding_length = target_length - msglength - 3 + + # We remove 0-bytes, so we'll end up with less padding than we've asked for, + # so keep adding data until we're at the correct length. + while len(padding) < padding_length: + needed_bytes = padding_length - len(padding) + + # Always read at least 8 bytes more than we need, and trim off the rest + # after removing the 0-bytes. This increases the chance of getting + # enough bytes, especially when needed_bytes is small + new_padding = os.urandom(needed_bytes + 5) + new_padding = new_padding.replace(b'\x00', b'') + padding = padding + new_padding[:needed_bytes] + + assert len(padding) == padding_length + + return b''.join([b'\x00\x02', + padding, + b'\x00', + message]) + + +def _pad_for_signing(message, target_length): + r"""Pads the message for signing, returning the padded message. + + The padding is always a repetition of FF bytes. + + :return: 00 01 PADDING 00 MESSAGE + + >>> block = _pad_for_signing(b'hello', 16) + >>> len(block) + 16 + >>> block[0:2] + b'\x00\x01' + >>> block[-6:] + b'\x00hello' + >>> block[2:-6] + b'\xff\xff\xff\xff\xff\xff\xff\xff' + + """ + + max_msglength = target_length - 11 + msglength = len(message) + + if msglength > max_msglength: + raise OverflowError('%i bytes needed for message, but there is only' + ' space for %i' % (msglength, max_msglength)) + + padding_length = target_length - msglength - 3 + + return b''.join([b'\x00\x01', + padding_length * b'\xff', + b'\x00', + message]) + + +def encrypt(message, pub_key): + """Encrypts the given message using PKCS#1 v1.5 + + :param message: the message to encrypt. Must be a byte string no longer than + ``k-11`` bytes, where ``k`` is the number of bytes needed to encode + the ``n`` component of the public key. + :param pub_key: the :py:class:`rsa.PublicKey` to encrypt with. + :raise OverflowError: when the message is too large to fit in the padded + block. + + >>> from rsa import key, common + >>> (pub_key, priv_key) = key.newkeys(256) + >>> message = b'hello' + >>> crypto = encrypt(message, pub_key) + + The crypto text should be just as long as the public key 'n' component: + + >>> len(crypto) == common.byte_size(pub_key.n) + True + + """ + + keylength = common.byte_size(pub_key.n) + padded = _pad_for_encryption(message, keylength) + + payload = transform.bytes2int(padded) + encrypted = core.encrypt_int(payload, pub_key.e, pub_key.n) + block = transform.int2bytes(encrypted, keylength) + + return block + + +def decrypt(crypto, priv_key): + r"""Decrypts the given message using PKCS#1 v1.5 + + The decryption is considered 'failed' when the resulting cleartext doesn't + start with the bytes 00 02, or when the 00 byte between the padding and + the message cannot be found. + + :param crypto: the crypto text as returned by :py:func:`rsa.encrypt` + :param priv_key: the :py:class:`rsa.PrivateKey` to decrypt with. + :raise DecryptionError: when the decryption fails. No details are given as + to why the code thinks the decryption fails, as this would leak + information about the private key. + + + >>> import rsa + >>> (pub_key, priv_key) = rsa.newkeys(256) + + It works with strings: + + >>> crypto = encrypt(b'hello', pub_key) + >>> decrypt(crypto, priv_key) + b'hello' + + And with binary data: + + >>> crypto = encrypt(b'\x00\x00\x00\x00\x01', pub_key) + >>> decrypt(crypto, priv_key) + b'\x00\x00\x00\x00\x01' + + Altering the encrypted information will *likely* cause a + :py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use + :py:func:`rsa.sign`. + + + .. warning:: + + Never display the stack trace of a + :py:class:`rsa.pkcs1.DecryptionError` exception. It shows where in the + code the exception occurred, and thus leaks information about the key. + It's only a tiny bit of information, but every bit makes cracking the + keys easier. + + >>> crypto = encrypt(b'hello', pub_key) + >>> crypto = crypto[0:5] + b'X' + crypto[6:] # change a byte + >>> decrypt(crypto, priv_key) + Traceback (most recent call last): + ... + rsa.pkcs1.DecryptionError: Decryption failed + + """ + + blocksize = common.byte_size(priv_key.n) + encrypted = transform.bytes2int(crypto) + decrypted = priv_key.blinded_decrypt(encrypted) + cleartext = transform.int2bytes(decrypted, blocksize) + + # If we can't find the cleartext marker, decryption failed. + if cleartext[0:2] != b'\x00\x02': + raise DecryptionError('Decryption failed') + + # Find the 00 separator between the padding and the message + try: + sep_idx = cleartext.index(b'\x00', 2) + except ValueError: + raise DecryptionError('Decryption failed') + + return cleartext[sep_idx + 1:] + + +def sign_hash(hash_value, priv_key, hash_method): + """Signs a precomputed hash with the private key. + + Hashes the message, then signs the hash with the given key. This is known + as a "detached signature", because the message itself isn't altered. + + :param hash_value: A precomputed hash to sign (ignores message). Should be set to + None if needing to hash and sign message. + :param priv_key: the :py:class:`rsa.PrivateKey` to sign with + :param hash_method: the hash method used on the message. Use 'MD5', 'SHA-1', + 'SHA-224', SHA-256', 'SHA-384' or 'SHA-512'. + :return: a message signature block. + :raise OverflowError: if the private key is too small to contain the + requested hash. + + """ + + # Get the ASN1 code for this hash method + if hash_method not in HASH_ASN1: + raise ValueError('Invalid hash method: %s' % hash_method) + asn1code = HASH_ASN1[hash_method] + + # Encrypt the hash with the private key + cleartext = asn1code + hash_value + keylength = common.byte_size(priv_key.n) + padded = _pad_for_signing(cleartext, keylength) + + payload = transform.bytes2int(padded) + encrypted = priv_key.blinded_encrypt(payload) + block = transform.int2bytes(encrypted, keylength) + + return block + + +def sign(message, priv_key, hash_method): + """Signs the message with the private key. + + Hashes the message, then signs the hash with the given key. This is known + as a "detached signature", because the message itself isn't altered. + + :param message: the message to sign. Can be an 8-bit string or a file-like + object. If ``message`` has a ``read()`` method, it is assumed to be a + file-like object. + :param priv_key: the :py:class:`rsa.PrivateKey` to sign with + :param hash_method: the hash method used on the message. Use 'MD5', 'SHA-1', + 'SHA-224', SHA-256', 'SHA-384' or 'SHA-512'. + :return: a message signature block. + :raise OverflowError: if the private key is too small to contain the + requested hash. + + """ + + msg_hash = compute_hash(message, hash_method) + return sign_hash(msg_hash, priv_key, hash_method) + + +def verify(message, signature, pub_key): + """Verifies that the signature matches the message. + + The hash method is detected automatically from the signature. + + :param message: the signed message. Can be an 8-bit string or a file-like + object. If ``message`` has a ``read()`` method, it is assumed to be a + file-like object. + :param signature: the signature block, as created with :py:func:`rsa.sign`. + :param pub_key: the :py:class:`rsa.PublicKey` of the person signing the message. + :raise VerificationError: when the signature doesn't match the message. + :returns: the name of the used hash. + + """ + + keylength = common.byte_size(pub_key.n) + encrypted = transform.bytes2int(signature) + decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n) + clearsig = transform.int2bytes(decrypted, keylength) + + # Get the hash method + method_name = _find_method_hash(clearsig) + message_hash = compute_hash(message, method_name) + + # Reconstruct the expected padded hash + cleartext = HASH_ASN1[method_name] + message_hash + expected = _pad_for_signing(cleartext, keylength) + + # Compare with the signed one + if expected != clearsig: + raise VerificationError('Verification failed') + + return method_name + + +def find_signature_hash(signature, pub_key): + """Returns the hash name detected from the signature. + + If you also want to verify the message, use :py:func:`rsa.verify()` instead. + It also returns the name of the used hash. + + :param signature: the signature block, as created with :py:func:`rsa.sign`. + :param pub_key: the :py:class:`rsa.PublicKey` of the person signing the message. + :returns: the name of the used hash. + """ + + keylength = common.byte_size(pub_key.n) + encrypted = transform.bytes2int(signature) + decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n) + clearsig = transform.int2bytes(decrypted, keylength) + + return _find_method_hash(clearsig) + + +def yield_fixedblocks(infile, blocksize): + """Generator, yields each block of ``blocksize`` bytes in the input file. + + :param infile: file to read and separate in blocks. + :param blocksize: block size in bytes. + :returns: a generator that yields the contents of each block + """ + + while True: + block = infile.read(blocksize) + + read_bytes = len(block) + if read_bytes == 0: + break + + yield block + + if read_bytes < blocksize: + break + + +def compute_hash(message, method_name): + """Returns the message digest. + + :param message: the signed message. Can be an 8-bit string or a file-like + object. If ``message`` has a ``read()`` method, it is assumed to be a + file-like object. + :param method_name: the hash method, must be a key of + :py:const:`HASH_METHODS`. + + """ + + if method_name not in HASH_METHODS: + raise ValueError('Invalid hash method: %s' % method_name) + + method = HASH_METHODS[method_name] + hasher = method() + + if hasattr(message, 'read') and hasattr(message.read, '__call__'): + # read as 1K blocks + for block in yield_fixedblocks(message, 1024): + hasher.update(block) + else: + # hash the message object itself. + hasher.update(message) + + return hasher.digest() + + +def _find_method_hash(clearsig): + """Finds the hash method. + + :param clearsig: full padded ASN1 and hash. + :return: the used hash method. + :raise VerificationFailed: when the hash method cannot be found + """ + + for (hashname, asn1code) in HASH_ASN1.items(): + if asn1code in clearsig: + return hashname + + raise VerificationError('Verification failed') + + +__all__ = ['encrypt', 'decrypt', 'sign', 'verify', + 'DecryptionError', 'VerificationError', 'CryptoError'] + +if __name__ == '__main__': + print('Running doctests 1000x or until failure') + import doctest + + for count in range(1000): + (failures, tests) = doctest.testmod() + if failures: + break + + if count % 100 == 0 and count: + print('%i times' % count) + + print('Doctests done') diff --git a/Lambdas/Websocket Authorizer/rsa/pkcs1_v2.py b/Lambdas/Websocket Authorizer/rsa/pkcs1_v2.py new file mode 100644 index 0000000..5f9c7dd --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/pkcs1_v2.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Functions for PKCS#1 version 2 encryption and signing + +This module implements certain functionality from PKCS#1 version 2. Main +documentation is RFC 2437: https://tools.ietf.org/html/rfc2437 +""" + +from rsa._compat import range +from rsa import ( + common, + pkcs1, + transform, +) + + +def mgf1(seed, length, hasher='SHA-1'): + """ + MGF1 is a Mask Generation Function based on a hash function. + + A mask generation function takes an octet string of variable length and a + desired output length as input, and outputs an octet string of the desired + length. The plaintext-awareness of RSAES-OAEP relies on the random nature of + the output of the mask generation function, which in turn relies on the + random nature of the underlying hash. + + :param bytes seed: seed from which mask is generated, an octet string + :param int length: intended length in octets of the mask, at most 2^32(hLen) + :param str hasher: hash function (hLen denotes the length in octets of the hash + function output) + + :return: mask, an octet string of length `length` + :rtype: bytes + + :raise OverflowError: when `length` is too large for the specified `hasher` + :raise ValueError: when specified `hasher` is invalid + """ + + try: + hash_length = pkcs1.HASH_METHODS[hasher]().digest_size + except KeyError: + raise ValueError( + 'Invalid `hasher` specified. Please select one of: {hash_list}'.format( + hash_list=', '.join(sorted(pkcs1.HASH_METHODS.keys())) + ) + ) + + # If l > 2^32(hLen), output "mask too long" and stop. + if length > (2**32 * hash_length): + raise OverflowError( + "Desired length should be at most 2**32 times the hasher's output " + "length ({hash_length} for {hasher} function)".format( + hash_length=hash_length, + hasher=hasher, + ) + ) + + # Looping `counter` from 0 to ceil(l / hLen)-1, build `output` based on the + # hashes formed by (`seed` + C), being `C` an octet string of length 4 + # generated by converting `counter` with the primitive I2OSP + output = b''.join( + pkcs1.compute_hash( + seed + transform.int2bytes(counter, fill_size=4), + method_name=hasher, + ) + for counter in range(common.ceil_div(length, hash_length) + 1) + ) + + # Output the leading `length` octets of `output` as the octet string mask. + return output[:length] + + +__all__ = [ + 'mgf1', +] + +if __name__ == '__main__': + print('Running doctests 1000x or until failure') + import doctest + + for count in range(1000): + (failures, tests) = doctest.testmod() + if failures: + break + + if count % 100 == 0 and count: + print('%i times' % count) + + print('Doctests done') diff --git a/Lambdas/Websocket Authorizer/rsa/prime.py b/Lambdas/Websocket Authorizer/rsa/prime.py new file mode 100644 index 0000000..3d63542 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/prime.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Numerical functions related to primes. + +Implementation based on the book Algorithm Design by Michael T. Goodrich and +Roberto Tamassia, 2002. +""" + +from rsa._compat import range +import rsa.common +import rsa.randnum + +__all__ = ['getprime', 'are_relatively_prime'] + + +def gcd(p, q): + """Returns the greatest common divisor of p and q + + >>> gcd(48, 180) + 12 + """ + + while q != 0: + (p, q) = (q, p % q) + return p + + +def get_primality_testing_rounds(number): + """Returns minimum number of rounds for Miller-Rabing primality testing, + based on number bitsize. + + According to NIST FIPS 186-4, Appendix C, Table C.3, minimum number of + rounds of M-R testing, using an error probability of 2 ** (-100), for + different p, q bitsizes are: + * p, q bitsize: 512; rounds: 7 + * p, q bitsize: 1024; rounds: 4 + * p, q bitsize: 1536; rounds: 3 + See: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + """ + + # Calculate number bitsize. + bitsize = rsa.common.bit_size(number) + # Set number of rounds. + if bitsize >= 1536: + return 3 + if bitsize >= 1024: + return 4 + if bitsize >= 512: + return 7 + # For smaller bitsizes, set arbitrary number of rounds. + return 10 + + +def miller_rabin_primality_testing(n, k): + """Calculates whether n is composite (which is always correct) or prime + (which theoretically is incorrect with error probability 4**-k), by + applying Miller-Rabin primality testing. + + For reference and implementation example, see: + https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test + + :param n: Integer to be tested for primality. + :type n: int + :param k: Number of rounds (witnesses) of Miller-Rabin testing. + :type k: int + :return: False if the number is composite, True if it's probably prime. + :rtype: bool + """ + + # prevent potential infinite loop when d = 0 + if n < 2: + return False + + # Decompose (n - 1) to write it as (2 ** r) * d + # While d is even, divide it by 2 and increase the exponent. + d = n - 1 + r = 0 + + while not (d & 1): + r += 1 + d >>= 1 + + # Test k witnesses. + for _ in range(k): + # Generate random integer a, where 2 <= a <= (n - 2) + a = rsa.randnum.randint(n - 3) + 1 + + x = pow(a, d, n) + if x == 1 or x == n - 1: + continue + + for _ in range(r - 1): + x = pow(x, 2, n) + if x == 1: + # n is composite. + return False + if x == n - 1: + # Exit inner loop and continue with next witness. + break + else: + # If loop doesn't break, n is composite. + return False + + return True + + +def is_prime(number): + """Returns True if the number is prime, and False otherwise. + + >>> is_prime(2) + True + >>> is_prime(42) + False + >>> is_prime(41) + True + """ + + # Check for small numbers. + if number < 10: + return number in {2, 3, 5, 7} + + # Check for even numbers. + if not (number & 1): + return False + + # Calculate minimum number of rounds. + k = get_primality_testing_rounds(number) + + # Run primality testing with (minimum + 1) rounds. + return miller_rabin_primality_testing(number, k + 1) + + +def getprime(nbits): + """Returns a prime number that can be stored in 'nbits' bits. + + >>> p = getprime(128) + >>> is_prime(p-1) + False + >>> is_prime(p) + True + >>> is_prime(p+1) + False + + >>> from rsa import common + >>> common.bit_size(p) == 128 + True + """ + + assert nbits > 3 # the loop wil hang on too small numbers + + while True: + integer = rsa.randnum.read_random_odd_int(nbits) + + # Test for primeness + if is_prime(integer): + return integer + + # Retry if not prime + + +def are_relatively_prime(a, b): + """Returns True if a and b are relatively prime, and False if they + are not. + + >>> are_relatively_prime(2, 3) + True + >>> are_relatively_prime(2, 4) + False + """ + + d = gcd(a, b) + return d == 1 + + +if __name__ == '__main__': + print('Running doctests 1000x or until failure') + import doctest + + for count in range(1000): + (failures, tests) = doctest.testmod() + if failures: + break + + if count % 100 == 0 and count: + print('%i times' % count) + + print('Doctests done') diff --git a/Lambdas/Websocket Authorizer/rsa/randnum.py b/Lambdas/Websocket Authorizer/rsa/randnum.py new file mode 100644 index 0000000..310acaa --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/randnum.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Functions for generating random numbers.""" + +# Source inspired by code by Yesudeep Mangalapilly + +import os + +from rsa import common, transform +from rsa._compat import byte + + +def read_random_bits(nbits): + """Reads 'nbits' random bits. + + If nbits isn't a whole number of bytes, an extra byte will be appended with + only the lower bits set. + """ + + nbytes, rbits = divmod(nbits, 8) + + # Get the random bytes + randomdata = os.urandom(nbytes) + + # Add the remaining random bits + if rbits > 0: + randomvalue = ord(os.urandom(1)) + randomvalue >>= (8 - rbits) + randomdata = byte(randomvalue) + randomdata + + return randomdata + + +def read_random_int(nbits): + """Reads a random integer of approximately nbits bits. + """ + + randomdata = read_random_bits(nbits) + value = transform.bytes2int(randomdata) + + # Ensure that the number is large enough to just fill out the required + # number of bits. + value |= 1 << (nbits - 1) + + return value + + +def read_random_odd_int(nbits): + """Reads a random odd integer of approximately nbits bits. + + >>> read_random_odd_int(512) & 1 + 1 + """ + + value = read_random_int(nbits) + + # Make sure it's odd + return value | 1 + + +def randint(maxvalue): + """Returns a random integer x with 1 <= x <= maxvalue + + May take a very long time in specific situations. If maxvalue needs N bits + to store, the closer maxvalue is to (2 ** N) - 1, the faster this function + is. + """ + + bit_size = common.bit_size(maxvalue) + + tries = 0 + while True: + value = read_random_int(bit_size) + if value <= maxvalue: + break + + if tries % 10 == 0 and tries: + # After a lot of tries to get the right number of bits but still + # smaller than maxvalue, decrease the number of bits by 1. That'll + # dramatically increase the chances to get a large enough number. + bit_size -= 1 + tries += 1 + + return value diff --git a/Lambdas/Websocket Authorizer/rsa/transform.py b/Lambdas/Websocket Authorizer/rsa/transform.py new file mode 100644 index 0000000..628d0af --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/transform.py @@ -0,0 +1,215 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Data transformation functions. + +From bytes to a number, number to bytes, etc. +""" + +from __future__ import absolute_import + +import binascii +from struct import pack + +from rsa._compat import byte, is_integer +from rsa import common, machine_size + + +def bytes2int(raw_bytes): + r"""Converts a list of bytes or an 8-bit string to an integer. + + When using unicode strings, encode it to some encoding like UTF8 first. + + >>> (((128 * 256) + 64) * 256) + 15 + 8405007 + >>> bytes2int(b'\x80@\x0f') + 8405007 + + """ + + return int(binascii.hexlify(raw_bytes), 16) + + +def _int2bytes(number, block_size=None): + r"""Converts a number to a string of bytes. + + Usage:: + + >>> _int2bytes(123456789) + b'\x07[\xcd\x15' + >>> bytes2int(_int2bytes(123456789)) + 123456789 + + >>> _int2bytes(123456789, 6) + b'\x00\x00\x07[\xcd\x15' + >>> bytes2int(_int2bytes(123456789, 128)) + 123456789 + + >>> _int2bytes(123456789, 3) + Traceback (most recent call last): + ... + OverflowError: Needed 4 bytes for number, but block size is 3 + + @param number: the number to convert + @param block_size: the number of bytes to output. If the number encoded to + bytes is less than this, the block will be zero-padded. When not given, + the returned block is not padded. + + @throws OverflowError when block_size is given and the number takes up more + bytes than fit into the block. + """ + + # Type checking + if not is_integer(number): + raise TypeError("You must pass an integer for 'number', not %s" % + number.__class__) + + if number < 0: + raise ValueError('Negative numbers cannot be used: %i' % number) + + # Do some bounds checking + if number == 0: + needed_bytes = 1 + raw_bytes = [b'\x00'] + else: + needed_bytes = common.byte_size(number) + raw_bytes = [] + + # You cannot compare None > 0 in Python 3x. It will fail with a TypeError. + if block_size and block_size > 0: + if needed_bytes > block_size: + raise OverflowError('Needed %i bytes for number, but block size ' + 'is %i' % (needed_bytes, block_size)) + + # Convert the number to bytes. + while number > 0: + raw_bytes.insert(0, byte(number & 0xFF)) + number >>= 8 + + # Pad with zeroes to fill the block + if block_size and block_size > 0: + padding = (block_size - needed_bytes) * b'\x00' + else: + padding = b'' + + return padding + b''.join(raw_bytes) + + +def bytes_leading(raw_bytes, needle=b'\x00'): + """ + Finds the number of prefixed byte occurrences in the haystack. + + Useful when you want to deal with padding. + + :param raw_bytes: + Raw bytes. + :param needle: + The byte to count. Default \x00. + :returns: + The number of leading needle bytes. + """ + + leading = 0 + # Indexing keeps compatibility between Python 2.x and Python 3.x + _byte = needle[0] + for x in raw_bytes: + if x == _byte: + leading += 1 + else: + break + return leading + + +def int2bytes(number, fill_size=None, chunk_size=None, overflow=False): + """ + Convert an unsigned integer to bytes (base-256 representation):: + + Does not preserve leading zeros if you don't specify a chunk size or + fill size. + + .. NOTE: + You must not specify both fill_size and chunk_size. Only one + of them is allowed. + + :param number: + Integer value + :param fill_size: + If the optional fill size is given the length of the resulting + byte string is expected to be the fill size and will be padded + with prefix zero bytes to satisfy that length. + :param chunk_size: + If optional chunk size is given and greater than zero, pad the front of + the byte string with binary zeros so that the length is a multiple of + ``chunk_size``. + :param overflow: + ``False`` (default). If this is ``True``, no ``OverflowError`` + will be raised when the fill_size is shorter than the length + of the generated byte sequence. Instead the byte sequence will + be returned as is. + :returns: + Raw bytes (base-256 representation). + :raises: + ``OverflowError`` when fill_size is given and the number takes up more + bytes than fit into the block. This requires the ``overflow`` + argument to this function to be set to ``False`` otherwise, no + error will be raised. + """ + + if number < 0: + raise ValueError("Number must be an unsigned integer: %d" % number) + + if fill_size and chunk_size: + raise ValueError("You can either fill or pad chunks, but not both") + + # Ensure these are integers. + number & 1 + + raw_bytes = b'' + + # Pack the integer one machine word at a time into bytes. + num = number + word_bits, _, max_uint, pack_type = machine_size.get_word_alignment(num) + pack_format = ">%s" % pack_type + while num > 0: + raw_bytes = pack(pack_format, num & max_uint) + raw_bytes + num >>= word_bits + # Obtain the index of the first non-zero byte. + zero_leading = bytes_leading(raw_bytes) + if number == 0: + raw_bytes = b'\x00' + # De-padding. + raw_bytes = raw_bytes[zero_leading:] + + length = len(raw_bytes) + if fill_size and fill_size > 0: + if not overflow and length > fill_size: + raise OverflowError( + "Need %d bytes for number, but fill size is %d" % + (length, fill_size) + ) + raw_bytes = raw_bytes.rjust(fill_size, b'\x00') + elif chunk_size and chunk_size > 0: + remainder = length % chunk_size + if remainder: + padding_size = chunk_size - remainder + raw_bytes = raw_bytes.rjust(length + padding_size, b'\x00') + return raw_bytes + + +if __name__ == '__main__': + import doctest + + doctest.testmod() diff --git a/Lambdas/Websocket Authorizer/rsa/util.py b/Lambdas/Websocket Authorizer/rsa/util.py new file mode 100644 index 0000000..29d5eb1 --- /dev/null +++ b/Lambdas/Websocket Authorizer/rsa/util.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2011 Sybren A. Stüvel +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utility functions.""" + +from __future__ import with_statement, print_function + +import sys +from optparse import OptionParser + +import rsa.key + + +def private_to_public(): + """Reads a private key and outputs the corresponding public key.""" + + # Parse the CLI options + parser = OptionParser(usage='usage: %prog [options]', + description='Reads a private key and outputs the ' + 'corresponding public key. Both private and public keys use ' + 'the format described in PKCS#1 v1.5') + + parser.add_option('-i', '--input', dest='infilename', type='string', + help='Input filename. Reads from stdin if not specified') + parser.add_option('-o', '--output', dest='outfilename', type='string', + help='Output filename. Writes to stdout of not specified') + + parser.add_option('--inform', dest='inform', + help='key format of input - default PEM', + choices=('PEM', 'DER'), default='PEM') + + parser.add_option('--outform', dest='outform', + help='key format of output - default PEM', + choices=('PEM', 'DER'), default='PEM') + + (cli, cli_args) = parser.parse_args(sys.argv) + + # Read the input data + if cli.infilename: + print('Reading private key from %s in %s format' % + (cli.infilename, cli.inform), file=sys.stderr) + with open(cli.infilename, 'rb') as infile: + in_data = infile.read() + else: + print('Reading private key from stdin in %s format' % cli.inform, + file=sys.stderr) + in_data = sys.stdin.read().encode('ascii') + + assert type(in_data) == bytes, type(in_data) + + # Take the public fields and create a public key + priv_key = rsa.key.PrivateKey.load_pkcs1(in_data, cli.inform) + pub_key = rsa.key.PublicKey(priv_key.n, priv_key.e) + + # Save to the output file + out_data = pub_key.save_pkcs1(cli.outform) + + if cli.outfilename: + print('Writing public key to %s in %s format' % + (cli.outfilename, cli.outform), file=sys.stderr) + with open(cli.outfilename, 'wb') as outfile: + outfile.write(out_data) + else: + print('Writing public key to stdout in %s format' % cli.outform, + file=sys.stderr) + sys.stdout.write(out_data.decode('ascii')) diff --git a/Lambdas/Websocket Authorizer/six.py b/Lambdas/Websocket Authorizer/six.py new file mode 100644 index 0000000..89b2188 --- /dev/null +++ b/Lambdas/Websocket Authorizer/six.py @@ -0,0 +1,952 @@ +# Copyright (c) 2010-2018 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.12.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + try: + if from_value is None: + raise value + raise value from from_value + finally: + value = None +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + if hasattr(cls, '__qualname__'): + orig_vars['__qualname__'] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def ensure_binary(s, encoding='utf-8', errors='strict'): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, text_type): + return s.encode(encoding, errors) + elif isinstance(s, binary_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding='utf-8', errors='strict'): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + if PY2 and isinstance(s, text_type): + s = s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + s = s.decode(encoding, errors) + return s + + +def ensure_text(s, encoding='utf-8', errors='strict'): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + + +def python_2_unicode_compatible(klass): + """ + A decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/Lambdas/Websocket Authorizer/six.pyc b/Lambdas/Websocket Authorizer/six.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b21d59d065cf92ca0c9f821038b06ee3609a9e14 GIT binary patch literal 29688 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 BYcv1= literal 0 HcmV?d00001 diff --git a/Lambdas/testDynamoDBTrigger-f1faee29-85ed-443a-9247-4c77e82f9af6.zip b/Lambdas/testDynamoDBTrigger-f1faee29-85ed-443a-9247-4c77e82f9af6.zip new file mode 100644 index 0000000000000000000000000000000000000000..2e5be191a26c2dbe7a1b5aa8173aaf4e5d3556c5 GIT binary patch literal 793 zcmWIWW@h1HU|`^2n9`W%?^yBY@?<6khV85j3_?KBoW$Iul*IV7(!Au7%=|pPg375O zvH7zNL~5UhSIk=_ps5=b#ceoY=s_i`e?bO+bhr7g|um1Y` z^V#EH+s_`Gs?`4U>RZ1%?9rOv{;XqK+AM#Vz}F_1rfiEBJF|lxTkt3;8~G)kJCf;JEp}aFeuuNj%9B@g z&M0Px9QDaswfKdMQgK4=!;FH2O9$Sr=qUWXFL8$>Q~rZl`MK)B)$F)?vR#;^+Cuvvk z%HRaA`TL3^4%Tt^{j#2@F>UFQtX+DI+jz^(Ic^)Q`t?Qn0dL>N!1}KbF2`A!yySgT z&ibs(_yMmf`=pQa7TLDh1@$Zadzi@4*R@FgHD6mi|C#0z-isb58Z!&tJ?gw+C)+;j z+WvA||3t^)zi|rE*X;!~5>Hn2E_iqHhyDw;D}|r8Ro6)RANhDxZgJGL;KEH$G&tX$ z3cPZ%dTFm_LDj}NK@T=xQIbgbR;JQzel5e%&hV_w=k=C_p;KPncyS@~_sZUSqeCK% znZkG1TxfZFamLw63$#z3yzG;?Ona-S;hC6Ck!$CzE&S0j^V!<))kg)mTw@j&U-|Hc z>r;%tXTkW{{EvOVKbXJPKERuiNsbwJA_k^oFj&$EqA-(mfHx}}NQMyz9f0& +

+ + + + \ No newline at end of file diff --git a/Website/Back Home Files/home.component.scss b/Website/Back Home Files/home.component.scss new file mode 100644 index 0000000..c019528 --- /dev/null +++ b/Website/Back Home Files/home.component.scss @@ -0,0 +1,21 @@ +.message { + width: 250px; +} +.container { + //display: flex; + padding: 15px; +} +.flex-spacer { + flex-grow: 1; +} +table { + width: 100%; + } + +.mat-form-field { + font-size: 14px; + width: 100%; +} +th.mat-sort-header-sorted { + color: black; + } diff --git a/Website/Back Home Files/home.component.spec.ts b/Website/Back Home Files/home.component.spec.ts new file mode 100644 index 0000000..490e81b --- /dev/null +++ b/Website/Back Home Files/home.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HomeComponent } from './home.component'; + +describe('HomeComponent', () => { + let component: HomeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HomeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/Back Home Files/home.component.ts b/Website/Back Home Files/home.component.ts new file mode 100644 index 0000000..6b694a1 --- /dev/null +++ b/Website/Back Home Files/home.component.ts @@ -0,0 +1,174 @@ +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; +import { WebSocketSubject } from 'rxjs/webSocket'; +import Auth from '@aws-amplify/auth'; +import { MatTableDataSource } from '@angular/material/table'; +import { MatSort } from '@angular/material/sort'; + +export interface MyJSON { + location: string; + company: string; + volumeflow: number; + field: string; + intakepressure: number; + current: number; + frequency: number; +} + + + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.scss'] +}) + +export class HomeComponent implements OnInit, OnDestroy { + + constructor() { + Auth.currentAuthenticatedUser().then(data => { + // console.log(data); + this.roles = data.signInUserSession.idToken.payload['cognito:roles']; + this.groups = data.signInUserSession.idToken.payload['cognito:groups']; + this.groups.forEach( (element, index, array) => { + array[index] = element.replace(/_/g, ' '); + }); + this.currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0]; + this.token = data.signInUserSession.accessToken.jwtToken; + this.connect(); + }); + } + + public serverMessages: MyJSON[] = []; + private socket$: WebSocketSubject; + private currentMessage = {location: '', company: '', volumeflow: '', field: ''}; + totalFlowRate = 0; + private roles: string[]; + private groups: string[]; + private currentRole: string; + private token: string; + gaugeType = 'arch'; + gaugeCap = 'round'; + gaugeValue = this.currentMessage.volumeflow; + gaugeLabel = 'Volume Flow'; + gaugeAppendText = 'gpm'; + gaugeThick = 10; + gaugeMin = 0; + gaugeMax = 100; + gaugeThresholds = { + 0 : { color : 'red'}, + 33 : { color : 'orange'}, + 66 : { color : 'green'} + }; + + displayedColumns: string[] = ['location', 'company', 'field', 'current', 'volumeflow', 'intakepressure', 'frequency']; + dataSource = new MatTableDataSource(this.serverMessages); + + @ViewChild(MatSort, {static: true}) sort: MatSort; + + applyFilter(filterValue: string) { + this.dataSource.filter = filterValue.trim().toLowerCase(); + } + + ngOnInit() { + this.dataSource.sort = this.sort; + } + + ngOnDestroy() { + this.socket$.complete(); + } + + connect() { + this.connectWS(this.token, this.currentRole); + this.subscribeWS(); + this.socket$.next({action: 'getDashboardData', policy: this.currentRole}); + } + + connectWS(token: string, role: string) { + this.socket$ = new WebSocketSubject('wss://3fseaywb8b.execute-api.us-east-1.amazonaws.com/prototype?token=' + token + + '&role=' + role); + // console.log(this.socket$); + } + + subscribeWS() { + this.socket$.subscribe((message) => { + console.log(message); + if (message instanceof Array) { + message.forEach(element => { + this.updateList(element); + }); + } else { + this.updateList(message); + } + this.totalFlowRate = this.totalFlowRates(); + this.dataSource.data = this.serverMessages; + // console.log(this.serverMessages); + }, + (err) => console.error(err), + () => console.warn('Completed!') + ); + } + + updateList(obj: MyJSON) { + // console.log(this.serverMessages); + // console.log(obj); + const index = this.serverMessages.findIndex((e) => e.location === obj.location); + try { + obj.volumeflow = Number(obj.volumeflow.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + try { + obj.current = Number(obj.current.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + try { + obj.intakepressure = Number(obj.intakepressure.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + try { + obj.frequency = Number(obj.frequency.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + + if (index === -1) { + this.serverMessages.push(obj); + + } else { + if (! obj.volumeflow) { + obj.volumeflow = this.serverMessages[index].volumeflow; + } + if (! obj.current) { + obj.current = this.serverMessages[index].current; + } + if (! obj.frequency) { + obj.frequency = this.serverMessages[index].frequency; + } + if (! obj.intakepressure) { + obj.intakepressure = this.serverMessages[index].intakepressure; + } + this.serverMessages[index] = obj; + } + } + + totalFlowRates() { + let temp = 0; + this.serverMessages.forEach(element => { + if (element.volumeflow) { + temp += element.volumeflow; + } + }); + return Number(temp.toFixed(2)); + } + + setRole(index: number) { + this.currentRole = this.roles[index]; + this.socket$.complete(); + this.serverMessages = []; + this.connect(); + } +} + + diff --git a/Website/Backup Home D3/home.component.html b/Website/Backup Home D3/home.component.html new file mode 100644 index 0000000..23b70f1 --- /dev/null +++ b/Website/Backup Home D3/home.component.html @@ -0,0 +1,20 @@ +
+
+ Total Flow Rate {{ totalFlowRate }} + +
+ + + + + + + + +
+

{{ title }}

+ +
+ diff --git a/Website/Backup Home D3/home.component.scss b/Website/Backup Home D3/home.component.scss new file mode 100644 index 0000000..743124d --- /dev/null +++ b/Website/Backup Home D3/home.component.scss @@ -0,0 +1,43 @@ +.message { + width: 250px; +} +.container { + display: inline-block; + width: fit-content; + height: fit-content; + padding: 15px; +} +.viewer { + width: 100%; + height: 100%; +} +.flex-spacer { + flex-grow: 1; +} +table { + width: 100%; + } + +.mat-form-field { + font-size: 14px; + width: 100%; +} +th.mat-sort-header-sorted { + color: black; + } + +.svg-container { + display: inline-block; + position: relative; + width: 100%; + height: 100%; + padding-bottom: 0; + vertical-align: top; + overflow: hidden; +} +.svg-content-responsive { + display: inline-block; + position: absolute; + top: 10px; + left: 0; + } diff --git a/Website/Backup Home D3/home.component.spec.ts b/Website/Backup Home D3/home.component.spec.ts new file mode 100644 index 0000000..490e81b --- /dev/null +++ b/Website/Backup Home D3/home.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HomeComponent } from './home.component'; + +describe('HomeComponent', () => { + let component: HomeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HomeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/Backup Home D3/home.component.ts b/Website/Backup Home D3/home.component.ts new file mode 100644 index 0000000..22d8972 --- /dev/null +++ b/Website/Backup Home D3/home.component.ts @@ -0,0 +1,222 @@ +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; +import { WebSocketSubject } from 'rxjs/webSocket'; +import Auth from '@aws-amplify/auth'; +import { MatTableDataSource } from '@angular/material/table'; +import { MatSort } from '@angular/material/sort'; + +import * as d3 from 'd3-selection'; +import * as d3Scale from 'd3-scale'; +import * as d3Array from 'd3-array'; +import * as d3Axis from 'd3-axis'; +import * as d3Color from 'd3-scale-chromatic'; + + +export interface MyJSON { + location: string; + company: string; + volumeflow: number; + field: string; + intakepressure: number; + current: number; + frequency: number; +} + + + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.scss'] +}) + +export class HomeComponent implements OnInit, OnDestroy { + + constructor() { + Auth.currentAuthenticatedUser().then(data => { + // console.log(data); + this.roles = data.signInUserSession.idToken.payload['cognito:roles']; + this.groups = data.signInUserSession.idToken.payload['cognito:groups']; + this.groups.forEach( (element, index, array) => { + array[index] = element.replace(/_/g, ' '); + }); + this.currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0]; + this.token = data.signInUserSession.accessToken.jwtToken; + this.connect(); + }); + } + + public serverMessages: MyJSON[] = []; + private socket$: WebSocketSubject; + private currentMessage = {location: '', company: '', volumeflow: '', field: ''}; + totalFlowRate = 0; + private roles: string[]; + private groups: string[]; + private currentRole: string; + private token: string; + + title = 'Bar Chart'; + private width: number; + private height: number; + private margin = {top: 20, right: 20, bottom: 30, left: 40}; + colorScale: any; + + private x: any; + private y: any; + private svg: any; + private g: any; + + @ViewChild(MatSort, {static: true}) sort: MatSort; + + ngOnInit() { + this.initSvg(); + } + + ngOnDestroy() { + this.socket$.complete(); + } + + connect() { + this.connectWS(this.token, this.currentRole); + this.subscribeWS(); + this.socket$.next({action: 'getDashboardData', policy: this.currentRole}); + } + + connectWS(token: string, role: string) { + this.socket$ = new WebSocketSubject('wss://3fseaywb8b.execute-api.us-east-1.amazonaws.com/prototype?token=' + token + + '&role=' + role); + // console.log(this.socket$); + } + + subscribeWS() { + this.socket$.subscribe((message) => { + console.log(message); + if (message instanceof Array) { + message.forEach(element => { + this.updateList(element); + }); + } else { + this.updateList(message); + } + this.totalFlowRate = this.totalFlowRates(); + // console.log(this.serverMessages); + this.serverMessages.sort((a, b) => a.location.localeCompare(b.location)); + this.g + .append('g') + .attr('transform', 'translate(0,' + this.height + ')') + .attr('class', 'x-axis') + .call(d3Axis.axisBottom(this.x)); + + // add the y Axis + this.g + .append('g') + .attr('transform', 'translate(0, 0 )') + .attr('class', 'y-axis') + .call(d3Axis.axisLeft(this.y)); + this.drawAxis(); + }, + (err) => console.error(err), + () => console.warn('Completed!') + ); + } + + updateList(obj: MyJSON) { + // console.log(this.serverMessages); + // console.log(obj); + const index = this.serverMessages.findIndex((e) => e.location === obj.location); + try { + obj.volumeflow = Number(obj.volumeflow.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + try { + obj.current = Number(obj.current.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + try { + obj.intakepressure = Number(obj.intakepressure.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + try { + obj.frequency = Number(obj.frequency.toFixed(2)); + } catch { + console.log('can transform to fixed decimal data missing or not a number'); + } + + if (index === -1) { + this.svg + .selectAll('.bar') + .remove() + .exit(); + this.serverMessages.push(obj); + + } else { + if (! obj.volumeflow) { + obj.volumeflow = this.serverMessages[index].volumeflow; + } + if (! obj.current) { + obj.current = this.serverMessages[index].current; + } + if (! obj.frequency) { + obj.frequency = this.serverMessages[index].frequency; + } + if (! obj.intakepressure) { + obj.intakepressure = this.serverMessages[index].intakepressure; + } + this.serverMessages[index] = obj; + } + } + + totalFlowRates() { + let temp = 0; + this.serverMessages.forEach(element => { + if (element.volumeflow) { + temp += element.volumeflow; + } + }); + return Number(temp.toFixed(2)); + } + + setRole(index: number) { + this.currentRole = this.roles[index]; + this.socket$.complete(); + this.serverMessages = []; + this.drawAxis(); + this.connect(); + } + + private initSvg() { + this.svg = d3.select('svg'); + this.width = +this.svg.attr('width') - this.margin.left - this.margin.right; + this.height = +this.svg.attr('height') - this.margin.top - this.margin.bottom; + this.g = this.svg.append('g') + .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')'); + this.x = d3Scale.scaleBand().rangeRound([0, this.width]).padding(0.1); + this.y = d3Scale.scaleLinear().rangeRound([this.height, 0]); + this.colorScale = d3Scale.scaleOrdinal(d3Color.schemeCategory10); + } + + private drawAxis() { + this.x.domain(this.serverMessages.map((d) => d.location)); + this.y.domain([0, d3Array.max(this.serverMessages, d => d.volumeflow)]).ticks(10); + this.colorScale.domain(this.serverMessages.map(d => d.location)); + this.g + .selectAll('.bar,.tick') + .remove() + .exit() + .data(this.serverMessages) + .enter() + .append('rect') + .attr('class', 'bar') + .attr('x', d => this.x(d.location)) + .attr('width', this.x.bandwidth()) + .attr('y', d => this.y(d.volumeflow)) + .attr('height', d => this.height - this.y(d.volumeflow)) + .attr('fill', d => this.colorScale(d.location)); + this.g.select('.x-axis').call(d3Axis.axisBottom(this.x)); + this.g.select('.y-axis').call(d3Axis.axisLeft(this.y)); + } +} + + diff --git a/Website/HPIoTWebApp/.editorconfig b/Website/HPIoTWebApp/.editorconfig new file mode 100644 index 0000000..e89330a --- /dev/null +++ b/Website/HPIoTWebApp/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/Website/HPIoTWebApp/.gitignore b/Website/HPIoTWebApp/.gitignore new file mode 100644 index 0000000..c2aefe9 --- /dev/null +++ b/Website/HPIoTWebApp/.gitignore @@ -0,0 +1,58 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events*.json +speed-measure-plugin*.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db + +#amplify +amplify/\#current-cloud-backend +amplify/.config/local-* +amplify/mock-data +amplify/backend/amplify-meta.json +amplify/backend/awscloudformation +build/ +dist/ +node_modules/ +#aws-exports.js +awsconfiguration.json \ No newline at end of file diff --git a/Website/HPIoTWebApp/.vscode/settings.json b/Website/HPIoTWebApp/.vscode/settings.json new file mode 100644 index 0000000..88322cc --- /dev/null +++ b/Website/HPIoTWebApp/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "C:\\Python27\\python.exe" +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/README.md b/Website/HPIoTWebApp/README.md new file mode 100644 index 0000000..37ecfa5 --- /dev/null +++ b/Website/HPIoTWebApp/README.md @@ -0,0 +1,27 @@ +# HPIoTWebApp + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.1. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/Website/HPIoTWebApp/amplify/.config/project-config.json b/Website/HPIoTWebApp/amplify/.config/project-config.json new file mode 100644 index 0000000..f11732c --- /dev/null +++ b/Website/HPIoTWebApp/amplify/.config/project-config.json @@ -0,0 +1,17 @@ +{ + "projectName": "HPIoTWebApp", + "version": "3.0", + "frontend": "javascript", + "javascript": { + "framework": "angular", + "config": { + "SourceDir": "src", + "DistributionDir": "dist/HPIoTWebApp", + "BuildCommand": "npm.cmd run-script build", + "StartCommand": "npm start" + } + }, + "providers": [ + "awscloudformation" + ] +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/hpiotwebapp78e5977f-cloudformation-template.yml b/Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/hpiotwebapp78e5977f-cloudformation-template.yml new file mode 100644 index 0000000..6c4e532 --- /dev/null +++ b/Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/hpiotwebapp78e5977f-cloudformation-template.yml @@ -0,0 +1,366 @@ +AWSTemplateFormatVersion: 2010-09-09 + +Parameters: + env: + Type: String + authRoleArn: + Type: String + unauthRoleArn: + Type: String + + + + + identityPoolName: + Type: String + + allowUnauthenticatedIdentities: + Type: String + + resourceNameTruncated: + Type: String + + userPoolName: + Type: String + + autoVerifiedAttributes: + Type: CommaDelimitedList + + mfaConfiguration: + Type: String + + mfaTypes: + Type: CommaDelimitedList + + smsAuthenticationMessage: + Type: String + + smsVerificationMessage: + Type: String + + emailVerificationSubject: + Type: String + + emailVerificationMessage: + Type: String + + defaultPasswordPolicy: + Type: String + + passwordPolicyMinLength: + Type: Number + + passwordPolicyCharacters: + Type: CommaDelimitedList + + requiredAttributes: + Type: CommaDelimitedList + + userpoolClientGenerateSecret: + Type: String + + userpoolClientRefreshTokenValidity: + Type: Number + + userpoolClientWriteAttributes: + Type: CommaDelimitedList + + userpoolClientReadAttributes: + Type: CommaDelimitedList + + userpoolClientLambdaRole: + Type: String + + userpoolClientSetAttributes: + Type: String + + resourceName: + Type: String + + authSelections: + Type: String + + useDefault: + Type: String + + usernameAttributes: + Type: CommaDelimitedList + + dependsOn: + Type: CommaDelimitedList + +Conditions: + ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ] + +Resources: + + + # BEGIN SNS ROLE RESOURCE + SNSRole: + # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process + Type: AWS::IAM::Role + Properties: + RoleName: !If [ShouldNotCreateEnvResources, 'hpiotw78e5977f_sns-role', !Join ['',['hpiotw78e5977f_sns-role', '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "" + Effect: "Allow" + Principal: + Service: "cognito-idp.amazonaws.com" + Action: + - "sts:AssumeRole" + Condition: + StringEquals: + sts:ExternalId: hpiotw78e5977f_role_external_id + Policies: + - + PolicyName: hpiotw78e5977f-sns-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - + Effect: "Allow" + Action: + - "sns:Publish" + Resource: "*" + # BEGIN USER POOL RESOURCES + UserPool: + # Created upon user selection + # Depends on SNS Role for Arn if MFA is enabled + Type: AWS::Cognito::UserPool + UpdateReplacePolicy: Retain + Properties: + UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]] + + Schema: + + - + Name: email + Required: true + Mutable: true + + + + + AutoVerifiedAttributes: !Ref autoVerifiedAttributes + + + EmailVerificationMessage: !Ref emailVerificationMessage + EmailVerificationSubject: !Ref emailVerificationSubject + + Policies: + PasswordPolicy: + MinimumLength: !Ref passwordPolicyMinLength + RequireLowercase: false + RequireNumbers: false + RequireSymbols: false + RequireUppercase: false + + UsernameAttributes: !Ref usernameAttributes + + MfaConfiguration: !Ref mfaConfiguration + SmsVerificationMessage: !Ref smsVerificationMessage + SmsConfiguration: + SnsCallerArn: !GetAtt SNSRole.Arn + ExternalId: hpiotw78e5977f_role_external_id + + + UserPoolClientWeb: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: hpiotw78e5977f_app_clientWeb + + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + UserPoolClient: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: hpiotw78e5977f_app_client + + GenerateSecret: !Ref userpoolClientGenerateSecret + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + # BEGIN USER POOL LAMBDA RESOURCES + UserPoolClientRole: + # Created to execute Lambda which gets userpool app client config values + Type: 'AWS::IAM::Role' + Properties: + RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - 'sts:AssumeRole' + DependsOn: UserPoolClient + UserPoolClientLambda: + # Lambda which gets userpool app client config values + # Depends on UserPool for id + # Depends on UserPoolClientRole for role ARN + Type: 'AWS::Lambda::Function' + Properties: + Code: + ZipFile: !Join + - |+ + - - 'const response = require(''cfn-response'');' + - 'const aws = require(''aws-sdk'');' + - 'const identity = new aws.CognitoIdentityServiceProvider();' + - 'exports.handler = (event, context, callback) => {' + - ' if (event.RequestType == ''Delete'') { ' + - ' response.send(event, context, response.SUCCESS, {})' + - ' }' + - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' + - ' const params = {' + - ' ClientId: event.ResourceProperties.clientId,' + - ' UserPoolId: event.ResourceProperties.userpoolId' + - ' };' + - ' identity.describeUserPoolClient(params).promise()' + - ' .then((res) => {' + - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});' + - ' })' + - ' .catch((err) => {' + - ' response.send(event, context, response.FAILED, {err});' + - ' });' + - ' }' + - '};' + Handler: index.handler + Runtime: nodejs10.x + Timeout: '300' + Role: !GetAtt + - UserPoolClientRole + - Arn + DependsOn: UserPoolClientRole + UserPoolClientLambdaPolicy: + # Sets userpool policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: hpiotw78e5977f_userpoolclient_lambda_iam_policy + Roles: + - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]] + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - 'cognito-idp:DescribeUserPoolClient' + Resource: !GetAtt UserPool.Arn + DependsOn: UserPoolClientLambda + UserPoolClientLogPolicy: + # Sets log policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: hpiotw78e5977f_userpoolclient_lambda_log_policy + Roles: + - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]] + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'logs:CreateLogGroup' + - 'logs:CreateLogStream' + - 'logs:PutLogEvents' + Resource: !Sub + - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* + - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda} + DependsOn: UserPoolClientLambdaPolicy + UserPoolClientInputs: + # Values passed to Userpool client Lambda + # Depends on UserPool for Id + # Depends on UserPoolClient for Id + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'Custom::LambdaCallout' + Properties: + ServiceToken: !GetAtt UserPoolClientLambda.Arn + clientId: !Ref UserPoolClient + userpoolId: !Ref UserPool + DependsOn: UserPoolClientLogPolicy + + + + + + + + # BEGIN IDENTITY POOL RESOURCES + + + IdentityPool: + # Always created + Type: AWS::Cognito::IdentityPool + Properties: + IdentityPoolName: !If [ShouldNotCreateEnvResources, 'hpiotwebapp78e5977f_identitypool_78e5977f', !Join ['',['hpiotwebapp78e5977f_identitypool_78e5977f', '__', !Ref env]]] + + CognitoIdentityProviders: + - ClientId: !Ref UserPoolClient + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + - ClientId: !Ref UserPoolClientWeb + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + + AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities + + + DependsOn: UserPoolClientInputs + + + IdentityPoolRoleMap: + # Created to map Auth and Unauth roles to the identity pool + # Depends on Identity Pool for ID ref + Type: AWS::Cognito::IdentityPoolRoleAttachment + Properties: + IdentityPoolId: !Ref IdentityPool + Roles: + unauthenticated: !Ref unauthRoleArn + authenticated: !Ref authRoleArn + DependsOn: IdentityPool + + +Outputs : + + IdentityPoolId: + Value: !Ref 'IdentityPool' + Description: Id for the identity pool + IdentityPoolName: + Value: !GetAtt IdentityPool.Name + + + + + UserPoolId: + Value: !Ref 'UserPool' + Description: Id for the user pool + UserPoolName: + Value: !Ref userPoolName + AppClientIDWeb: + Value: !Ref 'UserPoolClientWeb' + Description: The user pool app client id for web + AppClientID: + Value: !Ref 'UserPoolClient' + Description: The user pool app client id + AppClientSecret: + Value: !GetAtt UserPoolClientInputs.appSecret + + + + + + + \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/parameters.json b/Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/parameters.json new file mode 100644 index 0000000..4f56103 --- /dev/null +++ b/Website/HPIoTWebApp/amplify/backend/auth/hpiotwebapp78e5977f/parameters.json @@ -0,0 +1,52 @@ +{ + "identityPoolName": "hpiotwebapp78e5977f_identitypool_78e5977f", + "allowUnauthenticatedIdentities": false, + "resourceNameTruncated": "hpiotw78e5977f", + "userPoolName": "hpiotwebapp78e5977f_userpool_78e5977f", + "autoVerifiedAttributes": [ + "email" + ], + "mfaConfiguration": "OFF", + "mfaTypes": [ + "SMS Text Message" + ], + "smsAuthenticationMessage": "Your authentication code is {####}", + "smsVerificationMessage": "Your verification code is {####}", + "emailVerificationSubject": "Your verification code", + "emailVerificationMessage": "Your verification code is {####}", + "defaultPasswordPolicy": false, + "passwordPolicyMinLength": 8, + "passwordPolicyCharacters": [], + "requiredAttributes": [ + "email" + ], + "userpoolClientGenerateSecret": true, + "userpoolClientRefreshTokenValidity": 30, + "userpoolClientWriteAttributes": [ + "email" + ], + "userpoolClientReadAttributes": [ + "email" + ], + "userpoolClientLambdaRole": "hpiotw78e5977f_userpoolclient_lambda_role", + "userpoolClientSetAttributes": false, + "resourceName": "hpiotwebapp78e5977f", + "authSelections": "identityPoolAndUserPool", + "authRoleArn": { + "Fn::GetAtt": [ + "AuthRole", + "Arn" + ] + }, + "unauthRoleArn": { + "Fn::GetAtt": [ + "UnauthRole", + "Arn" + ] + }, + "useDefault": "default", + "usernameAttributes": [ + "email, phone_number" + ], + "dependsOn": [] +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/backend/backend-config.json b/Website/HPIoTWebApp/amplify/backend/backend-config.json new file mode 100644 index 0000000..6f6535a --- /dev/null +++ b/Website/HPIoTWebApp/amplify/backend/backend-config.json @@ -0,0 +1,21 @@ +{ + "hosting": { + "S3AndCloudFront": { + "service": "S3AndCloudFront", + "providerPlugin": "awscloudformation" + } + }, + "auth": { + "hpiotwebapp78e5977f": { + "service": "Cognito", + "providerPlugin": "awscloudformation", + "dependsOn": [] + } + }, + "storage": { + "hpiotuserstorage": { + "service": "S3", + "providerPlugin": "awscloudformation" + } + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/parameters.json b/Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/parameters.json new file mode 100644 index 0000000..3641037 --- /dev/null +++ b/Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/parameters.json @@ -0,0 +1,3 @@ +{ + "bucketName": "hpiotwebapp" +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/template.json b/Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/template.json new file mode 100644 index 0000000..57f33a7 --- /dev/null +++ b/Website/HPIoTWebApp/amplify/backend/hosting/S3AndCloudFront/template.json @@ -0,0 +1,271 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Hosting resource stack creation using Amplify CLI", + "Parameters": { + "env": { + "Type": "String" + }, + "bucketName": { + "Type": "String" + } + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + } + }, + "Resources": { + "S3Bucket": { + "Type": "AWS::S3::Bucket", + "DeletionPolicy": "Retain", + "Properties": { + "BucketName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + { + "Ref": "bucketName" + }, + { + "Fn::Join": [ + "", + [ + { + "Ref": "bucketName" + }, + "-", + { + "Ref": "env" + } + ] + ] + } + ] + }, + "WebsiteConfiguration": { + "IndexDocument": "index.html", + "ErrorDocument": "index.html" + }, + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedHeaders": [ + "Authorization", + "Content-Length" + ], + "AllowedMethods": [ + "GET" + ], + "AllowedOrigins": [ + "*" + ], + "MaxAge": 3000 + } + ] + } + } + }, + "PrivateBucketPolicy": { + "Type": "AWS::S3::BucketPolicy", + "DependsOn": "OriginAccessIdentity", + "Properties": { + "PolicyDocument": { + "Id": "MyPolicy", + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "APIReadForGetBucketObjects", + "Effect": "Allow", + "Principal": { + "CanonicalUser": { + "Fn::GetAtt": [ + "OriginAccessIdentity", + "S3CanonicalUserId" + ] + } + }, + "Action": "s3:GetObject", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/*" + ] + ] + } + } + ] + }, + "Bucket": { + "Ref": "S3Bucket" + } + } + }, + "OriginAccessIdentity": { + "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", + "Properties": { + "CloudFrontOriginAccessIdentityConfig": { + "Comment": "CloudFrontOriginAccessIdentityConfig" + } + } + }, + "CloudFrontDistribution": { + "Type": "AWS::CloudFront::Distribution", + "DependsOn": [ + "S3Bucket", + "OriginAccessIdentity" + ], + "Properties": { + "DistributionConfig": { + "Origins": [ + { + "DomainName": { + "Fn::GetAtt": [ + "S3Bucket", + "DomainName" + ] + }, + "Id": "hostingS3Bucket", + "S3OriginConfig": { + "OriginAccessIdentity": { + "Fn::Join": [ + "", + [ + "origin-access-identity/cloudfront/", + { + "Ref": "OriginAccessIdentity" + } + ] + ] + } + } + } + ], + "Enabled": "true", + "DefaultCacheBehavior": { + "AllowedMethods": [ + "DELETE", + "GET", + "HEAD", + "OPTIONS", + "PATCH", + "POST", + "PUT" + ], + "TargetOriginId": "hostingS3Bucket", + "ForwardedValues": { + "QueryString": "false" + }, + "ViewerProtocolPolicy": "redirect-to-https", + "DefaultTTL": 86400, + "MaxTTL": 31536000, + "MinTTL": 60, + "Compress": true + }, + "DefaultRootObject": "index.html", + "CustomErrorResponses": [ + { + "ErrorCachingMinTTL": 300, + "ErrorCode": 400, + "ResponseCode": 200, + "ResponsePagePath": "/" + }, + { + "ErrorCachingMinTTL": 300, + "ErrorCode": 403, + "ResponseCode": 200, + "ResponsePagePath": "/" + }, + { + "ErrorCachingMinTTL": 300, + "ErrorCode": 404, + "ResponseCode": 200, + "ResponsePagePath": "/" + } + ] + } + } + } + }, + "Outputs": { + "Region": { + "Value": { + "Ref": "AWS::Region" + } + }, + "HostingBucketName": { + "Description": "Hosting bucket name", + "Value": { + "Ref": "S3Bucket" + } + }, + "WebsiteURL": { + "Value": { + "Fn::GetAtt": [ + "S3Bucket", + "WebsiteURL" + ] + }, + "Description": "URL for website hosted on S3" + }, + "S3BucketSecureURL": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "S3Bucket", + "DomainName" + ] + } + ] + ] + }, + "Description": "Name of S3 bucket to hold website content" + }, + "CloudFrontDistributionID": { + "Value": { + "Ref": "CloudFrontDistribution" + } + }, + "CloudFrontDomainName": { + "Value": { + "Fn::GetAtt": [ + "CloudFrontDistribution", + "DomainName" + ] + } + }, + "CloudFrontSecureURL": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "CloudFrontDistribution", + "DomainName" + ] + } + ] + ] + } + }, + "CloudFrontOriginAccessIdentity": { + "Value": { + "Ref": "OriginAccessIdentity" + } + } + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/parameters.json b/Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/parameters.json new file mode 100644 index 0000000..82fc310 --- /dev/null +++ b/Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/parameters.json @@ -0,0 +1,34 @@ +{ + "bucketName": "hpiotuserstorage", + "authPolicyName": "s3_amplify_ba83ba82", + "unauthPolicyName": "s3_amplify_ba83ba82", + "authRoleName": { + "Ref": "AuthRoleName" + }, + "unauthRoleName": { + "Ref": "UnauthRoleName" + }, + "selectedGuestPermissions": [ + "s3:GetObject", + "s3:ListBucket" + ], + "selectedAuthenticatedPermissions": [ + "s3:PutObject", + "s3:GetObject", + "s3:ListBucket" + ], + "s3PermissionsAuthenticatedPublic": "s3:PutObject,s3:GetObject", + "s3PublicPolicy": "Public_policy_4ff86870", + "s3PermissionsAuthenticatedUploads": "s3:PutObject", + "s3UploadsPolicy": "Uploads_policy_4ff86870", + "s3PermissionsAuthenticatedProtected": "s3:PutObject,s3:GetObject", + "s3ProtectedPolicy": "Protected_policy_4ff86870", + "s3PermissionsAuthenticatedPrivate": "s3:PutObject,s3:GetObject", + "s3PrivatePolicy": "Private_policy_4ff86870", + "AuthenticatedAllowList": "ALLOW", + "s3ReadPolicy": "read_policy_4ff86870", + "s3PermissionsGuestPublic": "DISALLOW", + "s3PermissionsGuestUploads": "DISALLOW", + "GuestAllowList": "DISALLOW", + "triggerFunction": "NONE" +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/s3-cloudformation-template.json b/Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/s3-cloudformation-template.json new file mode 100644 index 0000000..73848eb --- /dev/null +++ b/Website/HPIoTWebApp/amplify/backend/storage/hpiotuserstorage/s3-cloudformation-template.json @@ -0,0 +1,631 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "S3 resource stack creation using Amplify CLI", + "Parameters": { + "bucketName": { + "Type": "String" + }, + "authPolicyName": { + "Type": "String" + }, + "unauthPolicyName": { + "Type": "String" + }, + "authRoleName": { + "Type": "String" + }, + "unauthRoleName": { + "Type": "String" + }, + "s3PublicPolicy": { + "Type": "String" + }, + "s3PrivatePolicy": { + "Type": "String" + }, + "s3ProtectedPolicy": { + "Type": "String" + }, + "s3UploadsPolicy": { + "Type": "String" + }, + "s3ReadPolicy": { + "Type": "String" + }, + "s3PermissionsAuthenticatedPublic": { + "Type": "String" + }, + "s3PermissionsAuthenticatedProtected": { + "Type": "String" + }, + "s3PermissionsAuthenticatedPrivate": { + "Type": "String" + }, + "s3PermissionsAuthenticatedUploads": { + "Type": "String" + }, + "s3PermissionsGuestPublic": { + "Type": "String", + "Default" : "DISALLOW" + }, + "s3PermissionsGuestUploads": { + "Type": "String", + "Default" : "DISALLOW" }, + "AuthenticatedAllowList": { + "Type": "String" + }, + "GuestAllowList": { + "Type": "String", + "Default" : "DISALLOW" + }, + "selectedGuestPermissions": { + "Type": "CommaDelimitedList" + }, + "selectedAuthenticatedPermissions": { + "Type": "CommaDelimitedList" + }, + "env": { + "Type": "String" + }, + "triggerFunction": { + "Type": "String" + } + + + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + }, + "CreateAuthPublic": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "s3PermissionsAuthenticatedPublic"}, + "DISALLOW" + ] + }] + }, + "CreateAuthProtected": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "s3PermissionsAuthenticatedProtected"}, + "DISALLOW" + ] + }] + }, + "CreateAuthPrivate": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "s3PermissionsAuthenticatedPrivate"}, + "DISALLOW" + ] + }] + }, + "CreateAuthUploads": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "s3PermissionsAuthenticatedUploads"}, + "DISALLOW" + ] + }] + }, + "CreateGuestPublic": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "s3PermissionsGuestPublic"}, + "DISALLOW" + ] + }] + }, + "CreateGuestUploads": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "s3PermissionsGuestUploads"}, + "DISALLOW" + ] + }] + }, + "AuthReadAndList": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "AuthenticatedAllowList"}, + "DISALLOW" + ] + }] + }, + "GuestReadAndList": { + "Fn::Not" : [{ + "Fn::Equals" : [ + {"Ref" : "GuestAllowList"}, + "DISALLOW" + ] + }] + } + }, + "Resources": { + "S3Bucket": { + "Type": "AWS::S3::Bucket", + + "DeletionPolicy" : "Retain", + "Properties": { + "BucketName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + { + "Ref": "bucketName" + }, + { + "Fn::Join": [ + "", + [ + { + "Ref": "bucketName" + }, + "-", + { + "Ref": "env" + } + ] + ] + } + ] + }, + + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedHeaders": [ + "*" + ], + "AllowedMethods": [ + "GET", + "HEAD", + "PUT", + "POST", + "DELETE" + ], + "AllowedOrigins": [ + "*" + ], + "ExposedHeaders": [ + "x-amz-server-side-encryption", + "x-amz-request-id", + "x-amz-id-2", + "ETag" + ], + "Id": "S3CORSRuleId1", + "MaxAge": "3000" + } + ] + } + } + }, + + "S3AuthPublicPolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "CreateAuthPublic", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3PublicPolicy" + }, + "Roles": [ + { + "Ref": "authRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": { + "Fn::Split" : [ "," , { + "Ref": "s3PermissionsAuthenticatedPublic" + } ] + }, + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/public/*" + ] + ] + } + ] + } + ] + } + } + }, + "S3AuthProtectedPolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "CreateAuthProtected", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3ProtectedPolicy" + }, + "Roles": [ + { + "Ref": "authRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": { + "Fn::Split" : [ "," , { + "Ref": "s3PermissionsAuthenticatedProtected" + } ] + }, + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/protected/${cognito-identity.amazonaws.com:sub}/*" + ] + ] + } + ] + } + ] + } + } + }, + "S3AuthPrivatePolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "CreateAuthPrivate", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3PrivatePolicy" + }, + "Roles": [ + { + "Ref": "authRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": { + "Fn::Split" : [ "," , { + "Ref": "s3PermissionsAuthenticatedPrivate" + } ] + }, + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/private/${cognito-identity.amazonaws.com:sub}/*" + ] + ] + } + ] + } + ] + } + } + }, + "S3AuthUploadPolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "CreateAuthUploads", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3UploadsPolicy" + }, + "Roles": [ + { + "Ref": "authRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": { + "Fn::Split" : [ "," , { + "Ref": "s3PermissionsAuthenticatedUploads" + } ] + }, + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/uploads/*" + ] + ] + } + ] + } + ] + } + } + }, + "S3AuthReadPolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "AuthReadAndList", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3ReadPolicy" + }, + "Roles": [ + { + "Ref": "authRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:GetObject" + ], + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/protected/*" + ] + ] + } + ] + }, + { + "Effect": "Allow", + "Action": [ + "s3:ListBucket" + ], + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + } + ] + ] + } + ], + "Condition": { + "StringLike": { + "s3:prefix": [ + "public/", + "public/*", + "protected/", + "protected/*", + "private/${cognito-identity.amazonaws.com:sub}/", + "private/${cognito-identity.amazonaws.com:sub}/*" + ] + } + } + } + ] + } + } + }, + "S3GuestPublicPolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "CreateGuestPublic", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3PublicPolicy" + }, + "Roles": [ + { + "Ref": "unauthRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": { + "Fn::Split" : [ "," , { + "Ref": "s3PermissionsGuestPublic" + } ] + }, + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/public/*" + ] + ] + } + ] + } + ] + } + } + }, + "S3GuestUploadPolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "CreateGuestUploads", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3UploadsPolicy" + }, + "Roles": [ + { + "Ref": "unauthRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": { + "Fn::Split" : [ "," , { + "Ref": "s3PermissionsGuestUploads" + } ] + }, + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/uploads/*" + ] + ] + } + ] + } + ] + } + } + }, + "S3GuestReadPolicy": { + "DependsOn": [ + "S3Bucket" + ], + "Condition": "GuestReadAndList", + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": { + "Ref": "s3ReadPolicy" + }, + "Roles": [ + { + "Ref": "unauthRoleName" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:GetObject" + ], + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + }, + "/protected/*" + ] + ] + } + ] + }, + { + "Effect": "Allow", + "Action": [ + "s3:ListBucket" + ], + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:s3:::", + { + "Ref": "S3Bucket" + } + ] + ] + } + ], + "Condition": { + "StringLike": { + "s3:prefix": [ + "public/", + "public/*", + "protected/", + "protected/*" + ] + } + } + } + ] + } + } + } + }, + "Outputs": { + "BucketName": { + "Value": { + "Ref": "S3Bucket" + }, + "Description": "Bucket name for the S3 bucket" + }, + "Region": { + "Value": { + "Ref": "AWS::Region" + } + } + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/amplify/team-provider-info.json b/Website/HPIoTWebApp/amplify/team-provider-info.json new file mode 100644 index 0000000..e27b93a --- /dev/null +++ b/Website/HPIoTWebApp/amplify/team-provider-info.json @@ -0,0 +1,31 @@ +{ + "dev": { + "awscloudformation": { + "AuthRoleName": "hpiotwebapp-dev-20191011145158-authRole", + "UnauthRoleArn": "arn:aws:iam::860246592755:role/hpiotwebapp-dev-20191011145158-unauthRole", + "AuthRoleArn": "arn:aws:iam::860246592755:role/hpiotwebapp-dev-20191011145158-authRole", + "Region": "us-east-1", + "DeploymentBucketName": "hpiotwebapp-dev-20191011145158-deployment", + "UnauthRoleName": "hpiotwebapp-dev-20191011145158-unauthRole", + "StackName": "hpiotwebapp-dev-20191011145158", + "StackId": "arn:aws:cloudformation:us-east-1:860246592755:stack/hpiotwebapp-dev-20191011145158/95829790-ec60-11e9-a33f-1207b4ca758c" + } + }, + "devs": { + "awscloudformation": { + "AuthRoleName": "hpiotwebapp-devs-20191011153744-authRole", + "UnauthRoleArn": "arn:aws:iam::860246592755:role/hpiotwebapp-devs-20191011153744-unauthRole", + "AuthRoleArn": "arn:aws:iam::860246592755:role/hpiotwebapp-devs-20191011153744-authRole", + "Region": "us-east-1", + "DeploymentBucketName": "hpiotwebapp-devs-20191011153744-deployment", + "UnauthRoleName": "hpiotwebapp-devs-20191011153744-unauthRole", + "StackName": "hpiotwebapp-devs-20191011153744", + "StackId": "arn:aws:cloudformation:us-east-1:860246592755:stack/hpiotwebapp-devs-20191011153744/fa4c3b30-ec66-11e9-8123-0e639cbb91d4" + }, + "categories": { + "auth": { + "hpiotwebapp78e5977f": {} + } + } + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/angular.json b/Website/HPIoTWebApp/angular.json new file mode 100644 index 0000000..1f5953b --- /dev/null +++ b/Website/HPIoTWebApp/angular.json @@ -0,0 +1,139 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "HPIoTWebApp": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/HPIoTWebApp", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "aot": false, + "assets": [ + "src/favicon.ico", + "src/assets", + "src/manifest.webmanifest" + ], + "styles": [ + "./node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css", + "src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb", + "maximumError": "10kb" + } + ], + "serviceWorker": true, + "ngswConfigPath": "ngsw-config.json" + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "HPIoTWebApp:build" + }, + "configurations": { + "production": { + "browserTarget": "HPIoTWebApp:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "HPIoTWebApp:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "assets": [ + "src/favicon.ico", + "src/assets", + "src/manifest.webmanifest" + ], + "styles": [ + "./node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css", + "src/styles.scss" + ], + "scripts": [] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "tsconfig.app.json", + "tsconfig.spec.json", + "e2e/tsconfig.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + }, + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "HPIoTWebApp:serve" + }, + "configurations": { + "production": { + "devServerTarget": "HPIoTWebApp:serve:production" + } + } + } + } + } + }, + "defaultProject": "HPIoTWebApp", + "cli": { + "analytics": false + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/browserslist b/Website/HPIoTWebApp/browserslist new file mode 100644 index 0000000..8084853 --- /dev/null +++ b/Website/HPIoTWebApp/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/Website/HPIoTWebApp/e2e/protractor.conf.js b/Website/HPIoTWebApp/e2e/protractor.conf.js new file mode 100644 index 0000000..73e4e68 --- /dev/null +++ b/Website/HPIoTWebApp/e2e/protractor.conf.js @@ -0,0 +1,32 @@ +// @ts-check +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +/** + * @type { import("protractor").Config } + */ +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; \ No newline at end of file diff --git a/Website/HPIoTWebApp/e2e/src/app.e2e-spec.ts b/Website/HPIoTWebApp/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000..ddcd7d9 --- /dev/null +++ b/Website/HPIoTWebApp/e2e/src/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import { AppPage } from './app.po'; +import { browser, logging } from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('Welcome to HPIoTWebApp!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry)); + }); +}); diff --git a/Website/HPIoTWebApp/e2e/src/app.po.ts b/Website/HPIoTWebApp/e2e/src/app.po.ts new file mode 100644 index 0000000..5776aa9 --- /dev/null +++ b/Website/HPIoTWebApp/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get(browser.baseUrl) as Promise; + } + + getTitleText() { + return element(by.css('app-root h1')).getText() as Promise; + } +} diff --git a/Website/HPIoTWebApp/e2e/tsconfig.json b/Website/HPIoTWebApp/e2e/tsconfig.json new file mode 100644 index 0000000..39b800f --- /dev/null +++ b/Website/HPIoTWebApp/e2e/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} diff --git a/Website/HPIoTWebApp/karma.conf.js b/Website/HPIoTWebApp/karma.conf.js new file mode 100644 index 0000000..900a226 --- /dev/null +++ b/Website/HPIoTWebApp/karma.conf.js @@ -0,0 +1,32 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, './coverage/HPIoTWebApp'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/Website/HPIoTWebApp/ngsw-config.json b/Website/HPIoTWebApp/ngsw-config.json new file mode 100644 index 0000000..4ddf1a7 --- /dev/null +++ b/Website/HPIoTWebApp/ngsw-config.json @@ -0,0 +1,29 @@ +{ + "$schema": "./node_modules/@angular/service-worker/config/schema.json", + "index": "/index.html", + "assetGroups": [ + { + "name": "app", + "installMode": "prefetch", + "resources": { + "files": [ + "/favicon.ico", + "/index.html", + "/manifest.webmanifest", + "/*.css", + "/*.js" + ] + } + }, { + "name": "assets", + "installMode": "lazy", + "updateMode": "prefetch", + "resources": { + "files": [ + "/assets/**", + "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" + ] + } + } + ] +} diff --git a/Website/HPIoTWebApp/package-lock.json b/Website/HPIoTWebApp/package-lock.json new file mode 100644 index 0000000..99b1f6d --- /dev/null +++ b/Website/HPIoTWebApp/package-lock.json @@ -0,0 +1,16280 @@ +{ + "name": "hpio-tweb-app", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.900.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.900.1.tgz", + "integrity": "sha512-zzB3J0fXFoYeJpgF5tsmZ7byygzjJn1IPiXBdnbNqcMbil1OPOhq+KdD4ZFPyXNwBQ3w02kOwPdNqB++jbPmlQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.1", + "rxjs": "6.5.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/build-angular": { + "version": "0.900.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.900.1.tgz", + "integrity": "sha512-e1/EiNI9UAKJxI9+7KA59A15Rkx2QA86evb9iUuwxWGvIsTsN/sg/oXUZA//nTUQTAht+qWJp3I2amd/nyQZLQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.900.1", + "@angular-devkit/build-optimizer": "0.900.1", + "@angular-devkit/build-webpack": "0.900.1", + "@angular-devkit/core": "9.0.1", + "@babel/core": "7.7.7", + "@babel/generator": "7.7.7", + "@babel/preset-env": "7.7.7", + "@ngtools/webpack": "9.0.1", + "ajv": "6.10.2", + "autoprefixer": "9.7.1", + "babel-loader": "8.0.6", + "browserslist": "4.8.3", + "cacache": "13.0.1", + "caniuse-lite": "1.0.30001020", + "circular-dependency-plugin": "5.2.0", + "copy-webpack-plugin": "5.1.1", + "core-js": "3.6.0", + "coverage-istanbul-loader": "2.0.3", + "cssnano": "4.1.10", + "file-loader": "4.2.0", + "find-cache-dir": "3.0.0", + "glob": "7.1.5", + "jest-worker": "24.9.0", + "karma-source-map-support": "1.4.0", + "less": "3.10.3", + "less-loader": "5.0.0", + "license-webpack-plugin": "2.1.3", + "loader-utils": "1.2.3", + "magic-string": "0.25.4", + "mini-css-extract-plugin": "0.8.0", + "minimatch": "3.0.4", + "open": "7.0.0", + "parse5": "4.0.0", + "postcss": "7.0.21", + "postcss-import": "12.0.1", + "postcss-loader": "3.0.0", + "raw-loader": "3.1.0", + "regenerator-runtime": "0.13.3", + "rimraf": "3.0.0", + "rollup": "1.25.2", + "rxjs": "6.5.3", + "sass": "1.23.3", + "sass-loader": "8.0.0", + "semver": "6.3.0", + "source-map": "0.7.3", + "source-map-loader": "0.2.4", + "source-map-support": "0.5.16", + "speed-measure-webpack-plugin": "1.3.1", + "style-loader": "1.0.0", + "stylus": "0.54.7", + "stylus-loader": "3.0.2", + "terser": "4.5.1", + "terser-webpack-plugin": "2.3.3", + "tree-kill": "1.2.2", + "webpack": "4.41.2", + "webpack-dev-middleware": "3.7.2", + "webpack-dev-server": "3.9.0", + "webpack-merge": "4.2.2", + "webpack-sources": "1.4.3", + "webpack-subresource-integrity": "1.3.4", + "worker-plugin": "3.2.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "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=", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "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" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "glob": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", + "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", + "dev": true, + "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" + } + }, + "magic-string": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz", + "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "minipass": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@angular-devkit/build-optimizer": { + "version": "0.900.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.900.1.tgz", + "integrity": "sha512-EnIU+ogiJrUPf8+fuPE5xQ+j/qUZDZ/SmLs8XAOmvoOBpZ0vPNedrHBHCxmV+ACbCxHGmIKQ/ZL29XUYVasteg==", + "dev": true, + "requires": { + "loader-utils": "1.2.3", + "source-map": "0.7.3", + "tslib": "1.10.0", + "typescript": "3.6.4", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "typescript": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", + "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", + "dev": true + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.900.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.900.1.tgz", + "integrity": "sha512-GwV+jht42S2XZZbvy07mXqZ5us9ppbIi/gCL5SiUh+xtSdZGbfE6RoFZXmeOuxBn9FY0vUMTFtKCK5Mx8O3WYg==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.900.1", + "@angular-devkit/core": "9.0.1", + "rxjs": "6.5.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/core": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.0.1.tgz", + "integrity": "sha512-HboJI/x+SJD9clSOAMjHRv0eXAGRAdEaqJGmjDfdFMP2wznfsBiC6cgcHC17oM4jRWFhmWMR8Omc7CjLZJawJg==", + "dev": true, + "requires": { + "ajv": "6.10.2", + "fast-json-stable-stringify": "2.0.0", + "magic-string": "0.25.4", + "rxjs": "6.5.3", + "source-map": "0.7.3" + }, + "dependencies": { + "magic-string": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz", + "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/schematics": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-9.0.1.tgz", + "integrity": "sha512-Cuub9eJm1TWygKTOowRbxMASA8QWeHWzNEU2V3TqUF1Tqy/iPf4cpuMijkFysXjTn2bi2HA9t26AwQkwymbliA==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.1", + "ora": "4.0.2", + "rxjs": "6.5.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular/animations": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.0.0.tgz", + "integrity": "sha512-jB8+SC3vMztW5zt5UYVmtVwqIWE33UyEjbP5JPba3I3bLRK5E059LcJmN1rSdJHItgIAdG9Y1I0WJ6aiSFyp4Q==" + }, + "@angular/cdk": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-9.0.0.tgz", + "integrity": "sha512-2kYpyYbewIB6fubSIDMvSprJLNplRZoL/AtXW3od4dLyRxtzX+7iWTAtzUG/dhq8CKev0lpd1HENh5lLR/Lhjw==", + "requires": { + "parse5": "^5.0.0" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + } + } + }, + "@angular/cli": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-9.0.1.tgz", + "integrity": "sha512-/nykTIqZq1plxaXVoMzAqjnExGhkYoSoq88AE4Mb31d6n/SW2DFh62C3hze+atI6YLqeFaPhYuA5zG+z3oOXbQ==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.900.1", + "@angular-devkit/core": "9.0.1", + "@angular-devkit/schematics": "9.0.1", + "@schematics/angular": "9.0.1", + "@schematics/update": "0.900.1", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.1", + "debug": "^4.1.1", + "ini": "1.3.5", + "inquirer": "7.0.0", + "npm-package-arg": "6.1.1", + "npm-pick-manifest": "3.0.2", + "open": "7.0.0", + "pacote": "9.5.8", + "read-package-tree": "5.3.1", + "rimraf": "3.0.0", + "semver": "6.3.0", + "symbol-observable": "1.2.0", + "universal-analytics": "^0.4.20", + "uuid": "^3.3.2" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "is-wsl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "open": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.0.0.tgz", + "integrity": "sha512-K6EKzYqnwQzk+/dzJAQSBORub3xlBTxMz+ntpZpH/LyCa1o6KjXhuN+2npAaI9jaSmU3R1Q8NWf4KUWcyytGsQ==", + "dev": true, + "requires": { + "is-wsl": "^2.1.0" + } + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "@angular/common": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.0.0.tgz", + "integrity": "sha512-ZMmEClGtUNJwV5CBlqcSHPIsNyz6WU/GvKWFzJ5VZc68oeg1e7lqfNMNIC47TjyolNJ7VSpNlyrKjzfdBlmqVw==" + }, + "@angular/compiler": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", + "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==" + }, + "@angular/compiler-cli": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.0.0.tgz", + "integrity": "sha512-6L3swd3Z2ceAapmioml6z7yu3bYC2aVm3/rgK7eCoZtPcevuvTpGnXcFSVvNgByV51GntgInThPbMx0xY23Rvw==", + "dev": true, + "requires": { + "canonical-path": "1.0.0", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.7.2", + "fs-extra": "4.0.2", + "magic-string": "^0.25.0", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "semver": "^6.3.0", + "source-map": "^0.6.1", + "yargs": "13.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==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "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==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "yargs": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.1.0.tgz", + "integrity": "sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "@angular/core": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", + "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==" + }, + "@angular/forms": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.0.0.tgz", + "integrity": "sha512-SIYJc0Rgaihow1t+iiwSFGEvvRgssgUuxwIYbMfCp1Sx513K+JX9nVFXqU+dcGj/eF1u5wwYwbvlVyuMQLzmXg==" + }, + "@angular/language-service": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-9.0.0.tgz", + "integrity": "sha512-tOMtXY8DFpTWMF77BOTXZmMMtqvdy6fbyOkJSccn6VatcPrNXOs5rKur+KNwdSlK+djjss6Y+LA8fQAvjNvUqw==", + "dev": true + }, + "@angular/material": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-9.0.0.tgz", + "integrity": "sha512-QxN2rmR5mvg2YE1NoIGWLpbnmcJq0iFidzy6odzvN17+XkoCJBZ65IdYsHrJgfwGpoIy6bywuixrDHHcSh9I5w==" + }, + "@angular/platform-browser": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.0.0.tgz", + "integrity": "sha512-2PR/o57HjZvKEnAF8ODeqxmeC90oth9dLTMrJNoI5MET0IeErKeI/9Sl5cLQuXC+lSVN5rOMCvDb74VWSno5yw==" + }, + "@angular/platform-browser-dynamic": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.0.0.tgz", + "integrity": "sha512-F1kbEpmDottTemRPEOAz2Te5ABVJ7wypfzBllxqXbdxPHvYLfL8db2dXyiGqABQ3ZFHPLNilrkUTy0sbuuU4OA==" + }, + "@angular/pwa": { + "version": "0.803.25", + "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-0.803.25.tgz", + "integrity": "sha512-ZWNXDEAkewyLOAb9/zr5zf3NFe8m2yGdI1pGAVqssCIJFG65V+fNdlwkVNAYc6MGOjOXo3tK8v9+/Cm8MOP8yQ==", + "requires": { + "@angular-devkit/core": "8.3.25", + "@angular-devkit/schematics": "8.3.25", + "@schematics/angular": "8.3.25", + "parse5-html-rewriting-stream": "5.1.0" + }, + "dependencies": { + "@angular-devkit/core": { + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.25.tgz", + "integrity": "sha512-l7Gqy1tMrTpRmPVlovcFX8UA3mtXRlgO8kcSsbJ9MKRKNTCcxlfsWEYY5igyDBUVh6ADkgSIu0nuk31ZGTe0lw==", + "requires": { + "ajv": "6.10.2", + "fast-json-stable-stringify": "2.0.0", + "magic-string": "0.25.3", + "rxjs": "6.4.0", + "source-map": "0.7.3" + } + }, + "@angular-devkit/schematics": { + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.25.tgz", + "integrity": "sha512-/p1MkfursfLy+JRGXlJGPEmX55lrFCsR/2khWAVXZcMaFR3QlR/b6/zvB8I2pHFfr0/XWnYTT/BsF7rJjO3RmA==", + "requires": { + "@angular-devkit/core": "8.3.25", + "rxjs": "6.4.0" + } + }, + "@schematics/angular": { + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.25.tgz", + "integrity": "sha512-/vEPtE+fvgsWPml/MVqzmlGPBujadPPNwaTuuj5Uz1aVcKeEYzLkbN8YQOpml4vxZHCF8RDwNdGiU4SZg63Jfg==", + "requires": { + "@angular-devkit/core": "8.3.25", + "@angular-devkit/schematics": "8.3.25" + } + }, + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular/router": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.0.0.tgz", + "integrity": "sha512-yyOcStpgN5t8wGRNO85mo0jplXkntP+v2tmSxNx45pahqmofSFm+QCEFa2zHQuMr7NoiGERhd0Tae7NDCCjtjA==" + }, + "@angular/service-worker": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-9.0.0.tgz", + "integrity": "sha512-QZjA9Syhz3sCcugUknXorScgSjVS6jhaCZilTmfPPaKazw0tASNw1SfjrZ60aOPCmoJGRkWyP/Hzzi/KKVSQjQ==" + }, + "@aws-amplify/analytics": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-1.4.3.tgz", + "integrity": "sha512-rgZwbNNPOqhQCGWy2qTT+wyLMveqXuQbZXVa7IRmRHMuuuZiCcI+QLNI+9Yg9CmYg6ISVYSSwYx06gGP5B6N0A==", + "requires": { + "@aws-amplify/cache": "^1.2.3", + "@aws-amplify/core": "^1.3.3", + "uuid": "^3.2.1" + } + }, + "@aws-amplify/api": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/api/-/api-1.3.3.tgz", + "integrity": "sha512-d0+x+DzUoDzjdSL3v0d2GglFqApC7c8qgGPXW1SySKZU53byCEJ/ipNBAdjh46BDxx+l0pWaz55OwvTnYMQs9w==", + "requires": { + "@aws-amplify/auth": "^1.6.3", + "@aws-amplify/cache": "^1.2.3", + "@aws-amplify/core": "^1.3.3", + "@types/zen-observable": "^0.5.3", + "axios": "^0.19.0", + "graphql": "14.0.0", + "uuid": "^3.2.1", + "zen-observable": "^0.8.6" + } + }, + "@aws-amplify/auth": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/auth/-/auth-1.6.3.tgz", + "integrity": "sha512-yJEknYhBo9/Uc9/am6kPOoN9ybjrS+cvJzHpYsNnqACjD20cF1lTWALXcgvs0WNylQ8o6PfHcUe5uymyadyXSg==", + "requires": { + "@aws-amplify/cache": "^1.2.3", + "@aws-amplify/core": "^1.3.3", + "amazon-cognito-identity-js": "^3.3.3", + "crypto-js": "^3.1.9-1" + } + }, + "@aws-amplify/cache": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/cache/-/cache-1.2.3.tgz", + "integrity": "sha512-kd4IrBUM+fhZlx2mzO7SvU07lEtnopV2zEXUUxyAHoP98DInSTlTJSg4mIbeaBqaVS0Ltmt39UJkJJMgLrXRyQ==", + "requires": { + "@aws-amplify/core": "^1.3.3" + } + }, + "@aws-amplify/core": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/core/-/core-1.3.3.tgz", + "integrity": "sha512-NyJii+PvZ1Sb1j7w1XWJpRr9nDjB60bjb+FspCRAWjdwlxgVgpCQdhXE4F4teUtLUd22Po2boxLkyhKnuI0jwg==", + "requires": { + "aws-sdk": "2.518.0", + "url": "^0.11.0" + } + }, + "@aws-amplify/interactions": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/interactions/-/interactions-1.2.3.tgz", + "integrity": "sha512-71WRgKv4+LF8Di4V9LM4Xc6Ef4PtmAEp2BGN7dlK+vRWTrdcVFM4aJD5h6A36HEbORb9OMCVbLOdwvs+6I7KgA==", + "requires": { + "@aws-amplify/core": "^1.3.3" + } + }, + "@aws-amplify/predictions": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/predictions/-/predictions-1.2.3.tgz", + "integrity": "sha512-w1f7w9MJywwGzDkhznRow9txPtDIKqLMFEpweJp0sq9sM/ARzWv+ssLD7PaOF1VtlWAp1iusT91D1w4dqbb7Iw==", + "requires": { + "@aws-amplify/core": "^1.3.3", + "@aws-amplify/storage": "^1.3.3", + "@aws-sdk/eventstream-marshaller": "0.1.0-preview.2", + "@aws-sdk/util-utf8-node": "0.1.0-preview.1", + "uuid": "^3.2.1" + } + }, + "@aws-amplify/pubsub": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/pubsub/-/pubsub-1.3.3.tgz", + "integrity": "sha512-xdKWhhNFFUDrZ8d8RbLrpXW5vwbTolH1vVz5ulIr5gghV7I/+KquNSebCF9g3maA1MwjSAvWViwgt2yHH2Sj4Q==", + "requires": { + "@aws-amplify/core": "^1.3.3", + "@types/zen-observable": "^0.5.3", + "paho-mqtt": "^1.1.0", + "uuid": "^3.2.1", + "zen-observable": "^0.8.6" + } + }, + "@aws-amplify/storage": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/storage/-/storage-1.3.3.tgz", + "integrity": "sha512-CZO76XYA538U+wSS7IoNQkhP5qgfjIXawc011yigSVbN5+g7Bky5+fY6++XOA9+v3rATYq1wWkbhyro6tss3oA==", + "requires": { + "@aws-amplify/core": "^1.3.3" + } + }, + "@aws-amplify/ui": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/ui/-/ui-1.2.3.tgz", + "integrity": "sha512-ZsNMkthkLfax/OngdlWFdJEjqXuRqXa5iwb4uKoGu58PTp6AnaM6nFkwPTGCLU4ilPicSXqZPIHCJ9K6MBlzHQ==" + }, + "@aws-amplify/xr": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@aws-amplify/xr/-/xr-0.3.3.tgz", + "integrity": "sha512-RzyopwtcWOi0RuJsc8QNhxXR729IakUaFxydYsgNweDrPKXtjbTJpXZSyIJ/BE095U5Z7QsCbFKqspmh7I9AnQ==", + "requires": { + "@aws-amplify/core": "^1.3.3" + } + }, + "@aws-crypto/crc32": { + "version": "0.1.0-preview.4", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-0.1.0-preview.4.tgz", + "integrity": "sha512-Faxpmo6pUPvfwE8ELdJo9K9bdIjsra+AM2Cq2Fvydd4xJRHpKLWzQ3kdz324auMkHKbn4veTDo3sZRuSbh/Pug==", + "requires": { + "tslib": "^1.9.3" + } + }, + "@aws-sdk/eventstream-marshaller": { + "version": "0.1.0-preview.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-marshaller/-/eventstream-marshaller-0.1.0-preview.2.tgz", + "integrity": "sha512-StNivqLMGk+6Blp7eBYgLvidD9HEhthzNz7dBBAQPELx3Nd3imodzSvckDw5ZkuWt6ViP+aAl8HgQvJmD71M5Q==", + "requires": { + "@aws-crypto/crc32": "^0.1.0-preview.1", + "@aws-sdk/types": "^0.1.0-preview.1", + "@aws-sdk/util-hex-encoding": "^0.1.0-preview.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/is-array-buffer": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-0.1.0-preview.1.tgz", + "integrity": "sha512-9Qrr9w6sNX19N0eO7JBYjp86OPcOyjDPe580L5ISDKo7XfuzK20IC2TeGTZ77okhRTsm8rF5UgP9scBu59jwoA==", + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/types": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-0.1.0-preview.1.tgz", + "integrity": "sha512-CcZpxyN2G0I7+Jyj0om3LafYX7d30JWJAAQ+53Ysjau7jyL/xLMMkLZgniQPV8BMV7uKLXyf4hwu8JSs0Ejb+w==" + }, + "@aws-sdk/util-buffer-from": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-0.1.0-preview.1.tgz", + "integrity": "sha512-i46iuFQA05+92L/epK7befgoxw6DM38LnaHjHNxRoJeIYUllZvpJst74FRCJ5UvVOaMDvHO3woWG+dY8/KVABw==", + "requires": { + "@aws-sdk/is-array-buffer": "^0.1.0-preview.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/util-hex-encoding": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-0.1.0-preview.1.tgz", + "integrity": "sha512-97ZMVcJpIXwOQN2RntPimav6G5iod/QHEbqGrmaECXyjXzSrexKHRYjpQAtmJ7geZTMsofoRSdj3qZCymjn7Uw==", + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/util-utf8-node": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-node/-/util-utf8-node-0.1.0-preview.1.tgz", + "integrity": "sha512-PSUsSJ0nnMPS389f0R3kIVR0BElnEb22Ofj40iO5HCtw9gZ1ot+enFdbOmW4m1e5+ED9U/Hqxqc7QhFWWF4NUQ==", + "requires": { + "@aws-sdk/util-buffer-from": "^0.1.0-preview.1", + "tslib": "^1.8.0" + } + }, + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.7.tgz", + "integrity": "sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.7", + "@babel/helpers": "^7.7.4", + "@babel/parser": "^7.7.7", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + } + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + } + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", + "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "dev": true, + "requires": { + "@babel/types": "^7.6.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", + "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", + "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-call-delegate": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz", + "integrity": "sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", + "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", + "dev": true, + "requires": { + "@babel/helper-regex": "^7.8.3", + "regexpu-core": "^4.6.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "regjsparser": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz", + "integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "@babel/helper-define-map": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", + "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/types": "^7.8.3", + "lodash": "^4.17.13" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.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==", + "dev": true + } + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", + "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", + "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-module-imports": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-module-transforms": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz", + "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-simple-access": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3", + "lodash": "^4.17.13" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.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==", + "dev": true + } + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", + "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", + "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-wrap-function": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-replace-supers": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", + "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-simple-access": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.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==", + "dev": true + } + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", + "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helpers": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", + "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } + } + }, + "@babel/parser": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", + "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", + "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", + "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", + "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz", + "integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz", + "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", + "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", + "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", + "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", + "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz", + "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-define-map": "^7.8.3", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "globals": "^11.1.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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.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==", + "dev": true + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", + "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz", + "integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", + "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", + "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", + "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz", + "integrity": "sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", + "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.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==", + "dev": true + } + } + }, + "@babel/plugin-transform-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", + "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", + "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz", + "integrity": "sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz", + "integrity": "sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-simple-access": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz", + "integrity": "sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz", + "integrity": "sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", + "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", + "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", + "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz", + "integrity": "sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.8.3", + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", + "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz", + "integrity": "sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", + "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", + "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", + "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", + "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-regex": "^7.8.3" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", + "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", + "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", + "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/preset-env": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.7.tgz", + "integrity": "sha512-pCu0hrSSDVI7kCVUOdcMNQEbOPJ52E+LrQ14sN8uL2ALfSqePZQlKrOy+tM4uhEdYlCHi4imr8Zz2cZe9oSdIg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.7.4", + "@babel/plugin-proposal-dynamic-import": "^7.7.4", + "@babel/plugin-proposal-json-strings": "^7.7.4", + "@babel/plugin-proposal-object-rest-spread": "^7.7.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.7.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.7.7", + "@babel/plugin-syntax-async-generators": "^7.7.4", + "@babel/plugin-syntax-dynamic-import": "^7.7.4", + "@babel/plugin-syntax-json-strings": "^7.7.4", + "@babel/plugin-syntax-object-rest-spread": "^7.7.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.7.4", + "@babel/plugin-syntax-top-level-await": "^7.7.4", + "@babel/plugin-transform-arrow-functions": "^7.7.4", + "@babel/plugin-transform-async-to-generator": "^7.7.4", + "@babel/plugin-transform-block-scoped-functions": "^7.7.4", + "@babel/plugin-transform-block-scoping": "^7.7.4", + "@babel/plugin-transform-classes": "^7.7.4", + "@babel/plugin-transform-computed-properties": "^7.7.4", + "@babel/plugin-transform-destructuring": "^7.7.4", + "@babel/plugin-transform-dotall-regex": "^7.7.7", + "@babel/plugin-transform-duplicate-keys": "^7.7.4", + "@babel/plugin-transform-exponentiation-operator": "^7.7.4", + "@babel/plugin-transform-for-of": "^7.7.4", + "@babel/plugin-transform-function-name": "^7.7.4", + "@babel/plugin-transform-literals": "^7.7.4", + "@babel/plugin-transform-member-expression-literals": "^7.7.4", + "@babel/plugin-transform-modules-amd": "^7.7.5", + "@babel/plugin-transform-modules-commonjs": "^7.7.5", + "@babel/plugin-transform-modules-systemjs": "^7.7.4", + "@babel/plugin-transform-modules-umd": "^7.7.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4", + "@babel/plugin-transform-new-target": "^7.7.4", + "@babel/plugin-transform-object-super": "^7.7.4", + "@babel/plugin-transform-parameters": "^7.7.7", + "@babel/plugin-transform-property-literals": "^7.7.4", + "@babel/plugin-transform-regenerator": "^7.7.5", + "@babel/plugin-transform-reserved-words": "^7.7.4", + "@babel/plugin-transform-shorthand-properties": "^7.7.4", + "@babel/plugin-transform-spread": "^7.7.4", + "@babel/plugin-transform-sticky-regex": "^7.7.4", + "@babel/plugin-transform-template-literals": "^7.7.4", + "@babel/plugin-transform-typeof-symbol": "^7.7.4", + "@babel/plugin-transform-unicode-regex": "^7.7.4", + "@babel/types": "^7.7.4", + "browserslist": "^4.6.0", + "core-js-compat": "^3.6.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/template": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" + } + }, + "@babel/traverse": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", + "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.3", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.3", + "@babel/types": "^7.6.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "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=", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, + "@ngtools/webpack": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.0.1.tgz", + "integrity": "sha512-SG1MDVSC7pIuaX1QYTh94k/YJa6w2OR2RNbghkDXToDzDv6bKnTQYoJPyXk+gwfDTVD4V5z2dKSNbxFzWleFpg==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.1", + "enhanced-resolve": "4.1.1", + "rxjs": "6.5.3", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@schematics/angular": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-9.0.1.tgz", + "integrity": "sha512-lQ8Qc697ef2jvEf1+tElAUsbOnbUAMo3dnOUVw9RlYO90pHeG3/OdWBMH1kjn3jbjuKuvCVZH3voJUUcLDx6eg==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.1", + "@angular-devkit/schematics": "9.0.1" + } + }, + "@schematics/update": { + "version": "0.900.1", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.900.1.tgz", + "integrity": "sha512-p2xfctTtT5kMAaCTBENxi69m5IhsvdTwwwokb9zVHJYAC6D1K//q1bl30mTe6U2YE3hSPWND2S14ahXw8PyN8g==", + "dev": true, + "requires": { + "@angular-devkit/core": "9.0.1", + "@angular-devkit/schematics": "9.0.1", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "npm-package-arg": "^7.0.0", + "pacote": "9.5.8", + "rxjs": "6.5.3", + "semver": "6.3.0", + "semver-intersect": "1.4.0" + }, + "dependencies": { + "npm-package-arg": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz", + "integrity": "sha512-xXxr8y5U0kl8dVkz2oK7yZjPBvqM2fwaO5l3Yg13p03v8+E3qQcD0JNhHzjL1vyGgxcKkD0cco+NLR72iuPk3g==", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.2", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@types/estree": { + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.42.tgz", + "integrity": "sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.3.16.tgz", + "integrity": "sha512-Nveep4zKGby8uIvG2AEUyYOwZS8uVeHK9TgbuWYSawUDDdIgfhCKz28QzamTo//Jk7Ztt9PO3f+vzlB6a4GV1Q==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.8.tgz", + "integrity": "sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg==", + "dev": true, + "requires": { + "@types/jasmine": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz", + "integrity": "sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz", + "integrity": "sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==", + "dev": true + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/webpack-sources": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.6.tgz", + "integrity": "sha512-FtAWR7wR5ocJ9+nP137DV81tveD/ZgB1sadnJ/axUGM3BUVfRPx8oQNMtv3JNfTeHx3VP7cXiyfR/jmtEsVHsQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/zen-observable": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.5.4.tgz", + "integrity": "sha512-sW6xN96wUak4tgc89d0tbTg7QDGYhGv5hvQIS6h4mRCd8h2btiZ80loPU8cyLwsBbA4ZeQt0FjvUhJ4rNhdsGg==" + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true + }, + "@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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "@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==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "adm-zip": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz", + "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.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==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amazon-cognito-identity-js": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-3.3.3.tgz", + "integrity": "sha512-uB1Bk2ezxVUz0vELZ4tI40ZJEYEZZcWdz8TVyNOPjQCKS+SszNUORTkOkL0KgawZMak7KhDfLTEXbInBeTsiow==", + "requires": { + "buffer": "4.9.1", + "crypto-js": "^3.1.9-1", + "js-cookie": "^2.1.4" + } + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "app-root-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz", + "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==", + "dev": true + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "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=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "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==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "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=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "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=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "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=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "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=", + "dev": true + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.1.tgz", + "integrity": "sha512-w3b5y1PXWlhYulevrTJ0lizkQ5CyqfeU6BIRDbuhsMupstHQOeb1Ur80tcB1zxSu7AwyY/qCQ7Vvqklh31ZBFw==", + "dev": true, + "requires": { + "browserslist": "^4.7.2", + "caniuse-lite": "^1.0.30001006", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.21", + "postcss-value-parser": "^4.0.2" + } + }, + "aws-amplify": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/aws-amplify/-/aws-amplify-1.3.3.tgz", + "integrity": "sha512-CKryRZMyqNsxlYpIaiT1YkW3LzOVkCYYCcEWlz8v8+q4CwchDM1eycMfaJBqkQYqE3tUzavPZEXgxylCSL2bNQ==", + "requires": { + "@aws-amplify/analytics": "^1.4.3", + "@aws-amplify/api": "^1.3.3", + "@aws-amplify/auth": "^1.6.3", + "@aws-amplify/cache": "^1.2.3", + "@aws-amplify/core": "^1.3.3", + "@aws-amplify/interactions": "^1.2.3", + "@aws-amplify/predictions": "^1.2.3", + "@aws-amplify/pubsub": "^1.3.3", + "@aws-amplify/storage": "^1.3.3", + "@aws-amplify/ui": "^1.2.3", + "@aws-amplify/xr": "^0.3.3" + } + }, + "aws-sdk": { + "version": "2.518.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.518.0.tgz", + "integrity": "sha512-hwtKKf93TFyd3qugDW54ElpkUXhPe+ArPIHadre6IAFjCJiv08L8DaZKLRyclDnKfTavKe+f/PhdSEYo1QUHiA==", + "requires": { + "buffer": "4.9.1", + "events": "1.1.1", + "ieee754": "1.1.8", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "dependencies": { + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + } + } + }, + "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=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + } + } + }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, + "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=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-loader": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "pify": "^4.0.1" + }, + "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==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "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=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "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==" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "bluebird": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.0.tgz", + "integrity": "sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "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==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "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=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.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==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.3.tgz", + "integrity": "sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001017", + "electron-to-chromium": "^1.3.322", + "node-releases": "^1.1.44" + } + }, + "browserstack": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", + "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "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=", + "dev": true + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.2.tgz", + "integrity": "sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==", + "dev": true, + "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" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "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" + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "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=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "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==", + "dev": true, + "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.30001020", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001020.tgz", + "integrity": "sha512-yWIvwA68wRHKanAVS1GjN8vajAv7MBFshullKCeq/eKpK7pJBVDgFFEqvgWTkcP2+wIDeQGYFRXECjKZnLkUjA==", + "dev": true + }, + "canonical-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", + "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "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==", + "dev": true + }, + "chart.js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz", + "integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==", + "requires": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + }, + "chartjs-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "requires": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^1.9.3" + } + }, + "chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "requires": { + "color-name": "^1.0.0" + } + }, + "chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "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==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-dependency-plugin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz", + "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.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==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", + "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==", + "dev": true + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.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=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "dependencies": { + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "codelyzer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.1.tgz", + "integrity": "sha512-awBZXFcJUyC5HMYXiHzjr3D24tww2l1D1OqtfA9vUhEtYr32a65A+Gblm/OvsO+HuKLYzn8EDMw1inSM3VbxWA==", + "dev": true, + "requires": { + "app-root-path": "^2.2.1", + "aria-query": "^3.0.0", + "axobject-query": "2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "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==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "compare-versions": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", + "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "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==", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + }, + "dependencies": { + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true + } + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "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" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + } + }, + "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==", + "dev": true + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==", + "dev": true, + "requires": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "cacache": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "dev": true, + "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" + } + }, + "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==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + } + } + }, + "core-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.0.tgz", + "integrity": "sha512-AHPTNKzyB+YwgDWoSOCaid9PUSEF6781vsfiK8qUz62zRR448/XgK2NtCbpiUGizbep8Lrpt0Du19PpGGZvw3Q==", + "dev": true + }, + "core-js-compat": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", + "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", + "dev": true, + "requires": { + "browserslist": "^4.8.3", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "coverage-istanbul-loader": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz", + "integrity": "sha512-LiGRvyIuzVYs3M1ZYK1tF0HekjH0DJ8zFdUwAZq378EJzqOgToyb1690dp3TAUlP6Y+82uu42LRjuROVeJ54CA==", + "dev": true, + "requires": { + "convert-source-map": "^1.7.0", + "istanbul-lib-instrument": "^4.0.0", + "loader-utils": "^1.2.3", + "merge-source-map": "^1.1.0", + "schema-utils": "^2.6.1" + }, + "dependencies": { + "schema-utils": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", + "dev": true, + "requires": { + "css": "^2.0.0" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "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==", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-unit-converter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", + "dev": true + }, + "css-what": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==", + "dev": true + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "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==", + "dev": true, + "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=", + "dev": true + }, + "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=", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "csso": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.2.tgz", + "integrity": "sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg==", + "dev": true, + "requires": { + "css-tree": "1.0.0-alpha.37" + } + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d3": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.15.0.tgz", + "integrity": "sha512-C+E80SL2nLLtmykZ6klwYj5rPqB5nlfN5LdWEAVdWPppqTD8taoJi2PxLZjPeYT8FFRR2yucXq+kBlOnnvZeLg==", + "requires": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" + } + }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "d3-axis": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", + "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==" + }, + "d3-brush": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.5.tgz", + "integrity": "sha512-rEaJ5gHlgLxXugWjIkolTA0OyMvw8UWU1imYXy1v642XyyswmI1ybKOv05Ft+ewq+TFmdliD3VuK0pRp1VT/5A==", + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "d3-chord": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", + "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", + "requires": { + "d3-array": "1", + "d3-path": "1" + } + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "d3-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz", + "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg==" + }, + "d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "requires": { + "d3-array": "^1.1.1" + } + }, + "d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" + }, + "d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "requires": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "d3-dsv": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", + "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + } + }, + "d3-ease": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.6.tgz", + "integrity": "sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ==" + }, + "d3-fetch": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz", + "integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==", + "requires": { + "d3-dsv": "1" + } + }, + "d3-force": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", + "requires": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "d3-format": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.3.tgz", + "integrity": "sha512-mm/nE2Y9HgGyjP+rKIekeITVgBtX97o1nrvHCWX8F/yBYyevUTvu9vb5pUnKwrcSw7o7GuwMOWjS9gFDs4O+uQ==" + }, + "d3-geo": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.9.tgz", + "integrity": "sha512-9edcH6J3s/Aa3KJITWqFJbyB/8q3mMlA9Fi7z6yy+FAYMnRaxmC7jBhUnsINxVWD14GmqX3DK8uk7nV6/Ekt4A==", + "requires": { + "d3-array": "1" + } + }, + "d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==" + }, + "d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "d3-polygon": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz", + "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==" + }, + "d3-quadtree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", + "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==" + }, + "d3-random": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz", + "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==" + }, + "d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", + "requires": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, + "d3-selection": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.1.tgz", + "integrity": "sha512-BTIbRjv/m5rcVTfBs4AMBLKs4x8XaaLkwm28KWu9S2vKNqXkXt2AH2Qf0sdPZHjFxcWg/YL53zcqAz+3g4/7PA==" + }, + "d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "requires": { + "d3-path": "1" + } + }, + "d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" + }, + "d3-time-format": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.3.tgz", + "integrity": "sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA==", + "requires": { + "d3-time": "1" + } + }, + "d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + }, + "d3-transition": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", + "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", + "requires": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" + } + }, + "d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" + }, + "d3-zoom": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", + "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "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=", + "dev": true + }, + "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==", + "dev": true, + "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" + } + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + } + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "dev": true + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "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=", + "dev": true + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "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=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true + } + } + }, + "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==", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "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=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.346", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.346.tgz", + "integrity": "sha512-Yy4jF5hJd57BWmGPt0KjaXc25AmWZeQK75kdr4zIzksWVtiT6DwaNtvTb9dt+LkQKwUpvBfCyyPsXXtbY/5GYw==", + "dev": true + }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "dev": true, + "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" + } + }, + "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==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "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==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "enhanced-resolve": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "dev": true + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "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==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, + "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==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "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=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, + "events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "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==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "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=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "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": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "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=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-loader": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.2.0.tgz", + "integrity": "sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "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==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "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" + } + }, + "find-cache-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.0.0.tgz", + "integrity": "sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "dev": true, + "requires": { + "semver": "^6.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==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "find-up": "^4.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==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "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=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.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=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "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=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "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": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": 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=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "graphql": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.0.tgz", + "integrity": "sha512-HGVcnO6B25YZcSt6ZsH6/N+XkYuPA7yMqJmlJ4JWxWlS4Tr8SHI56R1Ocs8Eor7V7joEZPRXPDH8RRdll1w44Q==", + "requires": { + "iterall": "^1.2.2" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", + "dev": true + }, + "handlebars": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.2.tgz", + "integrity": "sha512-4PwqDL2laXtTWZghzzCtunQUTLbo31pcCJrd/B/9JP8XbhVzpS5ZXuKqlOzsd1rtcaLo4KqAn8nl8mkknS4MHw==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "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=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "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==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.2.tgz", + "integrity": "sha512-ezZMWtHXm7Eb7Rq4Mwnx2vs79WUx2QmRg3+ZqeGroKzfDO+EprOcgRPYghsOP9JuYBfK18VojmRTGCg8Ma+ktw==", + "dev": true, + "requires": { + "lru-cache": "^5.1.1" + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.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=", + "dev": true + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "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==", + "dev": true + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "dev": true + }, + "http-proxy": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.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==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.3.tgz", + "integrity": "sha512-Ytgnz23gm2DVftnzqRRz2dOXZbGd2uiajSw/95bPp6v53zPRspQjLm/AfBgqbJ2qfeRXWIOMVLpp86+/5yX39Q==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "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==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "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==", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "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==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "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==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", + "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "dev": true, + "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.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "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==", + "dev": true + } + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", + "dev": true + }, + "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=", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "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=", + "dev": true, + "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-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "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==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "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=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "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==", + "dev": true + }, + "is-wsl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.6.tgz", + "integrity": "sha512-x0Eicp6KsShG1k1rMgBAi/1GgY7kFGEBwQpw3PXGEmu+rBcBNhqU8g2DgY9mlepAsLPzrzrbqSgCGANnki4POA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "compare-versions": "^3.4.0", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "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==", + "dev": true + }, + "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==", + "dev": true, + "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-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "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==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "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==", + "dev": true, + "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": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "iterall": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", + "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" + }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "requires": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "dependencies": { + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.4.0.tgz", + "integrity": "sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", + "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "dev": true, + "requires": { + "colors": "1.1.2" + } + }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "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==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "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=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "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-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=", + "dev": true + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jszip": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.2.tgz", + "integrity": "sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "karma": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-4.1.0.tgz", + "integrity": "sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw==", + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "braces": "^2.3.2", + "chokidar": "^2.0.3", + "colors": "^1.1.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.11", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.3.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": 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" + } + }, + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "dev": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "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" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "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=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "dev": true, + "requires": { + "fs-access": "^1.0.0", + "which": "^1.2.1" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.6.tgz", + "integrity": "sha512-WFh77RI8bMIKdOvI/1/IBmgnM+Q7NOLhnwG91QJrM8lW+CIXCjTzhhUsT/svLvAkLmR10uWY4RyYbHMLkTglvg==", + "dev": true, + "requires": { + "istanbul-api": "^2.1.6", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", + "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", + "dev": true, + "requires": { + "jasmine-core": "^3.3" + } + }, + "karma-jasmine-html-reporter": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.2.tgz", + "integrity": "sha512-ILBPsXqQ3eomq+oaQsM311/jxsypw5/d0LnZXj26XkfThwq7jZ55A2CFSKJVA5VekbbOGvMyv7d3juZj0SeTxA==", + "dev": true + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "less": { + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz", + "integrity": "sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow==", + "dev": true, + "requires": { + "clone": "^2.1.2", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.0", + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz", + "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^4.0.1" + } + }, + "license-webpack-plugin": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.3.tgz", + "integrity": "sha512-vTSY5r9HOq4sxR2BIxdIXWKI+9n3b+DoQkhKHedB3TdSxTfXUDRxKXdAj5iejR+qNXprXsxvEu9W+zOhgGIkAw==", + "dev": true, + "requires": { + "@types/webpack-sources": "^0.1.5", + "webpack-sources": "^1.2.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "log4js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "dev": true, + "requires": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.4", + "streamroller": "^1.0.6" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "loglevel": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz", + "integrity": "sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.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==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz", + "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==", + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "make-fetch-happen": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "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==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz", + "integrity": "sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.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==", + "dev": true + }, + "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=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.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==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "minipass-pipeline": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz", + "integrity": "sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "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=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "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" + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-forge": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.48", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.48.tgz", + "integrity": "sha512-Hr8BbmUl1ujAST0K0snItzEA5zkJTQup8VNTKNfT6Zw8vTJkIiagUPNfxHmgDOyfFYNfKAul40sD0UEYTvwebw==", + "dev": true, + "requires": { + "semver": "^6.3.0" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "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==", + "dev": true + }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "dev": true, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "npm-registry-fetch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz", + "integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } + } + }, + "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=", + "dev": true, + "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==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "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==", + "dev": true, + "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=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "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==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.0.0.tgz", + "integrity": "sha512-K6EKzYqnwQzk+/dzJAQSBORub3xlBTxMz+ntpZpH/LyCa1o6KjXhuN+2npAaI9jaSmU3R1Q8NWf4KUWcyytGsQ==", + "dev": true, + "requires": { + "is-wsl": "^2.1.0" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + } + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "ora": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ora/-/ora-4.0.2.tgz", + "integrity": "sha512-YUOZbamht5mfLxPmk4M35CD/5DuOkAacxlEUbStVXpBAt4fyhBf+vZHI/HRkI++QUp3sNoeA2Gw4C+hi4eGSig==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.2.0", + "is-interactive": "^1.0.0", + "log-symbols": "^3.0.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "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==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "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=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "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==", + "dev": true + }, + "pacote": { + "version": "9.5.8", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.8.tgz", + "integrity": "sha512-0Tl8Oi/K0Lo4MZmH0/6IsT3gpGf9eEAznLXEQPKgPq7FscnbUOyopnVpwXlnQdIbCUaojWy1Wd7VMyqfVsRrIw==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "paho-mqtt": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/paho-mqtt/-/paho-mqtt-1.1.0.tgz", + "integrity": "sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA==" + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.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=", + "dev": true, + "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==", + "dev": true + }, + "parse5-html-rewriting-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-5.1.0.tgz", + "integrity": "sha512-hZlaOTHJs4dpC5yFHnOSEMh26ErsqTsLzxKqkuRcUqtiu0kMsBQ9pkgANkECDyoBUhJ3+hvb2DPLsyqbtcS61Q==", + "requires": { + "parse5": "^5.1.0", + "parse5-sax-parser": "^5.1.0" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + } + } + }, + "parse5-sax-parser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-5.1.1.tgz", + "integrity": "sha512-9HIh6zd7bF1NJe95LPCUC311CekdOi55R+HWXNCsGY6053DWaMijVKOv1oPvdvPTvFicifZyimBVJ6/qvG039Q==", + "requires": { + "parse5": "^5.1.1" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + } + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "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==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "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=", + "dev": true + }, + "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=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "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==", + "dev": true + }, + "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=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "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=", + "dev": true + }, + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "portfinder": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "postcss": { + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", + "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-calc": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", + "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", + "dev": true, + "requires": { + "css-unit-converter": "^1.1.1", + "postcss": "^7.0.5", + "postcss-selector-parser": "^5.0.0-rc.4", + "postcss-value-parser": "^3.3.1" + }, + "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==", + "dev": true + } + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-import": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "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==", + "dev": true + } + } + }, + "postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "dev": true, + "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==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "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==", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + } + } + }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "protractor": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.3.tgz", + "integrity": "sha512-7pMAolv8Ah1yJIqaorDTzACtn3gk7BamVKPTeO5lqIGOrfosjPgXFx/z1dqSI+m5EeZc2GMJHPr5DYlodujDNA==", + "dev": true, + "requires": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "optimist": "~0.6.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.0.6" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "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" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "webdriver-manager": { + "version": "12.1.7", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.7.tgz", + "integrity": "sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA==", + "dev": true, + "requires": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + } + } + } + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "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" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "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=", + "dev": true + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true + } + } + }, + "raw-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-3.1.0.tgz", + "integrity": "sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "schema-utils": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-package-json": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", + "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": 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" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.7" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", + "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "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==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "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=", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "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.0", + "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.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "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==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "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==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rollup": { + "version": "1.25.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.25.2.tgz", + "integrity": "sha512-+7z6Wab/L45QCPcfpuTZKwKiB0tynj05s/+s2U3F2Bi7rOLPr9UcjUwO7/xpjlPNXA/hwnth6jBExFRGyf3tMg==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, + "rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "requires": { + "tslib": "^1.9.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==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "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==" + }, + "sass": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.23.3.tgz", + "integrity": "sha512-1DKRZxJMOh4Bme16AbWTyYeJAjTlrvw2+fWshHHaepeJfGq2soFZTnt0YhWit+bohtDu4LdyPoEj6VFD4APHog==", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, + "sass-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz", + "integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "schema-utils": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "selfsigned": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "dev": true, + "requires": { + "node-forge": "0.9.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "requires": { + "semver": "^5.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "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": { + "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=", + "dev": true, + "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=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "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=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "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==", + "dev": true + } + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "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": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "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==", + "dev": true, + "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=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "socks": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "dev": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "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==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + }, + "source-map-loader": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz", + "integrity": "sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ==", + "dev": true, + "requires": { + "async": "^2.5.0", + "loader-utils": "^1.1.0" + } + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "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.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", + "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==" + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "spdy": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", + "dev": true, + "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" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "readable-stream": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", + "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "speed-measure-webpack-plugin": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.1.tgz", + "integrity": "sha512-qVIkJvbtS9j/UeZumbdfz0vg+QfG/zxonAjzefZrqzkr7xOncLVXkeGbTpzd1gjCBM4PmVNkWlkeTVhgskAGSQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "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": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "streamroller": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.14" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.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=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "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=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "style-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.0.0.tgz", + "integrity": "sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "schema-utils": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "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==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "dev": true, + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "stylus": { + "version": "0.54.7", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.7.tgz", + "integrity": "sha512-Yw3WMTzVwevT6ZTrLCYNHAFmanMxdylelL3hkWNgPMeTCpMwpV3nXjpOHuBXtFv7aiO2xRuQS6OoAdgkNcSNug==", + "dev": true, + "requires": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.3", + "mkdirp": "~0.5.x", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.0.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "terser": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.5.1.tgz", + "integrity": "sha512-lH9zLIbX8PRBEFCTvfHGCy0s9HEKnNso1Dx9swSopF3VUnFLB8DpQ61tHxoofovNC/sG0spajJM3EIIRSTByiQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.3.tgz", + "integrity": "sha512-gWHkaGzGYjmDoYxksFZynWTzvXOAjQ5dd7xuTMYlv4zpWlLSb6v0QLSZjELzP5dMs1ox30O1BIPs9dgqlMHuLQ==", + "dev": true, + "requires": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.2.0", + "jest-worker": "^25.1.0", + "p-limit": "^2.2.2", + "schema-utils": "^2.6.4", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.4.3", + "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==", + "dev": true, + "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" + } + }, + "find-cache-dir": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.2.0.tgz", + "integrity": "sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.0", + "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==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz", + "integrity": "sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "minipass": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "dev": true, + "requires": { + "yallist": "^4.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==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "schema-utils": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "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=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "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=", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, + "tslint": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.15.0.tgz", + "integrity": "sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "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=", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "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=", + "dev": true + }, + "typescript": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", + "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", + "dev": true + }, + "uglify-js": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.6.tgz", + "integrity": "sha512-yYqjArOYSxvqeeiYH2VGjZOqq6SVmhxzaPjJC1W2F9e+bqvFL9QXQ2osQuKUFjM2hGjKG2YclQnRKWQSt/nOTQ==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "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==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universal-analytics": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.20.tgz", + "integrity": "sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw==", + "dev": true, + "requires": { + "debug": "^3.0.0", + "request": "^2.88.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "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=", + "dev": true + }, + "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-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "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==", + "dev": true + }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "dev": true, + "requires": { + "lru-cache": "4.1.x", + "tmp": "0.0.x" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "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=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "dependencies": { + "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==", + "dev": true + } + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "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==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": 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" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "3.2.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "dev": true, + "optional": true, + "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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "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=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "requires": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + } + }, + "webpack": { + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", + "dev": true, + "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.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + } + } + }, + "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==", + "dev": true, + "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": { + "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=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + } + } + }, + "webpack-dev-server": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz", + "integrity": "sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw==", + "dev": true, + "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.2.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.4", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.25", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.4.0", + "spdy": "^4.0.1", + "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": "12.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": 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" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "3.2.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "dev": true, + "optional": true, + "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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "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==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "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==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "webpack-subresource-integrity": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.3.4.tgz", + "integrity": "sha512-6XbGYzjh30cGQT/NsC+9IAkJP8IL7/t47sbwR5DLSsamiD56Rwv4/+hsgEHsviPvrEFZ0JRAQtCRN3UsR2Pw9g==", + "dev": true, + "requires": { + "webpack-sources": "^1.3.0" + } + }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "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=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "worker-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-3.2.0.tgz", + "integrity": "sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "dependencies": { + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + } + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "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==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, + "zone.js": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.2.tgz", + "integrity": "sha512-UAYfiuvxLN4oyuqhJwd21Uxb4CNawrq6fPS/05Su5L4G+1TN+HVDJMUHNMobVQDFJRir2cLAODXwluaOKB7HFg==" + } + } +} diff --git a/Website/HPIoTWebApp/package.json b/Website/HPIoTWebApp/package.json new file mode 100644 index 0000000..ebb466d --- /dev/null +++ b/Website/HPIoTWebApp/package.json @@ -0,0 +1,54 @@ +{ + "name": "hpiot-web-app", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "~9.0.0", + "@angular/cdk": "^9.0.0", + "@angular/common": "~9.0.0", + "@angular/compiler": "~9.0.0", + "@angular/core": "~9.0.0", + "@angular/forms": "~9.0.0", + "@angular/material": "^9.0.0", + "@angular/platform-browser": "~9.0.0", + "@angular/platform-browser-dynamic": "~9.0.0", + "@angular/pwa": "^0.803.25", + "@angular/router": "~9.0.0", + "@angular/service-worker": "~9.0.0", + "aws-amplify": "^1.2.2", + "chart.js": "^2.9.3", + "d3": "^5.15.0", + "rxjs": "~6.5.4", + "tslib": "^1.10.0", + "zone.js": "~0.10.2" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^0.900.1", + "@angular/cli": "^9.0.1", + "@angular/compiler-cli": "~9.0.0", + "@angular/language-service": "~9.0.0", + "@types/jasmine": "~3.3.8", + "@types/jasminewd2": "~2.0.3", + "@types/node": "^13.7.0", + "codelyzer": "^5.2.1", + "jasmine-core": "~3.4.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~4.1.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~2.0.1", + "karma-jasmine-html-reporter": "^1.5.2", + "protractor": "^5.4.3", + "ts-node": "~7.0.0", + "tslint": "~5.15.0", + "typescript": "~3.7.5" + } +} diff --git a/Website/HPIoTWebApp/src/app/app-routing.module.ts b/Website/HPIoTWebApp/src/app/app-routing.module.ts new file mode 100644 index 0000000..264e9b3 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/app-routing.module.ts @@ -0,0 +1,43 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { AuthComponent } from './auth/auth.component'; +import { SignInComponent } from './auth/sign-in/sign-in.component'; +import { SignUpComponent } from './auth/sign-up/sign-up.component'; +import { UnauthGuard } from './auth/unauth.guard'; +import { AuthGuard } from './auth/auth.guard'; +import { ConfirmCodeComponent } from './auth/confirm-code/confirm-code.component'; +import { ProfileComponent } from './auth/profile/profile.component'; +import { ConfigsComponent } from './configs/configs.component'; + +const routes: Routes = [ + { path: 'auth', component: AuthComponent, children: [ + { + path: 'signin', + component: SignInComponent, + canActivate: [UnauthGuard] + }, + { + path: 'signup', + component: SignUpComponent, + canActivate: [UnauthGuard] + }, + { + path: 'confirm', + component: ConfirmCodeComponent, + canActivate: [UnauthGuard] + }, + { + path: 'profile', + component: ProfileComponent, + canActivate: [AuthGuard] + } + ]}, + { path: 'configs', component: ConfigsComponent, canActivate: [AuthGuard]}, + { path: '', component: DashboardComponent, canActivate: [AuthGuard] }]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/Website/HPIoTWebApp/src/app/app.component.html b/Website/HPIoTWebApp/src/app/app.component.html new file mode 100644 index 0000000..618e382 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/app.component.html @@ -0,0 +1,99 @@ +
\ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/app.component.scss b/Website/HPIoTWebApp/src/app/app.component.scss new file mode 100644 index 0000000..e21df0d --- /dev/null +++ b/Website/HPIoTWebApp/src/app/app.component.scss @@ -0,0 +1,106 @@ +@import '~@angular/material/theming'; + +// Plus imports for other components in your app. + +// Include the common styles for Angular Material. We include this here so that you only +// have to load a single css file for Angular Material in your app. +// Be sure that you only ever include this mixin once! +@include mat-core(); + +// Define the palettes for your theme using the Material Design palettes available in palette.scss +// (imported above). For each palette, you can optionally specify a default, lighter, and darker +// hue. Available color palettes: https://material.io/design/color/ +$app-primary: mat-palette($mat-indigo, 800); +$app-accent: mat-palette($mat-pink, 800); +$app-active: mat-palette($mat-pink, 800); + +// The warn palette is optional (defaults to red). +$app-warn: mat-palette($mat-red); + +// Create the theme object (a Sass map containing all of the palettes). +$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn); + +// Include theme styles for core and each component used in your app. +// Alternatively, you can import and @include the theme mixins for each component +// that you are using. +@include angular-material-theme($app-theme); + +.active { + color: mat-color($app-primary); +} +.valid, .primary { + color: mat-color($app-primary); +} + + + +html, body { height: 100%; } +body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } +form { + width: 100%; +} + +form > * { + margin-bottom: 1.5em; + width: 100%; +} + +a { + color: mat-color($app-accent); +} + +.content { + padding: 0.5em; +} + +.sidenav-content { + flex-direction: column; +} + +.sidenav-container { + height: 90%; +} + +.app-content { + flex: 1; + margin: 0 auto; + padding: 2em; +} + +.cursor-pointer { + cursor: pointer; +} + +.full-width { + width: 100%; +} + +.active { + color: mat-color($app-active); +} + +.flex-spacer { + flex-grow: 1; +} +.item-list { + border: solid 1px #ccc; + min-height: 60px; + background: white; + border-radius: 4px; + overflow: hidden; + display: block; + } + +.item-box { + padding: 20px 10px; + border-bottom: solid 1px #ccc; + color: rgba(0, 0, 0, 0.87); + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + cursor: move; + background: white; + font-size: 14px; + } \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/app.component.spec.ts b/Website/HPIoTWebApp/src/app/app.component.spec.ts new file mode 100644 index 0000000..43f899f --- /dev/null +++ b/Website/HPIoTWebApp/src/app/app.component.spec.ts @@ -0,0 +1,35 @@ +import { TestBed, async } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule + ], + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have as title 'HPIoTWebApp'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('HPIoTWebApp'); + }); + + it('should render title in a h1 tag', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to HPIoTWebApp!'); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/app.component.ts b/Website/HPIoTWebApp/src/app/app.component.ts new file mode 100644 index 0000000..3874824 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/app.component.ts @@ -0,0 +1,79 @@ +import { Component, ChangeDetectorRef, EventEmitter, Output, OnInit } from '@angular/core'; +import { MediaMatcher } from '@angular/cdk/layout'; +import { MatSidenav } from '@angular/material/sidenav'; +import { DataService, AWSData } from './services/data.service'; +import { AuthService } from './auth/auth.service'; +import { Router } from '@angular/router'; +import { RangeValueAccessor } from '@angular/forms'; +import { CdkDragDrop } from '@angular/cdk/drag-drop'; + + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent implements OnInit { + title = 'HP SCADA'; + sidebar: AWSData = []; + mobileQuery: MediaQueryList; + nav = [ + { + title: 'Home', + path: '/' + }, + { + title: 'Account Settings', + path: '/auth' + }, + { + title: 'Device Configs', + path: '/configs' + } + ]; + + + private mobileQueryListener: () => void; + @Output() toggleSideNav = new EventEmitter(); + + constructor( changeDetectorRef: ChangeDetectorRef, media: MediaMatcher , public dataservice: DataService, + public authService: AuthService, private router: Router) { + this.mobileQuery = media.matchMedia('(max-width: 600px)'); + this.mobileQueryListener = () => changeDetectorRef.detectChanges(); + this.mobileQuery.addListener(this.mobileQueryListener); + } + + ngOnInit() { + this.dataservice.message.subscribe((data) => { + data.forEach( element => { + if (this.sidebar[element.field]) { + this.sidebar[element.field].push(element); + } else { + this.sidebar[element.field] = []; + this.sidebar[element.field].push(element); + } + }); + }); + } + roleChange(index: number) { + this.sidebar = []; + this.dataservice.setRole(index); + } + toggleMobileNav(nav: MatSidenav) { + if (this.mobileQuery.matches) { + nav.toggle(); + } + } + + signOut(nav: MatSidenav) { + nav.toggle(); + this.sidebar = []; + this.dataservice.serverMessages = []; + this.authService.signOut() + .then(() => this.router.navigate(['auth/signin'])); + } + + drop(event: CdkDragDrop) { + console.log(event); + } +} diff --git a/Website/HPIoTWebApp/src/app/app.module.ts b/Website/HPIoTWebApp/src/app/app.module.ts new file mode 100644 index 0000000..b46c9e0 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/app.module.ts @@ -0,0 +1,56 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { MaterialModule } from './material/material.module'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { ServiceWorkerModule } from '@angular/service-worker'; +import { environment } from '../environments/environment'; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { AuthComponent } from './auth/auth.component'; +import { LoaderComponent } from './loader/loader.component'; +import { CountryCodeSelectComponent } from './auth/country-code-select/country-code-select.component'; +import { FilterPipe } from './auth/country-code-select/filter.pipe'; +import { SignInComponent } from './auth/sign-in/sign-in.component'; +import { SignUpComponent } from './auth/sign-up/sign-up.component'; +import { ConfirmCodeComponent } from './auth/confirm-code/confirm-code.component'; +import { ProfileComponent } from './auth/profile/profile.component'; +import { AvatarComponent } from './auth/profile/avatar/avatar.component'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; +import { ConfigsComponent } from './configs/configs.component'; +import { HttpClientModule } from '@angular/common/http'; +import { DataService } from './services/data.service'; +@NgModule({ + declarations: [ + AppComponent, + DashboardComponent, + AuthComponent, + LoaderComponent, + CountryCodeSelectComponent, + FilterPipe, + SignInComponent, + SignUpComponent, + ConfirmCodeComponent, + ProfileComponent, + AvatarComponent, + ConfigsComponent + ], + imports: [ + BrowserModule, + AppRoutingModule, + BrowserAnimationsModule, + MaterialModule, + ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), + ReactiveFormsModule, + FormsModule, + MatTableModule, + MatSortModule, + HttpClientModule + ], + providers: [DataService], + bootstrap: [AppComponent], + entryComponents: [LoaderComponent, CountryCodeSelectComponent] +}) +export class AppModule { } diff --git a/Website/HPIoTWebApp/src/app/auth/auth.component.html b/Website/HPIoTWebApp/src/app/auth/auth.component.html new file mode 100644 index 0000000..6a164d6 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.component.html @@ -0,0 +1,2 @@ + + diff --git a/Website/HPIoTWebApp/src/app/auth/auth.component.scss b/Website/HPIoTWebApp/src/app/auth/auth.component.scss new file mode 100644 index 0000000..5a978da --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.component.scss @@ -0,0 +1,9 @@ +:host { + height: 100%; +} + +.auth-btn-signup { + position: absolute; + bottom: 1em; + right: 2em; +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/auth.component.spec.ts b/Website/HPIoTWebApp/src/app/auth/auth.component.spec.ts new file mode 100644 index 0000000..884576c --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AuthComponent } from './auth.component'; + +describe('AuthComponent', () => { + let component: AuthComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AuthComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AuthComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/auth.component.ts b/Website/HPIoTWebApp/src/app/auth/auth.component.ts new file mode 100644 index 0000000..c89c113 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit, NgZone } from '@angular/core'; +import Auth from '@aws-amplify/auth'; +import { Router } from '@angular/router'; +import { Hub } from '@aws-amplify/core'; + +@Component({ + selector: 'app-auth', + templateUrl: './auth.component.html', + styleUrls: ['./auth.component.scss'] +}) +export class AuthComponent implements OnInit { + + constructor( private router: Router, private zone: NgZone ) { } + + ngOnInit() { + Hub.listen('auth', ({ payload: { event, data } }) => { + switch (event) { + case 'signIn': + this.zone.run(() => { + this.router.navigate(['/']); + }); + break; + case 'signOut': + this.zone.run(() => { + this.router.navigate(['/auth/signin']); + }); + break; + } + }); + Auth.currentAuthenticatedUser() + .then(() => { + this.router.navigate(['auth/profile']); + }) + .catch(() => {}); + } + +} diff --git a/Website/HPIoTWebApp/src/app/auth/auth.guard.spec.ts b/Website/HPIoTWebApp/src/app/auth/auth.guard.spec.ts new file mode 100644 index 0000000..7ed05ee --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.guard.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, async, inject } from '@angular/core/testing'; + +import { AuthGuard } from './auth.guard'; + +describe('AuthGuard', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [AuthGuard] + }); + }); + + it('should ...', inject([AuthGuard], (guard: AuthGuard) => { + expect(guard).toBeTruthy(); + })); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/auth.guard.ts b/Website/HPIoTWebApp/src/app/auth/auth.guard.ts new file mode 100644 index 0000000..456df33 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.guard.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { Observable } from 'rxjs'; +import Auth from '@aws-amplify/auth'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthGuard implements CanActivate { + constructor( private router: Router ) { } + canActivate( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean { + return Auth.currentAuthenticatedUser().then(() => true) + .catch(() => { + this.router.navigate(['auth/signin']); + return false; + }); + } +} diff --git a/Website/HPIoTWebApp/src/app/auth/auth.service.spec.ts b/Website/HPIoTWebApp/src/app/auth/auth.service.spec.ts new file mode 100644 index 0000000..f3d964d --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuthService } from './auth.service'; + +describe('AuthService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: AuthService = TestBed.get(AuthService); + expect(service).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/auth.service.ts b/Website/HPIoTWebApp/src/app/auth/auth.service.ts new file mode 100644 index 0000000..94ca664 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/auth.service.ts @@ -0,0 +1,75 @@ +import { Injectable } from '@angular/core'; +import Auth, { CognitoHostedUIIdentityProvider } from '@aws-amplify/auth'; +import { Hub, ICredentials } from '@aws-amplify/core'; +import { Subject, Observable } from 'rxjs'; +import { CognitoUser } from 'amazon-cognito-identity-js'; +import { DataService } from '../services/data.service'; + +export interface NewUser { + email: string; + phone: string; + password: string; + firstName: string; + lastName: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + + public static SIGN_IN = 'signIn'; + public static SIGN_OUT = 'signOut'; + public static FACEBOOK = CognitoHostedUIIdentityProvider.Facebook; + public static GOOGLE = CognitoHostedUIIdentityProvider.Google; + public loggedIn: boolean; + private authStateSubject: Subject = new Subject(); + authState: Observable = this.authStateSubject.asObservable(); + + + constructor(private dataService: DataService) { + Hub.listen('auth', (data) => { + const { channel, payload } = data; + if (channel === 'auth') { + this.authStateSubject.next(payload.event); + } + }); + Auth.currentAuthenticatedUser().then(() => this.loggedIn = true).catch(() => this.loggedIn = false); + } + + signUp(user: NewUser): Promise { + return Auth.signUp({ + username: user.email, + password: user.password, + attributes: { + email: user.email, + given_name: user.firstName, + family_name: user.lastName, + phone_number: user.phone + } + }); + } + + signIn(username: string, password: string): Promise { + return new Promise((resolve, reject) => { + Auth.signIn(username, password) + .then((user: CognitoUser|any) => { + this.loggedIn = true; + this.dataService.startUp(); + resolve(user); + }).catch((error: any) => reject(error)); + }); + } + + signOut(): Promise { + return Auth.signOut() + .then(() => this.loggedIn = false); + } + + socialSignIn(provider: CognitoHostedUIIdentityProvider): Promise { + return Auth.federatedSignIn({ + provider + }); + } + +} diff --git a/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.html b/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.html new file mode 100644 index 0000000..a364c27 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.html @@ -0,0 +1,12 @@ +
+

Confirm your email address

+ + + + + + Enter the confirmation code that was emailed to you + + +

Didn't receive a code? Send again

+
diff --git a/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.scss b/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.spec.ts b/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.spec.ts new file mode 100644 index 0000000..f52f788 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConfirmCodeComponent } from './confirm-code.component'; + +describe('ConfirmCodeComponent', () => { + let component: ConfirmCodeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ConfirmCodeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfirmCodeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.ts b/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.ts new file mode 100644 index 0000000..7e2da80 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/confirm-code/confirm-code.component.ts @@ -0,0 +1,60 @@ +import { Component, OnInit } from '@angular/core'; +import { FormGroup, Validators, FormControl } from '@angular/forms'; +import { environment } from 'src/environments/environment'; +import { Router } from '@angular/router'; +import Auth from '@aws-amplify/auth'; +import { NotificationService } from 'src/app/services/notification.service'; + +@Component({ + selector: 'app-confirm-code', + templateUrl: './confirm-code.component.html', + styleUrls: ['./confirm-code.component.scss'] +}) +export class ConfirmCodeComponent implements OnInit { + + email = environment.confirm.email; + confirmForm: FormGroup = new FormGroup({ + email: new FormControl({value: this.email, disabled: true}), + code: new FormControl('', [ Validators.required, Validators.min(3) ]) + }); + + get codeInput() { return this.confirmForm.get('code'); } + + constructor( private _router: Router, private _notification: NotificationService ) { } + + ngOnInit() { + if (!this.email) { + this._router.navigate(['auth/signup']); + } else { + Auth.resendSignUp(this.email); + } + } + + sendAgain() { + Auth.resendSignUp(this.email) + .then(() => this._notification.show('A code has been emailed to you')) + .catch(() => this._notification.show('An error occurred')); + } + + confirmCode() { + Auth.confirmSignUp(this.email, this.codeInput.value) + .then((data: any) => { + console.log(data); + if (data === 'SUCCESS' && + environment.confirm.email && + environment.confirm.password) { + Auth.signIn(this.email, environment.confirm.password) + .then(() => { + this._router.navigate(['']); + }).catch((error: any) => { + this._router.navigate(['auth/signin']); + }) + } + }) + .catch((error: any) => { + console.log(error); + this._notification.show(error.message); + }) + } + +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.html b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.html new file mode 100644 index 0000000..205b36f --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.html @@ -0,0 +1,10 @@ + + + + + + {{ code.name }} + {{ code.dial_code }} + + + \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.scss b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.scss new file mode 100644 index 0000000..be4f704 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.scss @@ -0,0 +1,10 @@ +.country-list { + margin-top: 5px; + height: 300px; + overflow-y: scroll; +} +.country-filter { + position: sticky; + top: 0em; + margin-top:0.5em; +} diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.spec.ts b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.spec.ts new file mode 100644 index 0000000..c9b907d --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CountryCodeSelectComponent } from './country-code-select.component'; + +describe('CountryCodeSelectComponent', () => { + let component: CountryCodeSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CountryCodeSelectComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CountryCodeSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.ts b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.ts new file mode 100644 index 0000000..cbec2d4 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-code-select.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; +import { CountryCode, CountryCodes } from './country-codes'; +import { MatBottomSheetRef } from '@angular/material/bottom-sheet'; + +@Component({ + selector: 'app-country-code-select', + templateUrl: './country-code-select.component.html', + styleUrls: ['./country-code-select.component.scss'] +}) +export class CountryCodeSelectComponent implements OnInit { + countryCodes: Array = CountryCodes; + constructor(private bottomSheetRef: MatBottomSheetRef) { } + + ngOnInit() { + } + + selectCountry(code: CountryCode) { + this.bottomSheetRef.dismiss(code); + } + +} diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.spec.ts b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.spec.ts new file mode 100644 index 0000000..a7a4429 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.spec.ts @@ -0,0 +1,7 @@ +import { CountryCodes } from './country-codes'; + +describe('CountryCodes', () => { + it('should create an instance', () => { + expect(new CountryCodes()).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.ts b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.ts new file mode 100644 index 0000000..02a6d71 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/country-codes.ts @@ -0,0 +1,1213 @@ +export interface CountryCode { + name: string; + dial_code: string; + code: string; +} + +export const CountryCodes: Array = [ +{ +name: 'Afghanistan', +dial_code: '+93', +code: 'AF' +}, +{ +name: 'Aland Islands', +dial_code: '+358', +code: 'AX' +}, +{ +name: 'Albania', +dial_code: '+355', +code: 'AL' +}, +{ +name: 'Algeria', +dial_code: '+213', +code: 'DZ' +}, +{ +name: 'AmericanSamoa', +dial_code: '+1 684', +code: 'AS' +}, +{ +name: 'Andorra', +dial_code: '+376', +code: 'AD' +}, +{ +name: 'Angola', +dial_code: '+244', +code: 'AO' +}, +{ +name: 'Anguilla', +dial_code: '+1 264', +code: 'AI' +}, +{ +name: 'Antarctica', +dial_code: '+672', +code: 'AQ' +}, +{ +name: 'Antigua and Barbuda', +dial_code: '+1268', +code: 'AG' +}, +{ +name: 'Argentina', +dial_code: '+54', +code: 'AR' +}, +{ +name: 'Armenia', +dial_code: '+374', +code: 'AM' +}, +{ +name: 'Aruba', +dial_code: '+297', +code: 'AW' +}, +{ +name: 'Australia', +dial_code: '+61', +code: 'AU' +}, +{ +name: 'Austria', +dial_code: '+43', +code: 'AT' +}, +{ +name: 'Azerbaijan', +dial_code: '+994', +code: 'AZ' +}, +{ +name: 'Bahamas', +dial_code: '+1 242', +code: 'BS' +}, +{ +name: 'Bahrain', +dial_code: '+973', +code: 'BH' +}, +{ +name: 'Bangladesh', +dial_code: '+880', +code: 'BD' +}, +{ +name: 'Barbados', +dial_code: '+1 246', +code: 'BB' +}, +{ +name: 'Belarus', +dial_code: '+375', +code: 'BY' +}, +{ +name: 'Belgium', +dial_code: '+32', +code: 'BE' +}, +{ +name: 'Belize', +dial_code: '+501', +code: 'BZ' +}, +{ +name: 'Benin', +dial_code: '+229', +code: 'BJ' +}, +{ +name: 'Bermuda', +dial_code: '+1 441', +code: 'BM' +}, +{ +name: 'Bhutan', +dial_code: '+975', +code: 'BT' +}, +{ +name: 'Bolivia, Plurinational State of', +dial_code: '+591', +code: 'BO' +}, +{ +name: 'Bosnia and Herzegovina', +dial_code: '+387', +code: 'BA' +}, +{ +name: 'Botswana', +dial_code: '+267', +code: 'BW' +}, +{ +name: 'Brazil', +dial_code: '+55', +code: 'BR' +}, +{ +name: 'British Indian Ocean Territory', +dial_code: '+246', +code: 'IO' +}, +{ +name: 'Brunei Darussalam', +dial_code: '+673', +code: 'BN' +}, +{ +name: 'Bulgaria', +dial_code: '+359', +code: 'BG' +}, +{ +name: 'Burkina Faso', +dial_code: '+226', +code: 'BF' +}, +{ +name: 'Burundi', +dial_code: '+257', +code: 'BI' +}, +{ +name: 'Cambodia', +dial_code: '+855', +code: 'KH' +}, +{ +name: 'Cameroon', +dial_code: '+237', +code: 'CM' +}, +{ +name: 'Canada', +dial_code: '+1', +code: 'CA' +}, +{ +name: 'Cape Verde', +dial_code: '+238', +code: 'CV' +}, +{ +name: 'Cayman Islands', +dial_code: '+ 345', +code: 'KY' +}, +{ +name: 'Central African Republic', +dial_code: '+236', +code: 'CF' +}, +{ +name: 'Chad', +dial_code: '+235', +code: 'TD' +}, +{ +name: 'Chile', +dial_code: '+56', +code: 'CL' +}, +{ +name: 'China', +dial_code: '+86', +code: 'CN' +}, +{ +name: 'Christmas Island', +dial_code: '+61', +code: 'CX' +}, +{ +name: 'Cocos (Keeling) Islands', +dial_code: '+61', +code: 'CC' +}, +{ +name: 'Colombia', +dial_code: '+57', +code: 'CO' +}, +{ +name: 'Comoros', +dial_code: '+269', +code: 'KM' +}, +{ +name: 'Congo', +dial_code: '+242', +code: 'CG' +}, +{ +name: 'Congo, The Democratic Republic of the Congo', +dial_code: '+243', +code: 'CD' +}, +{ +name: 'Cook Islands', +dial_code: '+682', +code: 'CK' +}, +{ +name: 'Costa Rica', +dial_code: '+506', +code: 'CR' +}, +{ +name: 'Cote d\'Ivoire', +dial_code: '+225', +code: 'CI' +}, +{ +name: 'Croatia', +dial_code: '+385', +code: 'HR' +}, +{ +name: 'Cuba', +dial_code: '+53', +code: 'CU' +}, +{ +name: 'Cyprus', +dial_code: '+357', +code: 'CY' +}, +{ +name: 'Czech Republic', +dial_code: '+420', +code: 'CZ' +}, +{ +name: 'Denmark', +dial_code: '+45', +code: 'DK' +}, +{ +name: 'Djibouti', +dial_code: '+253', +code: 'DJ' +}, +{ +name: 'Dominica', +dial_code: '+1 767', +code: 'DM' +}, +{ +name: 'Dominican Republic', +dial_code: '+1 849', +code: 'DO' +}, +{ +name: 'Ecuador', +dial_code: '+593', +code: 'EC' +}, +{ +name: 'Egypt', +dial_code: '+20', +code: 'EG' +}, +{ +name: 'El Salvador', +dial_code: '+503', +code: 'SV' +}, +{ +name: 'Equatorial Guinea', +dial_code: '+240', +code: 'GQ' +}, +{ +name: 'Eritrea', +dial_code: '+291', +code: 'ER' +}, +{ +name: 'Estonia', +dial_code: '+372', +code: 'EE' +}, +{ +name: 'Ethiopia', +dial_code: '+251', +code: 'ET' +}, +{ +name: 'Falkland Islands (Malvinas)', +dial_code: '+500', +code: 'FK' +}, +{ +name: 'Faroe Islands', +dial_code: '+298', +code: 'FO' +}, +{ +name: 'Fiji', +dial_code: '+679', +code: 'FJ' +}, +{ +name: 'Finland', +dial_code: '+358', +code: 'FI' +}, +{ +name: 'France', +dial_code: '+33', +code: 'FR' +}, +{ +name: 'French Guiana', +dial_code: '+594', +code: 'GF' +}, +{ +name: 'French Polynesia', +dial_code: '+689', +code: 'PF' +}, +{ +name: 'Gabon', +dial_code: '+241', +code: 'GA' +}, +{ +name: 'Gambia', +dial_code: '+220', +code: 'GM' +}, +{ +name: 'Georgia', +dial_code: '+995', +code: 'GE' +}, +{ +name: 'Germany', +dial_code: '+49', +code: 'DE' +}, +{ +name: 'Ghana', +dial_code: '+233', +code: 'GH' +}, +{ +name: 'Gibraltar', +dial_code: '+350', +code: 'GI' +}, +{ +name: 'Greece', +dial_code: '+30', +code: 'GR' +}, +{ +name: 'Greenland', +dial_code: '+299', +code: 'GL' +}, +{ +name: 'Grenada', +dial_code: '+1 473', +code: 'GD' +}, +{ +name: 'Guadeloupe', +dial_code: '+590', +code: 'GP' +}, +{ +name: 'Guam', +dial_code: '+1 671', +code: 'GU' +}, +{ +name: 'Guatemala', +dial_code: '+502', +code: 'GT' +}, +{ +name: 'Guernsey', +dial_code: '+44', +code: 'GG' +}, +{ +name: 'Guinea', +dial_code: '+224', +code: 'GN' +}, +{ +name: 'Guinea-Bissau', +dial_code: '+245', +code: 'GW' +}, +{ +name: 'Guyana', +dial_code: '+595', +code: 'GY' +}, +{ +name: 'Haiti', +dial_code: '+509', +code: 'HT' +}, +{ +name: 'Holy See (Vatican City State)', +dial_code: '+379', +code: 'VA' +}, +{ +name: 'Honduras', +dial_code: '+504', +code: 'HN' +}, +{ +name: 'Hong Kong', +dial_code: '+852', +code: 'HK' +}, +{ +name: 'Hungary', +dial_code: '+36', +code: 'HU' +}, +{ +name: 'Iceland', +dial_code: '+354', +code: 'IS' +}, +{ +name: 'India', +dial_code: '+91', +code: 'IN' +}, +{ +name: 'Indonesia', +dial_code: '+62', +code: 'ID' +}, +{ +name: 'Iran, Islamic Republic of Persian Gulf', +dial_code: '+98', +code: 'IR' +}, +{ +name: 'Iraq', +dial_code: '+964', +code: 'IQ' +}, +{ +name: 'Ireland', +dial_code: '+353', +code: 'IE' +}, +{ +name: 'Isle of Man', +dial_code: '+44', +code: 'IM' +}, +{ +name: 'Israel', +dial_code: '+972', +code: 'IL' +}, +{ +name: 'Italy', +dial_code: '+39', +code: 'IT' +}, +{ +name: 'Jamaica', +dial_code: '+1 876', +code: 'JM' +}, +{ +name: 'Japan', +dial_code: '+81', +code: 'JP' +}, +{ +name: 'Jersey', +dial_code: '+44', +code: 'JE' +}, +{ +name: 'Jordan', +dial_code: '+962', +code: 'JO' +}, +{ +name: 'Kazakhstan', +dial_code: '+7 7', +code: 'KZ' +}, +{ +name: 'Kenya', +dial_code: '+254', +code: 'KE' +}, +{ +name: 'Kiribati', +dial_code: '+686', +code: 'KI' +}, +{ +name: 'Korea, Democratic People\'s Republic of Korea', +dial_code: '+850', +code: 'KP' +}, +{ +name: 'Korea, Republic of South Korea', +dial_code: '+82', +code: 'KR' +}, +{ +name: 'Kuwait', +dial_code: '+965', +code: 'KW' +}, +{ +name: 'Kyrgyzstan', +dial_code: '+996', +code: 'KG' +}, +{ +name: 'Laos', +dial_code: '+856', +code: 'LA' +}, +{ +name: 'Latvia', +dial_code: '+371', +code: 'LV' +}, +{ +name: 'Lebanon', +dial_code: '+961', +code: 'LB' +}, +{ +name: 'Lesotho', +dial_code: '+266', +code: 'LS' +}, +{ +name: 'Liberia', +dial_code: '+231', +code: 'LR' +}, +{ +name: 'Libyan Arab Jamahiriya', +dial_code: '+218', +code: 'LY' +}, +{ +name: 'Liechtenstein', +dial_code: '+423', +code: 'LI' +}, +{ +name: 'Lithuania', +dial_code: '+370', +code: 'LT' +}, +{ +name: 'Luxembourg', +dial_code: '+352', +code: 'LU' +}, +{ +name: 'Macao', +dial_code: '+853', +code: 'MO' +}, +{ +name: 'Macedonia', +dial_code: '+389', +code: 'MK' +}, +{ +name: 'Madagascar', +dial_code: '+261', +code: 'MG' +}, +{ +name: 'Malawi', +dial_code: '+265', +code: 'MW' +}, +{ +name: 'Malaysia', +dial_code: '+60', +code: 'MY' +}, +{ +name: 'Maldives', +dial_code: '+960', +code: 'MV' +}, +{ +name: 'Mali', +dial_code: '+223', +code: 'ML' +}, +{ +name: 'Malta', +dial_code: '+356', +code: 'MT' +}, +{ +name: 'Marshall Islands', +dial_code: '+692', +code: 'MH' +}, +{ +name: 'Martinique', +dial_code: '+596', +code: 'MQ' +}, +{ +name: 'Mauritania', +dial_code: '+222', +code: 'MR' +}, +{ +name: 'Mauritius', +dial_code: '+230', +code: 'MU' +}, +{ +name: 'Mayotte', +dial_code: '+262', +code: 'YT' +}, +{ +name: 'Mexico', +dial_code: '+52', +code: 'MX' +}, +{ +name: 'Micronesia, Federated States of Micronesia', +dial_code: '+691', +code: 'FM' +}, +{ +name: 'Moldova', +dial_code: '+373', +code: 'MD' +}, +{ +name: 'Monaco', +dial_code: '+377', +code: 'MC' +}, +{ +name: 'Mongolia', +dial_code: '+976', +code: 'MN' +}, +{ +name: 'Montenegro', +dial_code: '+382', +code: 'ME' +}, +{ +name: 'Montserrat', +dial_code: '+1664', +code: 'MS' +}, +{ +name: 'Morocco', +dial_code: '+212', +code: 'MA' +}, +{ +name: 'Mozambique', +dial_code: '+258', +code: 'MZ' +}, +{ +name: 'Myanmar', +dial_code: '+95', +code: 'MM' +}, +{ +name: 'Namibia', +dial_code: '+264', +code: 'NA' +}, +{ +name: 'Nauru', +dial_code: '+674', +code: 'NR' +}, +{ +name: 'Nepal', +dial_code: '+977', +code: 'NP' +}, +{ +name: 'Netherlands', +dial_code: '+31', +code: 'NL' +}, +{ +name: 'Netherlands Antilles', +dial_code: '+599', +code: 'AN' +}, +{ +name: 'New Caledonia', +dial_code: '+687', +code: 'NC' +}, +{ +name: 'New Zealand', +dial_code: '+64', +code: 'NZ' +}, +{ +name: 'Nicaragua', +dial_code: '+505', +code: 'NI' +}, +{ +name: 'Niger', +dial_code: '+227', +code: 'NE' +}, +{ +name: 'Nigeria', +dial_code: '+234', +code: 'NG' +}, +{ +name: 'Niue', +dial_code: '+683', +code: 'NU' +}, +{ +name: 'Norfolk Island', +dial_code: '+672', +code: 'NF' +}, +{ +name: 'Northern Mariana Islands', +dial_code: '+1 670', +code: 'MP' +}, +{ +name: 'Norway', +dial_code: '+47', +code: 'NO' +}, +{ +name: 'Oman', +dial_code: '+968', +code: 'OM' +}, +{ +name: 'Pakistan', +dial_code: '+92', +code: 'PK' +}, +{ +name: 'Palau', +dial_code: '+680', +code: 'PW' +}, +{ +name: 'Palestinian Territory, Occupied', +dial_code: '+970', +code: 'PS' +}, +{ +name: 'Panama', +dial_code: '+507', +code: 'PA' +}, +{ +name: 'Papua New Guinea', +dial_code: '+675', +code: 'PG' +}, +{ +name: 'Paraguay', +dial_code: '+595', +code: 'PY' +}, +{ +name: 'Peru', +dial_code: '+51', +code: 'PE' +}, +{ +name: 'Philippines', +dial_code: '+63', +code: 'PH' +}, +{ +name: 'Pitcairn', +dial_code: '+872', +code: 'PN' +}, +{ +name: 'Poland', +dial_code: '+48', +code: 'PL' +}, +{ +name: 'Portugal', +dial_code: '+351', +code: 'PT' +}, +{ +name: 'Puerto Rico', +dial_code: '+1 939', +code: 'PR' +}, +{ +name: 'Qatar', +dial_code: '+974', +code: 'QA' +}, +{ +name: 'Romania', +dial_code: '+40', +code: 'RO' +}, +{ +name: 'Russia', +dial_code: '+7', +code: 'RU' +}, +{ +name: 'Rwanda', +dial_code: '+250', +code: 'RW' +}, +{ +name: 'Reunion', +dial_code: '+262', +code: 'RE' +}, +{ +name: 'Saint Barthelemy', +dial_code: '+590', +code: 'BL' +}, +{ +name: 'Saint Helena, Ascension and Tristan Da Cunha', +dial_code: '+290', +code: 'SH' +}, +{ +name: 'Saint Kitts and Nevis', +dial_code: '+1 869', +code: 'KN' +}, +{ +name: 'Saint Lucia', +dial_code: '+1 758', +code: 'LC' +}, +{ +name: 'Saint Martin', +dial_code: '+590', +code: 'MF' +}, +{ +name: 'Saint Pierre and Miquelon', +dial_code: '+508', +code: 'PM' +}, +{ +name: 'Saint Vincent and the Grenadines', +dial_code: '+1 784', +code: 'VC' +}, +{ +name: 'Samoa', +dial_code: '+685', +code: 'WS' +}, +{ +name: 'San Marino', +dial_code: '+378', +code: 'SM' +}, +{ +name: 'Sao Tome and Principe', +dial_code: '+239', +code: 'ST' +}, +{ +name: 'Saudi Arabia', +dial_code: '+966', +code: 'SA' +}, +{ +name: 'Senegal', +dial_code: '+221', +code: 'SN' +}, +{ +name: 'Serbia', +dial_code: '+381', +code: 'RS' +}, +{ +name: 'Seychelles', +dial_code: '+248', +code: 'SC' +}, +{ +name: 'Sierra Leone', +dial_code: '+232', +code: 'SL' +}, +{ +name: 'Singapore', +dial_code: '+65', +code: 'SG' +}, +{ +name: 'Slovakia', +dial_code: '+421', +code: 'SK' +}, +{ +name: 'Slovenia', +dial_code: '+386', +code: 'SI' +}, +{ +name: 'Solomon Islands', +dial_code: '+677', +code: 'SB' +}, +{ +name: 'Somalia', +dial_code: '+252', +code: 'SO' +}, +{ +name: 'South Africa', +dial_code: '+27', +code: 'ZA' +}, +{ +name: 'South Georgia and the South Sandwich Islands', +dial_code: '+500', +code: 'GS' +}, +{ +name: 'Spain', +dial_code: '+34', +code: 'ES' +}, +{ +name: 'Sri Lanka', +dial_code: '+94', +code: 'LK' +}, +{ +name: 'Sudan', +dial_code: '+249', +code: 'SD' +}, +{ +name: 'Suriname', +dial_code: '+597', +code: 'SR' +}, +{ +name: 'Svalbard and Jan Mayen', +dial_code: '+47', +code: 'SJ' +}, +{ +name: 'Swaziland', +dial_code: '+268', +code: 'SZ' +}, +{ +name: 'Sweden', +dial_code: '+46', +code: 'SE' +}, +{ +name: 'Switzerland', +dial_code: '+41', +code: 'CH' +}, +{ +name: 'Syrian Arab Republic', +dial_code: '+963', +code: 'SY' +}, +{ +name: 'Taiwan', +dial_code: '+886', +code: 'TW' +}, +{ +name: 'Tajikistan', +dial_code: '+992', +code: 'TJ' +}, +{ +name: 'Tanzania, United Republic of Tanzania', +dial_code: '+255', +code: 'TZ' +}, +{ +name: 'Thailand', +dial_code: '+66', +code: 'TH' +}, +{ +name: 'Timor-Leste', +dial_code: '+670', +code: 'TL' +}, +{ +name: 'Togo', +dial_code: '+228', +code: 'TG' +}, +{ +name: 'Tokelau', +dial_code: '+690', +code: 'TK' +}, +{ +name: 'Tonga', +dial_code: '+676', +code: 'TO' +}, +{ +name: 'Trinidad and Tobago', +dial_code: '+1 868', +code: 'TT' +}, +{ +name: 'Tunisia', +dial_code: '+216', +code: 'TN' +}, +{ +name: 'Turkey', +dial_code: '+90', +code: 'TR' +}, +{ +name: 'Turkmenistan', +dial_code: '+993', +code: 'TM' +}, +{ +name: 'Turks and Caicos Islands', +dial_code: '+1 649', +code: 'TC' +}, +{ +name: 'Tuvalu', +dial_code: '+688', +code: 'TV' +}, +{ +name: 'Uganda', +dial_code: '+256', +code: 'UG' +}, +{ +name: 'Ukraine', +dial_code: '+380', +code: 'UA' +}, +{ +name: 'United Arab Emirates', +dial_code: '+971', +code: 'AE' +}, +{ +name: 'United Kingdom', +dial_code: '+44', +code: 'GB' +}, +{ +name: 'United States', +dial_code: '+1', +code: 'US' +}, +{ +name: 'Uruguay', +dial_code: '+598', +code: 'UY' +}, +{ +name: 'Uzbekistan', +dial_code: '+998', +code: 'UZ' +}, +{ +name: 'Vanuatu', +dial_code: '+678', +code: 'VU' +}, +{ +name: 'Venezuela, Bolivarian Republic of Venezuela', +dial_code: '+58', +code: 'VE' +}, +{ +name: 'Vietnam', +dial_code: '+84', +code: 'VN' +}, +{ +name: 'Virgin Islands, British', +dial_code: '+1 284', +code: 'VG' +}, +{ +name: 'Virgin Islands, U.S.', +dial_code: '+1 340', +code: 'VI' +}, +{ +name: 'Wallis and Futuna', +dial_code: '+681', +code: 'WF' +}, +{ +name: 'Yemen', +dial_code: '+967', +code: 'YE' +}, +{ +name: 'Zambia', +dial_code: '+260', +code: 'ZM' +}, +{ +name: 'Zimbabwe', +dial_code: '+263', +code: 'ZW' +} +]; diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.spec.ts b/Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.spec.ts new file mode 100644 index 0000000..1427de3 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.spec.ts @@ -0,0 +1,8 @@ +import { FilterPipe } from './filter.pipe'; + +describe('FilterPipe', () => { + it('create an instance', () => { + const pipe = new FilterPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.ts b/Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.ts new file mode 100644 index 0000000..a74c418 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/country-code-select/filter.pipe.ts @@ -0,0 +1,19 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { CountryCode } from './country-codes'; +@Pipe({ + name: 'filter' +}) +export class FilterPipe implements PipeTransform { + transform(items: CountryCode[], searchText: string): CountryCode[] { + if (!items) { + return []; + } + if (!searchText) { + return items; + } + searchText = searchText.toLowerCase(); + return items.filter( code => { + return code.name.toLowerCase().includes(searchText); + }); + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.html b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.html new file mode 100644 index 0000000..72b4c4d --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.html @@ -0,0 +1,33 @@ +
+
+ +
+
+ Avatar Preview + +
Processing Avatar...
+
+
+ +
+
+
+
+ +
{{ errorMessage }}
+ × +
+
+
\ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.scss b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.scss new file mode 100644 index 0000000..9ca0ec2 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.scss @@ -0,0 +1,71 @@ +.app-avatar { + width: 95%; + border-radius: 6px; +} + +.avatar-remove { + position: relative; + left: -2em; +} + +.app-avatar-container { + width: 100%; + margin: 0 auto; + padding: 1em; +} + +.app-avatar-upload { + height: 212px; + border: 2px dotted #979797; + border-radius: 4px; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAABBCAYAAACUyynLAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAASASURBVHic7ZtZe7I6FEbfEMIMbe3p//+BfRyKzBk4F2pFvyJDMdiWda2bZD1JSHY2hHNeY2EQxtwN+Iks0kawSBvBIm0Ei7QRmLofyIXEerOHVOpbcahh4HUVgpl0opb1R/tI28Xpt4UBgFQKuzidoEXD0SqtLDmqSkwWr6oEypJPFq8vWqXFSf4jYnahTVpZclR8ulF2ouL6R5s2afccEbpHGxly9uRcoKg4pFSoB5xY67pGXlRj2tcb17FACOn9e0IASg04FgNjwzYRvaRVlcBun4HfYXo9AoyZeA49WFY/eZ3S0qyc7dWum+fIh+/Znb+7uablRfVnhAGHPWSfZaRVmlL1nxJ2YhenUOr2itUqLc2Lzj//RpSqkebFzd+0Sitm2Gk/Cl19b5UmhJy8MT+Frr7fXNP+KqPXtIV2tOfTvsJiJlzHgmWZYCb93NnXdQ0uJKpKIC+qu5xdxzCrNMsyEQUe7JadOCEEFjNhMROB76CsBOIkmzS9NIbZpD1HHnzPGfQf2zLxtoqQZgV2cXanlnWjXRohBK8v4cXoklIhy0sUJYeQEkrVMAwCk1I4NoPn2qD0vPz6ngPTNLHe7lEPyRxMhHZpq+fgU1hd14iTHEn672ZSqRqVEqi4QJzkCHwHUeB+rne2ZWL1HGC93WttP6D57RmFHhybATjk+N838ZfCviJJC7xv4ov7BcdmiELvLm29hTZplBoIjhmEuq6x3u7B+bANNOfynykZeJdTVwfanhaF3ufUipN8sLATnMuLTC0hRPto0yLNMAjc07SUqveUbCNJC0h5nqauzWAY/bO230WLNMc+p6KzvJwkZjMOIQSObU0Stw9apFnsfAs+VfbkOk7zGfdGizRKzx0ScprsyXWc5jPujRZppLHeTJU9uY5Dftuahkb/plqw/4mj8WCgRVrzTWdONI2u4zSfcW+0SOPinJU4nQi+y3Wc5jPujRZpzVoLz+2+V+zDdZyy0nenoWmkSfBj3p1SA4E/LCV0TeA7F0cnLuToE8YYZimAiQIXbOS+ijGKKHAvY+/15ta0SSuKCtVxCp1yakPFMUbx+hJeFLqUFdd+3ag1PbD5SKGOqR1qGHhbRb2nauA7eFtFoMa5yVIpbD/0VwFoTUJKqbDeJvhvdRgthBA8hR4CzxmUuQUO6aXNNtG61TihPXNbcYH3dYzVSwjzKIJSA2HgIrxaq9oQUmGz3X++XHQzy70nFxLv6w+kWTm4ODDNS7yvP2YTBsx4G3WqSkqyAoHnwHWs1iOWUodKyiQrHqJcYvbLYiEkdnGKXZzCNCmYSWEc347qeFn8CKKazC6tiXhAQV/RuqYNqPn9dXT1vVWazqTeo9HV91ZpjjVNNuIn0tX3VmlTZSN+Il19b5XGGB1coPIb8D2n80x8c3P7FLqtZVC/Edsy8RR2n0o6P76o6xof+xxp9r0L3kfH9xw8hW6vT4V6fxvFhUSWHQ7VUslBx59HhBCAGseEgGcP+kJ50AdlCweWQuURLNJGsEgbwSJtBIu0ESzSRrBIG8H/BsMLCwR4M6kAAAAASUVORK5CYII=') center no-repeat #FBFBFB; +} + +.app-avatar-upload-dragover { + opacity: 0.5; + height: 212px; + border: 2px solid #333; + border-radius: 4px; + background: url('data:image/png;base64,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') center no-repeat #cccccc; +} + +.app-upload-input { + margin-top: 0.5em; +} + +.app-upload-button { + margin: 0.5em auto !important; + width: 100% !important; +} + +.app-avatar-preview { + width: auto; + max-height: 200px; +} + +.app-image-container { + display: inline; +} + +.app-image { + width: 30%; + margin: 0.2em; + border-radius: 6px; + border: 2px solid white; + cursor: pointer; +} + +@media (max-width: 600px) { +.app-avatar { + width: 100%; +} +.app-image { + width: 100%; +} +.app-avatar-container { + width: auto; +} +.app-avatar-upload { + width: auto; +} +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.spec.ts b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.spec.ts new file mode 100644 index 0000000..562f867 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AvatarComponent } from './avatar.component'; + +describe('AvatarComponent', () => { + let component: AvatarComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AvatarComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AvatarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.ts b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.ts new file mode 100644 index 0000000..dd3a507 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/avatar/avatar.component.ts @@ -0,0 +1,162 @@ +import { Component, Input, Output, EventEmitter } from '@angular/core'; +import Storage from '@aws-amplify/storage'; +import { NotificationService } from 'src/app/services/notification.service'; +import { CompressorService } from 'src/app/services/compressor.service'; + +@Component({ + selector: 'app-avatar', + templateUrl: './avatar.component.html', + styleUrls: ['./avatar.component.scss'] +}) +export class AvatarComponent { + + photoUrl: string; + hasPhoto = false; + uploading = false; + s3ImageFile: any = null; + s3ImagePath = 'avatar'; + errorMessage: string; + previewClass = 'app-avatar-upload'; + + private storageOptionsHolder: any = { level: 'private' }; + private previewClassIdle = 'app-avatar-upload'; + private previewClassOver = 'app-avatar-upload-dragover'; + + @Input() + set url(url: string) { + this.photoUrl = url; + this.hasPhoto = true; + } + + @Input() + set storageOptions(storageOptions: any) { + this.storageOptionsHolder = Object.assign(this.storageOptionsHolder, storageOptions); + } + + @Input() + set path(path: string) { + this.s3ImagePath = path; + } + + @Input() + set data(data: any) { + this.photoUrl = data.url; + this.s3ImagePath = data.path; + this.storageOptionsHolder = Object.assign(this.storageOptionsHolder, data.storageOptions); + this.hasPhoto = true; + } + + @Output() + picked: EventEmitter = new EventEmitter(); + + @Output() + loaded: EventEmitter = new EventEmitter(); + + @Output() + uploaded: EventEmitter = new EventEmitter(); + + @Output() + removed: EventEmitter = new EventEmitter(); + + constructor( private notification: NotificationService, + private compressor: CompressorService ) {} + + pick(evt) { + let file = null; + if (evt.target.files) { + file = evt.target.files[0]; + } + if (!file && evt.dataTransfer.files) { + file = evt.dataTransfer.files[0]; + } + if (!file) { return; } + const isImage = file.type.split('/')[0] === 'image'; + if (!isImage) { + this.previewClass = this.previewClassIdle; + return this.notification.show('Only images are allowed.'); + } + if (!this.storageOptionsHolder.contentType) { + this.storageOptionsHolder.contentType = file.type; + } + // console.log('file size: ', file.size); + this.picked.emit(file); + this.compressor.compress(file).subscribe( + () => { + const { name, size, type } = file; + // console.log('compressed size: ', size, name, type); + const fileName = file.name.split('.'); + const fileExt = fileName[fileName.length - 1]; + this.s3ImagePath = `${this.s3ImagePath}/picture.${fileExt}`; + this.s3ImageFile = file; + const that = this; + const reader = new FileReader(); + reader.onload = (e) => { + const target: any = e.target; + const url = target.result; + that.photoUrl = url; + that.hasPhoto = true; + that.loaded.emit(url); + that.uploadFile(); + }; + reader.readAsDataURL(file); + } + ); + } + + uploadFile() { + this.uploading = true; + Storage.put( + this.s3ImagePath, + this.s3ImageFile, this.storageOptionsHolder) + .then ( (result: any) => { + this.uploaded.emit(result); + this.completeFileUpload(); + }) + .catch( error => { + this.completeFileUpload(error); + console.log('error uploading image'); + }); + } + + completeFileUpload(error?: any) { + if (error) { + console.log('error completeing upload'); + return this._setError(error); + } + this.uploading = false; + } + + onPhotoError() { + this.hasPhoto = false; + } + + onAlertClose() { + this._setError(null); + } + + onDrop(event) { + event.preventDefault(); + this.pick(event); + } + + onDragover(event: DragEvent) { + event.stopPropagation(); + event.preventDefault(); + this.previewClass = this.previewClassOver; + } + + onDragout(event: DragEvent) { + event.stopPropagation(); + event.preventDefault(); + this.previewClass = this.previewClassIdle; + } + + _setError(err) { + if (!err) { + this.errorMessage = null; + return; + } + this.errorMessage = err.message || err; + } + +} diff --git a/Website/HPIoTWebApp/src/app/auth/profile/profile.component.html b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.html new file mode 100644 index 0000000..4600838 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.html @@ -0,0 +1,38 @@ +
+

My Account

+
+ + + Enter your first name + + + + + Enter your last name + + + + + + + + + True + False + + + +
+ + + +
+ + + +
+
\ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/profile/profile.component.scss b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.scss new file mode 100644 index 0000000..63119af --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.scss @@ -0,0 +1,26 @@ +.container { + width: 100%; +} +form { + width: 100%; +} + +form > * { + margin-bottom: 1.5em; + width: 100%; +} + +.cursor-pointer { + cursor: pointer; +} + +.signout { + float: right; +} + +@media (min-width: 900px) { + .container { + margin: 0 auto; + width: 75%; + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/profile/profile.component.spec.ts b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.spec.ts new file mode 100644 index 0000000..692b234 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProfileComponent } from './profile.component'; + +describe('ProfileComponent', () => { + let component: ProfileComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ProfileComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ProfileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/profile/profile.component.ts b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.ts new file mode 100644 index 0000000..72ec5c4 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/profile/profile.component.ts @@ -0,0 +1,117 @@ +import { Component, OnInit } from '@angular/core'; +import { AuthService } from '../auth.service'; +import { Router } from '@angular/router'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; +import Auth, { CognitoUser } from '@aws-amplify/auth'; +import Storage from '@aws-amplify/storage'; +import { NotificationService } from 'src/app/services/notification.service'; +import { LoaderService } from 'src/app/loader/loader.service'; + +@Component({ + selector: 'app-profile', + templateUrl: './profile.component.html', + styleUrls: ['./profile.component.scss'] +}) +export class ProfileComponent implements OnInit { + profileForm: FormGroup = new FormGroup({ + email: new FormControl('', [ Validators.email ]), + phone: new FormControl('', [ Validators.min(10) ]), + fname: new FormControl('', [ Validators.min(2) ]), + lname: new FormControl('', [ Validators.min(2) ]), + 'custom:holiday': new FormControl('', [Validators.min(1)]) + }); + currentAvatarUrl: string; + avatar: string; + deleteAvatar = false; + profile: any = {}; + user: CognitoUser; + + get emailInput() { return this.profileForm.get('email'); } + get fnameInput() { return this.profileForm.get('fname'); } + get lnameInput() { return this.profileForm.get('lname'); } + get phoneInput() { return this.profileForm.get('phone'); } + get holidayInput() { return this.profileForm.get('custom:holiday'); } + + constructor( + private authService: AuthService, + private router: Router, + private notification: NotificationService, + public loading: LoaderService ) { } + + ngOnInit() { + this.loading.show(); + this.getUserInfo(); + } + + async getUserInfo() { + this.profile = await Auth.currentUserInfo(); + this.user = await Auth.currentAuthenticatedUser(); + // console.log(this.profile); + if ( this.profile.attributes.profile ) { + this.avatar = this.profile.attributes.profile; + this.currentAvatarUrl = await Storage.vault.get(this.avatar) as string; + } + this.fnameInput.setValue(this.profile.attributes.given_name); + this.lnameInput.setValue(this.profile.attributes.family_name); + this.phoneInput.setValue(this.profile.attributes.phone_number); + this.holidayInput.setValue(String(this.profile.attributes['custom:holiday'])); + this.loading.hide(); + } + + getEmailInputError() { + if (this.emailInput.hasError('email')) { + return 'Please enter a valid email address.'; + } + if (this.emailInput.hasError('required')) { + return 'An Email is required.'; + } + } + + signOut() { + this.authService.signOut() + .then(() => this.router.navigate(['auth/signin'])); + } + + onAvatarUploadStart() { + // this.loading.show(); + // console.log(this.loading); + } + onAvatarUploadComplete(data: any) { + this.avatar = data.key; + this.loading.hide(); + } + + onAvatarRemove() { + this.avatar = undefined; + this.currentAvatarUrl = undefined; + this.deleteAvatar = true; + } + + async editProfile() { + try { + const attributes = { + given_name: this.fnameInput.value, + family_name: this.lnameInput.value, + phone_number: this.phoneInput.value, + profile: this.profile.value, + 'custom:holiday': this.holidayInput.value + }; + if (this.avatar) { + attributes.profile = this.avatar; + } + console.log(attributes); + await Auth.updateUserAttributes(this.user, attributes); + if (!this.avatar && this.deleteAvatar) { + this.user.deleteAttributes(['profile'], (error) => { + if (error) { console.log(error); } + this.notification.show('Your profile information has been updated.'); + }); + } else { + this.notification.show('Your profile information has been updated.'); + } + } catch (error) { + console.log(error); + } + } + +} diff --git a/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.html b/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.html new file mode 100644 index 0000000..385d36c --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.html @@ -0,0 +1,23 @@ +
+

Sign in to your account

+ + + Enter your email address + + {{getEmailInputError()}} + + + + + {{hide ? 'visibility_off' : 'visibility'}} + Enter your password + + {{getPasswordInputError()}} + + + + +

Don't have an account? Sign up

+
diff --git a/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.scss b/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.spec.ts b/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.spec.ts new file mode 100644 index 0000000..e5fe8d3 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SignInComponent } from './sign-in.component'; + +describe('SignInComponent', () => { + let component: SignInComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SignInComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SignInComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.ts b/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.ts new file mode 100644 index 0000000..3c5e46b --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/sign-in/sign-in.component.ts @@ -0,0 +1,80 @@ +import { Component } from '@angular/core'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; +import { AuthService } from '../auth.service'; +import { CognitoUser } from '@aws-amplify/auth'; +import { NotificationService } from 'src/app/services/notification.service'; +import { Router } from '@angular/router'; +import { environment } from 'src/environments/environment'; +import { LoaderService } from 'src/app/loader/loader.service'; + +@Component({ + selector: 'app-sign-in', + templateUrl: './sign-in.component.html', + styleUrls: ['./sign-in.component.scss'] +}) +export class SignInComponent { + + signinForm: FormGroup = new FormGroup({ + email: new FormControl('', [ Validators.email, Validators.required ]), + password: new FormControl('', [ Validators.required, Validators.min(6) ]) + }); + + hide = true; + + get emailInput() { return this.signinForm.get('email'); } + get passwordInput() { return this.signinForm.get('password'); } + + constructor( + public auth: AuthService, + private notification: NotificationService, + private router: Router, + private loader: LoaderService ) { } + + getEmailInputError() { + if (this.emailInput.hasError('email')) { + return 'Please enter a valid email address.'; + } + if (this.emailInput.hasError('required')) { + return 'An Email is required.'; + } + } + + getPasswordInputError() { + if (this.passwordInput.hasError('required')) { + return 'A password is required.'; + } + } + + signIn() { + this.loader.show(); + this.auth.signIn(this.emailInput.value, this.passwordInput.value) + .then((user: CognitoUser|any) => { + this.loader.hide(); + this.router.navigate(['']); + }) + .catch((error: any) => { + this.loader.hide(); + this.notification.show(error.message); + switch (error.code) { + case 'UserNotConfirmedException': + environment.confirm.email = this.emailInput.value; + environment.confirm.password = this.passwordInput.value; + this.router.navigate(['auth/confirm']); + break; + case 'UsernameExistsException': + this.router.navigate(['auth/signin']); + break; + } + }); + } + + /* async signInWithFacebook() { + const socialResult = await this.auth.socialSignIn(AuthService.FACEBOOK); + console.log('fb Result:', socialResult); + } + + async signInWithGoogle() { + const socialResult = await this.auth.socialSignIn(AuthService.GOOGLE); + console.log('google Result:', socialResult); + } */ +} diff --git a/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.html b/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.html new file mode 100644 index 0000000..8b22e09 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.html @@ -0,0 +1,27 @@ +
+

Create a new account

+ + + Enter your email address + + + {{ countryCode }}   + + mode_edit + + + + Enter your first name + + + + Enter your last name + + + + {{hide ? 'visibility_off' : 'visibility'}} + Enter your password + + +

Already have an account? Sign In

+
\ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.scss b/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.spec.ts b/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.spec.ts new file mode 100644 index 0000000..24c0a1c --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SignUpComponent } from './sign-up.component'; + +describe('SignUpComponent', () => { + let component: SignUpComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SignUpComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SignUpComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.ts b/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.ts new file mode 100644 index 0000000..fea6269 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/sign-up/sign-up.component.ts @@ -0,0 +1,92 @@ +import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; +import { MatBottomSheet } from '@angular/material/bottom-sheet'; +import { CountryCodeSelectComponent } from '../country-code-select/country-code-select.component'; +import { CountryCode } from '../country-code-select/country-codes'; +import { AuthService } from '../auth.service'; +import { environment } from 'src/environments/environment'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-sign-up', + templateUrl: './sign-up.component.html', + styleUrls: ['./sign-up.component.scss'] +}) +export class SignUpComponent implements OnInit { + hide = true; + signupForm: FormGroup = new FormGroup({ + email: new FormControl('', [ Validators.email, Validators.required ]), + password: new FormControl('', [ Validators.required ]), + phone: new FormControl('', [ Validators.min(10) ]), + fname: new FormControl('', [ Validators.min(2) ]), + lname: new FormControl('', [ Validators.min(2) ]) + }); + + countryCode = '+1'; + + get emailInput() { return this.signupForm.get('email'); } + get passwordInput() { return this.signupForm.get('password'); } + get fnameInput() { return this.signupForm.get('fname'); } + get lnameInput() { return this.signupForm.get('lname'); } + get phoneInput() { return this.signupForm.get('phone'); } + + constructor( + private _bottomSheet: MatBottomSheet, + private _authService: AuthService, + private _router: Router ) { + + } + + ngOnInit() { + } + + selectCountryCode() { + this._bottomSheet.open(CountryCodeSelectComponent) + .afterDismissed() + .subscribe( + (data: CountryCode) => { + this.countryCode = (data) ? data.dial_code : this.countryCode; + } + ); + } + + getEmailInputError() { + if (this.emailInput.hasError('email')) { + return 'Please enter a valid email address.'; + } + if (this.emailInput.hasError('required')) { + return 'An Email is required.'; + } + } + + getPasswordInputError() { + if (this.passwordInput.hasError('required')) { + return 'A password is required.'; + } + } + + shouldEnableSubmit() { + return !this.emailInput.valid || + !this.passwordInput.valid || + !this.fnameInput.valid || + !this.lnameInput.valid || + !this.phoneInput.valid; + } + + signUp() { + this._authService.signUp({ + "email": this.emailInput.value, + "password": this.passwordInput.value, + "firstName": this.fnameInput.value, + "lastName": this.lnameInput.value, + "phone": this.countryCode + this.phoneInput.value + }) + .then((data) => { + environment.confirm.email = this.emailInput.value; + environment.confirm.password = this.passwordInput.value; + this._router.navigate(['auth/confirm']); + }) + .catch((error) => console.log(error)); + } + +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/auth/unauth.guard.spec.ts b/Website/HPIoTWebApp/src/app/auth/unauth.guard.spec.ts new file mode 100644 index 0000000..202c0f4 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/unauth.guard.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, async, inject } from '@angular/core/testing'; + +import { UnauthGuard } from './unauth.guard'; + +describe('UnauthGuard', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [UnauthGuard] + }); + }); + + it('should ...', inject([UnauthGuard], (guard: UnauthGuard) => { + expect(guard).toBeTruthy(); + })); +}); diff --git a/Website/HPIoTWebApp/src/app/auth/unauth.guard.ts b/Website/HPIoTWebApp/src/app/auth/unauth.guard.ts new file mode 100644 index 0000000..57faf6b --- /dev/null +++ b/Website/HPIoTWebApp/src/app/auth/unauth.guard.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { + CanActivate, + ActivatedRouteSnapshot, + RouterStateSnapshot, + Router } from '@angular/router'; +import { Observable } from 'rxjs'; +import Auth from '@aws-amplify/auth'; + +@Injectable({ + providedIn: 'root' +}) +export class UnauthGuard implements CanActivate { + constructor( private _router: Router ) { } + canActivate( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean { + return Auth.currentAuthenticatedUser() + .then(() => { + this._router.navigate(['auth/profile']); + return false; + }) + .catch(() => { + return true; + }); + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/configs/configs.component.html b/Website/HPIoTWebApp/src/app/configs/configs.component.html new file mode 100644 index 0000000..6ee3cef --- /dev/null +++ b/Website/HPIoTWebApp/src/app/configs/configs.component.html @@ -0,0 +1,83 @@ +
+

Configuration

+
+ + + + + {{option}} + + + + +
+ + + Device {{i + 1}} + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + Tag {{j+1}} + + + + +
+ + + + + + + + + + + + + + + + + + + CLX + Micro800 + + +
+ +
+
+
+ + + +
+
+ +
+
diff --git a/Website/HPIoTWebApp/src/app/configs/configs.component.scss b/Website/HPIoTWebApp/src/app/configs/configs.component.scss new file mode 100644 index 0000000..00d9fa1 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/configs/configs.component.scss @@ -0,0 +1,32 @@ +.container { + width: 100%; +} +form { + width: 100%; +} +mat-form-field { + padding: .25em; +} + +mat-card-actions { + display: flex; + justify-self: right; +} +.DataPoint { + padding: .5em; +} +form > * { + margin-bottom: 1.5em; + width: 100%; +} + +.cursor-pointer { + cursor: pointer; +} + +@media (min-width: 900px) { + .container { + margin: 0 auto; + width: 75%; + } +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/app/configs/configs.component.spec.ts b/Website/HPIoTWebApp/src/app/configs/configs.component.spec.ts new file mode 100644 index 0000000..ceea4aa --- /dev/null +++ b/Website/HPIoTWebApp/src/app/configs/configs.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConfigsComponent } from './configs.component'; + +describe('ConfigsComponent', () => { + let component: ConfigsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ConfigsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfigsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/configs/configs.component.ts b/Website/HPIoTWebApp/src/app/configs/configs.component.ts new file mode 100644 index 0000000..8fa7c2e --- /dev/null +++ b/Website/HPIoTWebApp/src/app/configs/configs.component.ts @@ -0,0 +1,172 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, FormArray } from '@angular/forms'; +import { Observable } from 'rxjs'; +import {map, startWith} from 'rxjs/operators'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; + +export interface Config { + [key: string]: any; +} + +@Component({ + selector: 'app-configs', + templateUrl: './configs.component.html', + styleUrls: ['./configs.component.scss'] +}) +export class ConfigsComponent implements OnInit { + + constructor(private builder: FormBuilder, private http: HttpClient) { } + + get certificateIDInput() { return this.configForm.get('certificateID'); } + get devicesArray() { return this.configForm.get('devices') as FormArray; } + configDownloaded: Config; + configForm = this.builder.group({ + certificateID: '', + devices: new FormArray([]) + }); + // Setup an API call to get the list of certificate IDs from DDB to store in options + options: string[]; + + filteredOptions: Observable; + + ngOnInit() { + this.getCertList(); + } + getCertList() { + const httpOptions = { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }; + const certList = this.http.get('https://4ax24ru9ra.execute-api.us-east-1.amazonaws.com/Gamma/HPIoTgetCertList/', httpOptions); + + certList.subscribe( + data => { + this.options = data as string[]; + // console.log(data); + this.filteredOptions = this.certificateIDInput.valueChanges.pipe( + startWith(''), + map(value => this._filter(value)) + ); + }, + (err) => console.log(err) + ); + + } + plcArray(i) { return this.configForm.get('devices.' + i + '.PLCData') as FormArray; } + private _filter(value: string): string[] { + const filterValue = value.toLowerCase(); + return this.options.filter(option => option.toLowerCase().includes(filterValue)); + } + onSelect(e) { + // console.log(e.target.innerText.slice(1, -1)); + if (this.certificateIDInput !== e.target.innerText.slice(1, -1)) { + this.configForm.controls.certificateID.setValue(e.target.innerText.slice(1, -1)); + this.onCertificateChange(); + } + } + buildForms() { + const numberOfDevices = Object.keys(this.configDownloaded).length - 2; + // console.log(numberOfDevices); + this.devicesArray.clear(); + for (let i = this.devicesArray.length; i < numberOfDevices; i++) { + this.devicesArray.push(this.builder.group({ + appname: this.configDownloaded['device' + (i + 1).toString()].appname, + certificateID: this.configDownloaded['device' + (i + 1).toString()].certificateID, + company: this.configDownloaded['device' + (i + 1).toString()].company, + location: this.configDownloaded['device' + (i + 1).toString()].locationID, + field: this.configDownloaded['device' + (i + 1).toString()].field, + devicetype: this.configDownloaded['device' + (i + 1).toString()].deviceType, + PLCData: new FormArray([]), + modbusdata: new FormArray([]), + currentdata: new FormArray([]), + voltagedata: new FormArray([]) + })); + if (this.configDownloaded['device' + (i + 1).toString()].PLCData !== 'empty') { + for (let j = 1; j - 1 < Object.keys(this.configDownloaded['device' + (i + 1).toString()].PLCData).length; j++ ) { + this.plcArray(i).push(this.builder.group({ + plcIP: this.configDownloaded['device' + (i + 1).toString()].PLCData['tag' + j.toString()].plcIP, + tag: this.configDownloaded['device' + (i + 1).toString()].PLCData['tag' + j.toString()].tag, + name: this.configDownloaded['device' + (i + 1).toString()].PLCData['tag' + j.toString()].name, + changeThreshold: this.configDownloaded['device' + (i + 1).toString()].PLCData['tag' + j.toString()].changeThreshold, + guaranteed: this.configDownloaded['device' + (i + 1).toString()].PLCData['tag' + j.toString()].guaranteed, + plcType: this.configDownloaded['device' + (i + 1).toString()].PLCData['tag' + j.toString()].plcType, + })); + } + } + } + } + onCertificateChange() { + // console.log(this.certificateIDInput.value); + const httpOptions = { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }; + const config = this.http.get('https://4ax24ru9ra.execute-api.us-east-1.amazonaws.com/Gamma/HPIoTgetConfig/?certificateID=' + + this.certificateIDInput.value, httpOptions); + config.subscribe( + data => {this.configDownloaded = data; console.log(this.configDownloaded); this.buildForms(); }, + (err) => console.log(err) + ); + } + + addDataPoint(e) { + this.plcArray(e).push(this.builder.group({ + plcIP: '', + tag: '', + name: '', + changeThreshold: '', + guaranteed: '', + plcType: '' + })); + } + + removeDataPoint(i, j) { + this.plcArray(i).removeAt(j); + } + + addDevice() { + this.devicesArray.push(this.builder.group({ + appname: '', + certificateID: '', + company: '', + location: '', + field: '', + devicetype: '', + PLCData: new FormArray([]), + modbusdata: new FormArray([]), + currentdata: new FormArray([]), + voltagedata: new FormArray([]) + })); + } + + removeDevice(e) { + this.devicesArray.removeAt(e); + } + + saveConfig() { + const formObj = this.configForm.getRawValue(); + const devices = formObj.devices; + let j = 1; + devices.forEach(device => { + let i = 1; + const plcdata = {}; + device.PLCData.forEach(element => { + plcdata['tag' + i] = element; + i++; + }); + device.PLCData = plcdata; + formObj['device' + j.toString()] = device; + j++; + }); + delete formObj.devices; + formObj.version = this.configDownloaded.version + 1; + const serialized = JSON.stringify(formObj); + this.http.post('https://4ax24ru9ra.execute-api.us-east-1.amazonaws.com/Gamma/postConfig/', serialized) + .subscribe( + data => console.log('success!', data), + error => console.error('couldn\'t post because', error) + ); + } +} diff --git a/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.html b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.html new file mode 100644 index 0000000..81172c9 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.html @@ -0,0 +1,4 @@ +
+
+
+ diff --git a/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.scss b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.scss new file mode 100644 index 0000000..2329e3f --- /dev/null +++ b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.scss @@ -0,0 +1,31 @@ +.message { + width: 250px; +} +.container { + display: inline-block; + width: fit-content; + height: fit-content; + padding: 15px; +} +.viewer { + width: 100%; + height: 100%; +} +.flex-spacer { + flex-grow: 1; +} +table { + width: 100%; + } + +.mat-form-field { + font-size: 14px; + width: 100%; +} +th.mat-sort-header-sorted { + color: black; + } + +#charts { + display: flexbox; +} diff --git a/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.spec.ts b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.spec.ts new file mode 100644 index 0000000..9c996c3 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DashboardComponent } from './dashboard.component'; + +describe('DashboardComponent', () => { + let component: DashboardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DashboardComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DashboardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.ts b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.ts new file mode 100644 index 0000000..26e1f88 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/dashboard/dashboard.component.ts @@ -0,0 +1,124 @@ +import { Component, OnInit } from '@angular/core'; +import { Chart } from 'chart.js'; +import { DataService, AWSData } from '../services/data.service'; +import { CdkDropList } from '@angular/cdk/drag-drop'; +@Component({ + selector: 'app-home', + templateUrl: './dashboard.component.html', + styleUrls: ['./dashboard.component.scss'] +}) + +export class DashboardComponent implements OnInit { + + constructor(private dataservice: DataService) { } + + title = 'Bar Chart'; + charts: Array; + messages: Array = []; + charttypes = ['bar', 'line']; + userCharts = { + 'arn:aws:iam::860246592755:role/HPIoT_CrownQuest_User': { + 'chart-0': { + type: 'bar', + data: { + labels: ['Horton 20 WS 9-8', 'Horton 20 WS 9-7', 'Horton 20 WS 10-20', 'Horton 20 WS 10-20'].sort((a, b) => a.localeCompare(b)), + datasets: [{ + label: 'Horton', + data: { + 'Horton 20 WS 9-7': ['volumeflow'], + 'Horton 20 WS 10-20': ['pressure', 'depth'], + 'Horton 20 WS 9-8': ['volumeflow'] + } + }] + } + }, + 'chart-1': { + type: 'line', + data: { + labels: ['LimeQuest 5 WS 1-1', 'Wilkinson 34 WS 2-2', 'Horton 20 WS 10-20'].sort((a, b) => a.localeCompare(b)), + datasets: [{ + label: 'Horton', + data: { + 'LimeQuest 5 WS 1-1': ['depth'], + 'Horton 20 WS 10-20': ['pressure'], + 'Wilkinson 34 WS 2-2': ['current'] + } + }] + } + } + }, + 'arn:aws:iam::860246592755:role/HPIoT_QEP_User': { + 'chart-0': { + type: 'radar', + data: { + labels: ['Frequency', 'Pressure', 'Current', 'Down Hole'], + datasets: [{ + label: 'POE 1', + data: { + 'POE 1': ['frequency', 'pressure', 'current', 'down_hole_level'] + }}] + } + } + } + }; + ngOnInit() { + this.dataservice.roleSubject.subscribe(() => { + this.initCharts(); + }); + this.initCharts(); + this.dataservice.message.subscribe((data) => { + this.messages = data; + // console.log(this.messages); + this.populate(); + }); + } + getData(req) { + const x = []; + this.messages.forEach(location => { + if (Object.keys(req).indexOf(location.location) > -1) { + req[location.location].forEach((ele) => { + x.push(location[ele]); + }); + } + }); + return x; + } + initCharts() { + document.getElementById('charts').innerHTML = ''; + this.charts = new Array(); + Object.keys(this.userCharts[this.dataservice.currentRole]).forEach( key => { + const chart = document.createElement('canvas'); + chart.id = key; + chart.style.width = '100%'; + chart.style.height = '25rem'; + document.getElementById('charts').appendChild(chart); + this.charts.push(new Chart(document.getElementById(key), { + type: this.userCharts[this.dataservice.currentRole][key].type, + data: { + labels: this.userCharts[this.dataservice.currentRole][key].data.labels, + datasets: [{ + label: this.userCharts[this.dataservice.currentRole][key].data.datasets.label, + data: [] + }] + } + })); + }); + } + populate() { + this.charts.forEach(element => { + element.type = this.userCharts[this.dataservice.currentRole][element.canvas.id].type; + element.data.labels = this.userCharts[this.dataservice.currentRole][element.canvas.id].data.labels; + element.data.datasets.forEach( (dataset, ind) => { + dataset.label = this.userCharts[this.dataservice.currentRole][element.canvas.id].data.datasets[ind].label; + dataset.data = this.getData(this.userCharts[this.dataservice.currentRole][element.canvas.id].data.datasets[ind].data); + dataset.backgroundColor = dataset.data.map((item, index) => 'rgba(' + + index * (255 / dataset.data.length) + ',' + + 0 + ',' + + (dataset.data.length - index) * (255 / dataset.data.length) + ',' + '0.8)'); + }); + element.update(); + }); + } +} + + diff --git a/Website/HPIoTWebApp/src/app/loader/loader.component.html b/Website/HPIoTWebApp/src/app/loader/loader.component.html new file mode 100644 index 0000000..420fbd6 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/loader/loader.component.html @@ -0,0 +1,4 @@ +
+ +

{{message}}

+
diff --git a/Website/HPIoTWebApp/src/app/loader/loader.component.scss b/Website/HPIoTWebApp/src/app/loader/loader.component.scss new file mode 100644 index 0000000..f70bfb6 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/loader/loader.component.scss @@ -0,0 +1,7 @@ +.loader > * { + text-align: center; + margin: 0 auto; +} +.loader p { + margin-top: 1em; +} diff --git a/Website/HPIoTWebApp/src/app/loader/loader.component.spec.ts b/Website/HPIoTWebApp/src/app/loader/loader.component.spec.ts new file mode 100644 index 0000000..35adf49 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/loader/loader.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoaderComponent } from './loader.component'; + +describe('LoaderComponent', () => { + let component: LoaderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LoaderComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/loader/loader.component.ts b/Website/HPIoTWebApp/src/app/loader/loader.component.ts new file mode 100644 index 0000000..c98d3e4 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/loader/loader.component.ts @@ -0,0 +1,24 @@ +import { Component, OnInit, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; + +@Component({ + selector: 'app-loader', + templateUrl: './loader.component.html', + styleUrls: ['./loader.component.scss'] +}) +export class LoaderComponent implements OnInit { + + message = 'Please wait...'; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: any + ) { + if (data.message) { + this.message = data.message; + } + } + + ngOnInit() { + } + +} diff --git a/Website/HPIoTWebApp/src/app/loader/loader.service.spec.ts b/Website/HPIoTWebApp/src/app/loader/loader.service.spec.ts new file mode 100644 index 0000000..ff3167a --- /dev/null +++ b/Website/HPIoTWebApp/src/app/loader/loader.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { LoaderService } from './loader.service'; + +describe('LoaderService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: LoaderService = TestBed.get(LoaderService); + expect(service).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/loader/loader.service.ts b/Website/HPIoTWebApp/src/app/loader/loader.service.ts new file mode 100644 index 0000000..1e50f34 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/loader/loader.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { LoaderComponent } from './loader.component'; + +@Injectable({ + providedIn: 'root' +}) +export class LoaderService { + loading: boolean; + dialogRef: MatDialogRef; + constructor( private dialog: MatDialog ) { } + + show(message: string = 'Please wait...'): void { + setTimeout(() => { + this.loading = true; + this.dialogRef = this.dialog.open(LoaderComponent, { + width: '80%', + data: { message }, + closeOnNavigation: true + }); + }); + } + + hide() { + if (this.dialogRef) { + this.dialogRef.close(); + this.loading = false; + } + } +} diff --git a/Website/HPIoTWebApp/src/app/material/material.module.ts b/Website/HPIoTWebApp/src/app/material/material.module.ts new file mode 100644 index 0000000..bf2c2f6 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/material/material.module.ts @@ -0,0 +1,81 @@ +import { NgModule } from '@angular/core'; +import { CdkTableModule } from '@angular/cdk/table'; +import { CdkTreeModule } from '@angular/cdk/tree'; +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { MatAutocompleteModule } from '@angular/material/autocomplete'; +import { MatBadgeModule } from '@angular/material/badge'; +import { MatBottomSheetModule } from '@angular/material/bottom-sheet'; +import { MatButtonModule } from '@angular/material/button'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { MatCardModule } from '@angular/material/card'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatNativeDateModule, MatRippleModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatGridListModule } from '@angular/material/grid-list'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatListModule } from '@angular/material/list'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatSliderModule } from '@angular/material/slider'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatSortModule } from '@angular/material/sort'; +import { MatStepperModule } from '@angular/material/stepper'; +import { MatTableModule } from '@angular/material/table'; +import { MatTabsModule } from '@angular/material/tabs'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatTreeModule } from '@angular/material/tree'; +@NgModule({ + exports: [ + CdkTableModule, + CdkTreeModule, + DragDropModule, + MatAutocompleteModule, + MatBadgeModule, + MatBottomSheetModule, + MatButtonModule, + MatButtonToggleModule, + MatCardModule, + MatCheckboxModule, + MatChipsModule, + MatStepperModule, + MatDatepickerModule, + MatDialogModule, + MatDividerModule, + MatExpansionModule, + MatGridListModule, + MatIconModule, + MatInputModule, + MatListModule, + MatMenuModule, + MatNativeDateModule, + MatPaginatorModule, + MatProgressBarModule, + MatProgressSpinnerModule, + MatRadioModule, + MatRippleModule, + MatSelectModule, + MatSidenavModule, + MatSliderModule, + MatSlideToggleModule, + MatSnackBarModule, + MatSortModule, + MatTableModule, + MatTabsModule, + MatToolbarModule, + MatTooltipModule, + MatTreeModule, + ] +}) +export class MaterialModule { } diff --git a/Website/HPIoTWebApp/src/app/services/compressor.service.spec.ts b/Website/HPIoTWebApp/src/app/services/compressor.service.spec.ts new file mode 100644 index 0000000..c0572fb --- /dev/null +++ b/Website/HPIoTWebApp/src/app/services/compressor.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { CompressorService } from './compressor.service'; + +describe('CompressorService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: CompressorService = TestBed.get(CompressorService); + expect(service).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/services/compressor.service.ts b/Website/HPIoTWebApp/src/app/services/compressor.service.ts new file mode 100644 index 0000000..0bb43c9 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/services/compressor.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core'; +import { Observable} from 'rxjs'; +@Injectable({ + providedIn: 'root' +}) +export class CompressorService { + + constructor() { } + compress(file: File): Observable { + const width = 128; // For scaling relative to width + const reader = new FileReader(); + reader.readAsDataURL(file); + return new Observable(observer => { + reader.onload = ev => { + const img = new Image(); + img.src = (ev.target as any).result; + (img.onload = () => { + const elem = document.createElement('canvas'); // Use Angular's Renderer2 method + const scaleFactor = width / img.width; + elem.width = width; + elem.height = img.height * scaleFactor; + const ctx = elem.getContext('2d') as CanvasRenderingContext2D; + ctx.drawImage(img, 0, 0, width, img.height * scaleFactor); + ctx.canvas.toBlob( + blob => { + observer.next( + new File([blob], file.name, { + type: file.type, + lastModified: Date.now(), + }), + ); + }, + file.type, + 1, + ); + }), + (reader.onerror = error => observer.error(error)); + }; + }); + } +} diff --git a/Website/HPIoTWebApp/src/app/services/data.service.spec.ts b/Website/HPIoTWebApp/src/app/services/data.service.spec.ts new file mode 100644 index 0000000..38e8d9e --- /dev/null +++ b/Website/HPIoTWebApp/src/app/services/data.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { DataService } from './data.service'; + +describe('DataService', () => { + let service: DataService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(DataService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/services/data.service.ts b/Website/HPIoTWebApp/src/app/services/data.service.ts new file mode 100644 index 0000000..7fa70a5 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/services/data.service.ts @@ -0,0 +1,122 @@ +import { Injectable } from '@angular/core'; +import Auth from '@aws-amplify/auth'; +import { WebSocketSubject } from 'rxjs/webSocket'; +import { Observable, Subject, BehaviorSubject } from 'rxjs'; +import { PassThrough } from 'stream'; +export interface AWSData { + [key: string]: any; +} + +@Injectable({ + providedIn: 'root' +}) + + +export class DataService { + public serverMessages: Array = []; + public message = new BehaviorSubject(this.serverMessages); + private socket$: WebSocketSubject; + totalFlowRate = 0; + private roles: string[]; + private groups: string[]; + public currentRole: string; + public roleSubject = new Subject(); + private token: string; + + constructor() { + Auth.currentAuthenticatedUser().then(data => { + // console.log(data); + this.roles = data.signInUserSession.idToken.payload['cognito:roles']; + this.groups = data.signInUserSession.idToken.payload['cognito:groups']; + this.groups.forEach( (element, index, array) => { + array[index] = element.replace(/_/g, ' '); + }); + this.currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0]; + this.token = data.signInUserSession.accessToken.jwtToken; + this.message.subscribe({ + next: d => d + }); + this.roleSubject.subscribe({ + next: r => r + }); + this.connect(); + }).catch((err) => + err + ); + } + + startUp() { + Auth.currentAuthenticatedUser().then(data => { + // console.log(data); + this.roles = data.signInUserSession.idToken.payload['cognito:roles']; + this.groups = data.signInUserSession.idToken.payload['cognito:groups']; + this.groups.forEach( (element, index, array) => { + array[index] = element.replace(/_/g, ' '); + }); + this.currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0]; + this.token = data.signInUserSession.accessToken.jwtToken; + this.message.subscribe({ + next: d => d + }); + this.roleSubject.subscribe({ + next: r => r + }); + this.connect(); + }).catch((error) => console.log(error)); + } + + connect() { + this.connectWS(this.token, this.currentRole); + this.subscribeWS(); + this.socket$.next({action: 'getDashboardData', policy: this.currentRole}); + } + + connectWS(token: string, role: string) { + this.socket$ = new WebSocketSubject('wss://3fseaywb8b.execute-api.us-east-1.amazonaws.com/prototype?token=' + token + + '&role=' + role); + // console.log(this.socket$); + } + + subscribeWS() { + this.socket$.subscribe((message) => { + // console.log(message); + if (message instanceof Array) { + message.forEach(element => { + this.updateList(element); + }); + } else { + this.updateList(message); + } + // console.log(this.serverMessages); + this.serverMessages.sort((a, b) => a.location.localeCompare(b.location)); + this.message.next(this.serverMessages); + }, + (err) => console.error(err), + () => console.warn('Complete: Websocket closed') + ); + } + + updateList(obj: AWSData) { + // console.log(this.serverMessages); + // console.log(obj); + const index = this.serverMessages.findIndex((e) => e.location === obj.location); + + if (index === -1) { + this.serverMessages.push(obj); + + } else { + Object.keys(obj).forEach(element => { + this.serverMessages[index][element] = obj[element]; + }); + } + } + + setRole(index: number) { + this.currentRole = this.roles[index]; + this.roleSubject.next(this.currentRole); + this.socket$.complete(); + this.serverMessages = []; + this.connect(); + } + +} diff --git a/Website/HPIoTWebApp/src/app/services/notification.service.spec.ts b/Website/HPIoTWebApp/src/app/services/notification.service.spec.ts new file mode 100644 index 0000000..698c421 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/services/notification.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { NotificationService } from './notification.service'; + +describe('NotificationService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: NotificationService = TestBed.get(NotificationService); + expect(service).toBeTruthy(); + }); +}); diff --git a/Website/HPIoTWebApp/src/app/services/notification.service.ts b/Website/HPIoTWebApp/src/app/services/notification.service.ts new file mode 100644 index 0000000..e4fde06 --- /dev/null +++ b/Website/HPIoTWebApp/src/app/services/notification.service.ts @@ -0,0 +1,57 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { MatSnackBar, MatSnackBarRef } from '@angular/material/snack-bar'; +import { Subscription } from 'rxjs'; + +/** + * Provides an abstract wrapper around showing a MatSnackbar + * notification based on global environment or API provided + * configuration. + * + * This class Listens for the authentication state to change. + * Once the state becomes authenticated, retrieve the startup + * configuration from the API service. Once de-authenticated + * set the _params to undefined and unsubscribe. + */ +@Injectable({ + providedIn: 'root' +}) +export class NotificationService implements OnDestroy { + + // Configuration api subscription + private _configState: Subscription; + /** + * Constructor + * @param toast {MatSnackBar} + * @param configService {ConfigurationService} + */ + constructor( + private toast: MatSnackBar) {} + + /** + * Unsubscribe from the config state + * when the component is destroyed, and remove + * the in-memory parameters. + */ + ngOnDestroy() { + this._configState.unsubscribe(); + } + + /** + * Display a MatSnackbar notification and return the reference. + * Will set the duration to the global configuration if present. + * @param message {string} + * @param buttonLabel {string} + * @returns {MatSnackBarRef} + */ + show(message: string, buttonLabel: string = 'OK'): MatSnackBarRef { + const toastTimeout = 8000; + if (toastTimeout > 0) { + return this.toast.open(message, buttonLabel, { + duration: toastTimeout + }); + } else { + return this.toast.open(message, buttonLabel, { + }); + } + } +} diff --git a/Website/HPIoTWebApp/src/assets/.gitkeep b/Website/HPIoTWebApp/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Website/HPIoTWebApp/src/assets/icons/icon-128x128.png b/Website/HPIoTWebApp/src/assets/icons/icon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..bf60b767459710a96c7cb90065abbf33a3c5c67a GIT binary patch literal 2743 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 literal 0 HcmV?d00001 diff --git a/Website/HPIoTWebApp/src/assets/icons/icon-192x192.png b/Website/HPIoTWebApp/src/assets/icons/icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..cb69621b56f2f3f595d8a6cc6cad30c71b0eefca GIT binary patch literal 3859 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 BJ}CeI literal 0 HcmV?d00001 diff --git a/Website/HPIoTWebApp/src/assets/icons/icon-384x384.png b/Website/HPIoTWebApp/src/assets/icons/icon-384x384.png new file mode 100644 index 0000000000000000000000000000000000000000..90661888523b34e31f8640bded629bd0d0e0beda GIT binary patch literal 7279 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 literal 0 HcmV?d00001 diff --git a/Website/HPIoTWebApp/src/assets/icons/icon-512x512.png b/Website/HPIoTWebApp/src/assets/icons/icon-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..ee16098a5a4cc218efd6f91d0b09ef439b9d2bb2 GIT binary patch literal 9498 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 W2p4sy7+*gC0000hlsCqI6(A? zh{m8GGy$=_)kg?H9W~b=8DH~3VW_X2^#N}TI*0PJv-^SWKrUj6^D%92+>f};AIvNy zpi{{RA+9hb*P866pS+)O!{14)A4&EjMj!9#v2s4d;NP#amRjVNfuEUgswa>ebmD{8 z57i~Vs{146jKL4_I?)e413j;Z%uBZ|>#*AnIhaEZS2Bd;DlI{Q)!_DzZH(B zahPX6e;5mzz2b(ee6X*9kNfwWzv7>D_^;>xKi2>JBj=Aj8s(Jj@Z;#(wC-MsNXN9L(^ + + + + Henry Pump SCADA + + + + + + + + + + + + + + diff --git a/Website/HPIoTWebApp/src/main.ts b/Website/HPIoTWebApp/src/main.ts new file mode 100644 index 0000000..1fd8237 --- /dev/null +++ b/Website/HPIoTWebApp/src/main.ts @@ -0,0 +1,21 @@ + +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +// Amplify Config +import Auth from '@aws-amplify/auth'; +import Storage from '@aws-amplify/storage'; +import AWSConfig from './aws-exports'; +Storage.configure(AWSConfig); +Auth.configure(AWSConfig); + + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/Website/HPIoTWebApp/src/manifest.webmanifest b/Website/HPIoTWebApp/src/manifest.webmanifest new file mode 100644 index 0000000..f66e8a7 --- /dev/null +++ b/Website/HPIoTWebApp/src/manifest.webmanifest @@ -0,0 +1,51 @@ +{ + "name": "HPIoTWebApp", + "short_name": "HPIoTWebApp", + "theme_color": "#1976d2", + "background_color": "#fafafa", + "display": "standalone", + "scope": "/", + "start_url": "/", + "icons": [ + { + "src": "assets/icons/icon-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "assets/icons/icon-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "assets/icons/icon-128x128.png", + "sizes": "128x128", + "type": "image/png" + }, + { + "src": "assets/icons/icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "assets/icons/icon-152x152.png", + "sizes": "152x152", + "type": "image/png" + }, + { + "src": "assets/icons/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "assets/icons/icon-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "assets/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} \ No newline at end of file diff --git a/Website/HPIoTWebApp/src/polyfills.ts b/Website/HPIoTWebApp/src/polyfills.ts new file mode 100644 index 0000000..c303cf5 --- /dev/null +++ b/Website/HPIoTWebApp/src/polyfills.ts @@ -0,0 +1,64 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +(window as any).global = window; +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/Website/HPIoTWebApp/src/styles.scss b/Website/HPIoTWebApp/src/styles.scss new file mode 100644 index 0000000..7e7239a --- /dev/null +++ b/Website/HPIoTWebApp/src/styles.scss @@ -0,0 +1,4 @@ +/* You can add global styles to this file, and also import other style files */ + +html, body { height: 100%; } +body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } diff --git a/Website/HPIoTWebApp/src/test.ts b/Website/HPIoTWebApp/src/test.ts new file mode 100644 index 0000000..1631789 --- /dev/null +++ b/Website/HPIoTWebApp/src/test.ts @@ -0,0 +1,20 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/Website/HPIoTWebApp/tsconfig.app.json b/Website/HPIoTWebApp/tsconfig.app.json new file mode 100644 index 0000000..45f325a --- /dev/null +++ b/Website/HPIoTWebApp/tsconfig.app.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": ["node"] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/test.ts", + "src/**/*.spec.ts" + ] +} diff --git a/Website/HPIoTWebApp/tsconfig.json b/Website/HPIoTWebApp/tsconfig.json new file mode 100644 index 0000000..30956ae --- /dev/null +++ b/Website/HPIoTWebApp/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "module": "esnext", + "moduleResolution": "node", + "importHelpers": true, + "target": "es2015", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + }, + "angularCompilerOptions": { + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true + } +} diff --git a/Website/HPIoTWebApp/tsconfig.spec.json b/Website/HPIoTWebApp/tsconfig.spec.json new file mode 100644 index 0000000..6400fde --- /dev/null +++ b/Website/HPIoTWebApp/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/Website/HPIoTWebApp/tslint.json b/Website/HPIoTWebApp/tslint.json new file mode 100644 index 0000000..f0adae9 --- /dev/null +++ b/Website/HPIoTWebApp/tslint.json @@ -0,0 +1,92 @@ +{ + "extends": "tslint:recommended", + "rules": { + "array-type": false, + "arrow-parens": false, + "deprecation": { + "severity": "warning" + }, + "component-class-suffix": true, + "contextual-lifecycle": true, + "directive-class-suffix": true, + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ], + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "interface-name": false, + "max-classes-per-file": false, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-consecutive-blank-lines": false, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-empty": false, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-switch-case-fall-through": true, + "no-use-before-declare": true, + "no-var-requires": false, + "object-literal-key-quotes": [ + true, + "as-needed" + ], + "object-literal-sort-keys": false, + "ordered-imports": false, + "quotemark": [ + true, + "single" + ], + "trailing-comma": false, + "no-conflicting-lifecycle": true, + "no-host-metadata-property": true, + "no-input-rename": true, + "no-inputs-metadata-property": true, + "no-output-native": true, + "no-output-on-prefix": true, + "no-output-rename": true, + "no-outputs-metadata-property": true, + "template-banana-in-box": true, + "template-no-negated-async": true, + "use-lifecycle-interface": true, + "use-pipe-transform-interface": true + }, + "rulesDirectory": [ + "codelyzer" + ] +} \ No newline at end of file diff --git a/Website/hpiot-react/.gitignore b/Website/hpiot-react/.gitignore new file mode 100644 index 0000000..448863b --- /dev/null +++ b/Website/hpiot-react/.gitignore @@ -0,0 +1,24 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + diff --git a/Website/hpiot-react/README.md b/Website/hpiot-react/README.md new file mode 100644 index 0000000..54ef094 --- /dev/null +++ b/Website/hpiot-react/README.md @@ -0,0 +1,68 @@ +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `npm start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+You will also see any lint errors in the console. + +### `npm test` + +Launches the test runner in the interactive watch mode.
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `npm run build` + +Builds the app for production to the `build` folder.
+It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `npm run eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting + +### Analyzing the Bundle Size + +This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size + +### Making a Progressive Web App + +This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app + +### Advanced Configuration + +This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration + +### Deployment + +This section has moved here: https://facebook.github.io/create-react-app/docs/deployment + +### `npm run build` fails to minify + +This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify diff --git a/Website/hpiot-react/amplify/#current-cloud-backend/amplify-meta.json b/Website/hpiot-react/amplify/#current-cloud-backend/amplify-meta.json new file mode 100644 index 0000000..cc42911 --- /dev/null +++ b/Website/hpiot-react/amplify/#current-cloud-backend/amplify-meta.json @@ -0,0 +1,56 @@ +{ + "providers": { + "awscloudformation": { + "AuthRoleName": "amplify-hpiot-react-hpiot-162610-authRole", + "UnauthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-unauthRole", + "AuthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-authRole", + "Region": "us-east-1", + "DeploymentBucketName": "amplify-hpiot-react-hpiot-162610-deployment", + "UnauthRoleName": "amplify-hpiot-react-hpiot-162610-unauthRole", + "StackName": "amplify-hpiot-react-hpiot-162610", + "StackId": "arn:aws:cloudformation:us-east-1:860246592755:stack/amplify-hpiot-react-hpiot-162610/1913c1f0-64a8-11ea-baa2-0ee5b74c6229", + "AmplifyAppId": "d3hyexpjn33q6q" + } + }, + "hosting": { + "S3AndCloudFront": { + "service": "S3AndCloudFront", + "providerPlugin": "awscloudformation", + "providerMetadata": { + "s3TemplateURL": "https://s3.amazonaws.com/amplify-hpiot-react-hpiot-162610-deployment/amplify-cfn-templates/hosting/template.json", + "logicalId": "hostingS3AndCloudFront" + }, + "lastPushTimeStamp": "2020-03-12T21:33:05.218Z", + "output": { + "S3BucketSecureURL": "https://hpiot-react-hpiot.s3.amazonaws.com", + "WebsiteURL": "http://hpiot-react-hpiot.s3-website-us-east-1.amazonaws.com", + "Region": "us-east-1", + "HostingBucketName": "hpiot-react-hpiot" + }, + "lastPushDirHash": "NulnbGKP8lFEe2FacQkja5CAJcc=" + } + }, + "auth": { + "hpiotreact8c9024fb": { + "service": "Cognito", + "providerPlugin": "awscloudformation", + "dependsOn": [], + "customAuth": false, + "providerMetadata": { + "s3TemplateURL": "https://s3.amazonaws.com/amplify-hpiot-react-hpiot-162610-deployment/amplify-cfn-templates/auth/hpiotreact8c9024fb-cloudformation-template.yml", + "logicalId": "authhpiotreact8c9024fb" + }, + "lastPushTimeStamp": "2020-03-12T21:33:05.218Z", + "output": { + "AppClientSecret": "msldgo1telohjsm20p8nn58f15iensrjup7cb1712tirkcrooou", + "UserPoolId": "us-east-1_L6XsGIASX", + "AppClientIDWeb": "63ieddff77nfc3i151m8l8k3ip", + "AppClientID": "3b1gubo57cng5p2avotsgr75ji", + "IdentityPoolId": "us-east-1:20972146-c6fe-4ada-a723-d1debcc7d074", + "IdentityPoolName": "hpiotreact8c9024fb_identitypool_8c9024fb__hpiot", + "UserPoolName": "hpiotreact8c9024fb_userpool_8c9024fb" + }, + "lastPushDirHash": "UsD33D5D2jMU3hAfHMEhFJOINGM=" + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml b/Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml new file mode 100644 index 0000000..0159d22 --- /dev/null +++ b/Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml @@ -0,0 +1,369 @@ +AWSTemplateFormatVersion: 2010-09-09 + +Parameters: + env: + Type: String + authRoleArn: + Type: String + unauthRoleArn: + Type: String + + + + + identityPoolName: + Type: String + + allowUnauthenticatedIdentities: + Type: String + + resourceNameTruncated: + Type: String + + userPoolName: + Type: String + + autoVerifiedAttributes: + Type: CommaDelimitedList + + mfaConfiguration: + Type: String + + mfaTypes: + Type: CommaDelimitedList + + smsAuthenticationMessage: + Type: String + + smsVerificationMessage: + Type: String + + emailVerificationSubject: + Type: String + + emailVerificationMessage: + Type: String + + defaultPasswordPolicy: + Type: String + + passwordPolicyMinLength: + Type: Number + + passwordPolicyCharacters: + Type: CommaDelimitedList + + requiredAttributes: + Type: CommaDelimitedList + + userpoolClientGenerateSecret: + Type: String + + userpoolClientRefreshTokenValidity: + Type: Number + + userpoolClientWriteAttributes: + Type: CommaDelimitedList + + userpoolClientReadAttributes: + Type: CommaDelimitedList + + userpoolClientLambdaRole: + Type: String + + userpoolClientSetAttributes: + Type: String + + resourceName: + Type: String + + authSelections: + Type: String + + useDefault: + Type: String + + usernameAttributes: + Type: CommaDelimitedList + + userPoolGroupList: + Type: CommaDelimitedList + + dependsOn: + Type: CommaDelimitedList + +Conditions: + ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ] + +Resources: + + + # BEGIN SNS ROLE RESOURCE + SNSRole: + # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process + Type: AWS::IAM::Role + Properties: + RoleName: !If [ShouldNotCreateEnvResources, 'hpiotr8c9024fb_sns-role', !Join ['',[ 'sns', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "" + Effect: "Allow" + Principal: + Service: "cognito-idp.amazonaws.com" + Action: + - "sts:AssumeRole" + Condition: + StringEquals: + sts:ExternalId: hpiotr8c9024fb_role_external_id + Policies: + - + PolicyName: hpiotr8c9024fb-sns-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - + Effect: "Allow" + Action: + - "sns:Publish" + Resource: "*" + # BEGIN USER POOL RESOURCES + UserPool: + # Created upon user selection + # Depends on SNS Role for Arn if MFA is enabled + Type: AWS::Cognito::UserPool + UpdateReplacePolicy: Retain + Properties: + UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]] + + Schema: + + - + Name: email + Required: true + Mutable: true + + + + + AutoVerifiedAttributes: !Ref autoVerifiedAttributes + + + EmailVerificationMessage: !Ref emailVerificationMessage + EmailVerificationSubject: !Ref emailVerificationSubject + + Policies: + PasswordPolicy: + MinimumLength: !Ref passwordPolicyMinLength + RequireLowercase: false + RequireNumbers: false + RequireSymbols: false + RequireUppercase: false + + UsernameAttributes: !Ref usernameAttributes + + MfaConfiguration: !Ref mfaConfiguration + SmsVerificationMessage: !Ref smsVerificationMessage + SmsConfiguration: + SnsCallerArn: !GetAtt SNSRole.Arn + ExternalId: hpiotr8c9024fb_role_external_id + + + UserPoolClientWeb: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: hpiotr8c9024fb_app_clientWeb + + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + UserPoolClient: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: hpiotr8c9024fb_app_client + + GenerateSecret: !Ref userpoolClientGenerateSecret + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + # BEGIN USER POOL LAMBDA RESOURCES + UserPoolClientRole: + # Created to execute Lambda which gets userpool app client config values + Type: 'AWS::IAM::Role' + Properties: + RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - 'sts:AssumeRole' + DependsOn: UserPoolClient + UserPoolClientLambda: + # Lambda which gets userpool app client config values + # Depends on UserPool for id + # Depends on UserPoolClientRole for role ARN + Type: 'AWS::Lambda::Function' + Properties: + Code: + ZipFile: !Join + - |+ + - - 'const response = require(''cfn-response'');' + - 'const aws = require(''aws-sdk'');' + - 'const identity = new aws.CognitoIdentityServiceProvider();' + - 'exports.handler = (event, context, callback) => {' + - ' if (event.RequestType == ''Delete'') { ' + - ' response.send(event, context, response.SUCCESS, {})' + - ' }' + - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' + - ' const params = {' + - ' ClientId: event.ResourceProperties.clientId,' + - ' UserPoolId: event.ResourceProperties.userpoolId' + - ' };' + - ' identity.describeUserPoolClient(params).promise()' + - ' .then((res) => {' + - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});' + - ' })' + - ' .catch((err) => {' + - ' response.send(event, context, response.FAILED, {err});' + - ' });' + - ' }' + - '};' + Handler: index.handler + Runtime: nodejs10.x + Timeout: '300' + Role: !GetAtt + - UserPoolClientRole + - Arn + DependsOn: UserPoolClientRole + UserPoolClientLambdaPolicy: + # Sets userpool policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: hpiotr8c9024fb_userpoolclient_lambda_iam_policy + Roles: + - !Ref UserPoolClientRole + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - 'cognito-idp:DescribeUserPoolClient' + Resource: !GetAtt UserPool.Arn + DependsOn: UserPoolClientLambda + UserPoolClientLogPolicy: + # Sets log policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: hpiotr8c9024fb_userpoolclient_lambda_log_policy + Roles: + - !Ref UserPoolClientRole + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'logs:CreateLogGroup' + - 'logs:CreateLogStream' + - 'logs:PutLogEvents' + Resource: !Sub + - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* + - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda} + DependsOn: UserPoolClientLambdaPolicy + UserPoolClientInputs: + # Values passed to Userpool client Lambda + # Depends on UserPool for Id + # Depends on UserPoolClient for Id + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'Custom::LambdaCallout' + Properties: + ServiceToken: !GetAtt UserPoolClientLambda.Arn + clientId: !Ref UserPoolClient + userpoolId: !Ref UserPool + DependsOn: UserPoolClientLogPolicy + + + + + + + + # BEGIN IDENTITY POOL RESOURCES + + + IdentityPool: + # Always created + Type: AWS::Cognito::IdentityPool + Properties: + IdentityPoolName: !If [ShouldNotCreateEnvResources, 'hpiotreact8c9024fb_identitypool_8c9024fb', !Join ['',['hpiotreact8c9024fb_identitypool_8c9024fb', '__', !Ref env]]] + + CognitoIdentityProviders: + - ClientId: !Ref UserPoolClient + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + - ClientId: !Ref UserPoolClientWeb + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + + AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities + + + DependsOn: UserPoolClientInputs + + + IdentityPoolRoleMap: + # Created to map Auth and Unauth roles to the identity pool + # Depends on Identity Pool for ID ref + Type: AWS::Cognito::IdentityPoolRoleAttachment + Properties: + IdentityPoolId: !Ref IdentityPool + Roles: + unauthenticated: !Ref unauthRoleArn + authenticated: !Ref authRoleArn + DependsOn: IdentityPool + + +Outputs : + + IdentityPoolId: + Value: !Ref 'IdentityPool' + Description: Id for the identity pool + IdentityPoolName: + Value: !GetAtt IdentityPool.Name + + + + + UserPoolId: + Value: !Ref 'UserPool' + Description: Id for the user pool + UserPoolName: + Value: !Ref userPoolName + AppClientIDWeb: + Value: !Ref 'UserPoolClientWeb' + Description: The user pool app client id for web + AppClientID: + Value: !Ref 'UserPoolClient' + Description: The user pool app client id + AppClientSecret: + Value: !GetAtt UserPoolClientInputs.appSecret + + + + + + + diff --git a/Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/parameters.json b/Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/parameters.json new file mode 100644 index 0000000..a7b85a9 --- /dev/null +++ b/Website/hpiot-react/amplify/#current-cloud-backend/auth/hpiotreact8c9024fb/parameters.json @@ -0,0 +1,53 @@ +{ + "identityPoolName": "hpiotreact8c9024fb_identitypool_8c9024fb", + "allowUnauthenticatedIdentities": false, + "resourceNameTruncated": "hpiotr8c9024fb", + "userPoolName": "hpiotreact8c9024fb_userpool_8c9024fb", + "autoVerifiedAttributes": [ + "email" + ], + "mfaConfiguration": "OFF", + "mfaTypes": [ + "SMS Text Message" + ], + "smsAuthenticationMessage": "Your authentication code is {####}", + "smsVerificationMessage": "Your verification code is {####}", + "emailVerificationSubject": "Your verification code", + "emailVerificationMessage": "Your verification code is {####}", + "defaultPasswordPolicy": false, + "passwordPolicyMinLength": 8, + "passwordPolicyCharacters": [], + "requiredAttributes": [ + "email" + ], + "userpoolClientGenerateSecret": true, + "userpoolClientRefreshTokenValidity": 30, + "userpoolClientWriteAttributes": [ + "email" + ], + "userpoolClientReadAttributes": [ + "email" + ], + "userpoolClientLambdaRole": "hpiotr8c9024fb_userpoolclient_lambda_role", + "userpoolClientSetAttributes": false, + "resourceName": "hpiotreact8c9024fb", + "authSelections": "identityPoolAndUserPool", + "authRoleArn": { + "Fn::GetAtt": [ + "AuthRole", + "Arn" + ] + }, + "unauthRoleArn": { + "Fn::GetAtt": [ + "UnauthRole", + "Arn" + ] + }, + "useDefault": "default", + "usernameAttributes": [ + "email" + ], + "userPoolGroupList": [], + "dependsOn": [] +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/#current-cloud-backend/backend-config.json b/Website/hpiot-react/amplify/#current-cloud-backend/backend-config.json new file mode 100644 index 0000000..2694335 --- /dev/null +++ b/Website/hpiot-react/amplify/#current-cloud-backend/backend-config.json @@ -0,0 +1,16 @@ +{ + "hosting": { + "S3AndCloudFront": { + "service": "S3AndCloudFront", + "providerPlugin": "awscloudformation" + } + }, + "auth": { + "hpiotreact8c9024fb": { + "service": "Cognito", + "providerPlugin": "awscloudformation", + "dependsOn": [], + "customAuth": false + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/parameters.json b/Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/parameters.json new file mode 100644 index 0000000..629829f --- /dev/null +++ b/Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/parameters.json @@ -0,0 +1,3 @@ +{ + "bucketName": "hpiot-react" +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/template.json b/Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/template.json new file mode 100644 index 0000000..d98d689 --- /dev/null +++ b/Website/hpiot-react/amplify/#current-cloud-backend/hosting/S3AndCloudFront/template.json @@ -0,0 +1,113 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Hosting resource stack creation using Amplify CLI", + "Parameters": { + "env": { + "Type": "String" + }, + "bucketName": { + "Type": "String" + } + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + } + }, + "Resources": { + "S3Bucket": { + "Type": "AWS::S3::Bucket", + "DeletionPolicy": "Retain", + "Properties": { + "BucketName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + { + "Ref": "bucketName" + }, + { + "Fn::Join": [ + "", + [ + { + "Ref": "bucketName" + }, + "-", + { + "Ref": "env" + } + ] + ] + } + ] + }, + "AccessControl": "Private", + "WebsiteConfiguration": { + "IndexDocument": "index.html", + "ErrorDocument": "index.html" + }, + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedHeaders": [ + "Authorization", + "Content-Length" + ], + "AllowedMethods": [ + "GET" + ], + "AllowedOrigins": [ + "*" + ], + "MaxAge": 3000 + } + ] + } + } + } + }, + "Outputs": { + "Region": { + "Value": { + "Ref": "AWS::Region" + } + }, + "HostingBucketName": { + "Description": "Hosting bucket name", + "Value": { + "Ref": "S3Bucket" + } + }, + "WebsiteURL": { + "Value": { + "Fn::GetAtt": [ + "S3Bucket", + "WebsiteURL" + ] + }, + "Description": "URL for website hosted on S3" + }, + "S3BucketSecureURL": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "S3Bucket", + "DomainName" + ] + } + ] + ] + }, + "Description": "Name of S3 bucket to hold website content" + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/.config/local-aws-info.json b/Website/hpiot-react/amplify/.config/local-aws-info.json new file mode 100644 index 0000000..0f870d7 --- /dev/null +++ b/Website/hpiot-react/amplify/.config/local-aws-info.json @@ -0,0 +1,7 @@ +{ + "hpiot": { + "configLevel": "project", + "useProfile": true, + "profileName": "default" + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/.config/local-env-info.json b/Website/hpiot-react/amplify/.config/local-env-info.json new file mode 100644 index 0000000..c959c3e --- /dev/null +++ b/Website/hpiot-react/amplify/.config/local-env-info.json @@ -0,0 +1,5 @@ +{ + "projectPath": "/mnt/c/Users/Nico Melone/Documents/React Website/hpiot-react", + "defaultEditor": "vscode", + "envName": "hpiot" +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/.config/project-config.json b/Website/hpiot-react/amplify/.config/project-config.json new file mode 100644 index 0000000..15112a0 --- /dev/null +++ b/Website/hpiot-react/amplify/.config/project-config.json @@ -0,0 +1,17 @@ +{ + "projectName": "hpiot-react", + "version": "3.0", + "frontend": "javascript", + "javascript": { + "framework": "react", + "config": { + "SourceDir": "src", + "DistributionDir": "build", + "BuildCommand": "npm run-script build", + "StartCommand": "npm run-script start" + } + }, + "providers": [ + "awscloudformation" + ] +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/backend/amplify-meta.json b/Website/hpiot-react/amplify/backend/amplify-meta.json new file mode 100644 index 0000000..82968e7 --- /dev/null +++ b/Website/hpiot-react/amplify/backend/amplify-meta.json @@ -0,0 +1,56 @@ +{ + "providers": { + "awscloudformation": { + "AuthRoleName": "amplify-hpiot-react-hpiot-162610-authRole", + "UnauthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-unauthRole", + "AuthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-authRole", + "Region": "us-east-1", + "DeploymentBucketName": "amplify-hpiot-react-hpiot-162610-deployment", + "UnauthRoleName": "amplify-hpiot-react-hpiot-162610-unauthRole", + "StackName": "amplify-hpiot-react-hpiot-162610", + "StackId": "arn:aws:cloudformation:us-east-1:860246592755:stack/amplify-hpiot-react-hpiot-162610/1913c1f0-64a8-11ea-baa2-0ee5b74c6229", + "AmplifyAppId": "d3hyexpjn33q6q" + } + }, + "hosting": { + "S3AndCloudFront": { + "service": "S3AndCloudFront", + "providerPlugin": "awscloudformation", + "providerMetadata": { + "s3TemplateURL": "https://s3.amazonaws.com/amplify-hpiot-react-hpiot-162610-deployment/amplify-cfn-templates/hosting/template.json", + "logicalId": "hostingS3AndCloudFront" + }, + "lastPushTimeStamp": "2020-03-24T17:59:51.368Z", + "output": { + "S3BucketSecureURL": "https://hpiot-react-hpiot.s3.amazonaws.com", + "WebsiteURL": "http://hpiot-react-hpiot.s3-website-us-east-1.amazonaws.com", + "Region": "us-east-1", + "HostingBucketName": "hpiot-react-hpiot" + }, + "lastPushDirHash": "NulnbGKP8lFEe2FacQkja5CAJcc=" + } + }, + "auth": { + "hpiotreact8c9024fb": { + "service": "Cognito", + "providerPlugin": "awscloudformation", + "dependsOn": [], + "customAuth": false, + "providerMetadata": { + "s3TemplateURL": "https://s3.amazonaws.com/amplify-hpiot-react-hpiot-162610-deployment/amplify-cfn-templates/auth/hpiotreact8c9024fb-cloudformation-template.yml", + "logicalId": "authhpiotreact8c9024fb" + }, + "lastPushTimeStamp": "2020-03-24T17:59:51.373Z", + "output": { + "AppClientSecret": "msldgo1telohjsm20p8nn58f15iensrjup7cb1712tirkcrooou", + "UserPoolId": "us-east-1_L6XsGIASX", + "AppClientIDWeb": "63ieddff77nfc3i151m8l8k3ip", + "AppClientID": "3b1gubo57cng5p2avotsgr75ji", + "IdentityPoolId": "us-east-1:20972146-c6fe-4ada-a723-d1debcc7d074", + "IdentityPoolName": "hpiotreact8c9024fb_identitypool_8c9024fb__hpiot", + "UserPoolName": "hpiotreact8c9024fb_userpool_8c9024fb" + }, + "lastPushDirHash": "UsD33D5D2jMU3hAfHMEhFJOINGM=" + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml b/Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml new file mode 100644 index 0000000..0159d22 --- /dev/null +++ b/Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/hpiotreact8c9024fb-cloudformation-template.yml @@ -0,0 +1,369 @@ +AWSTemplateFormatVersion: 2010-09-09 + +Parameters: + env: + Type: String + authRoleArn: + Type: String + unauthRoleArn: + Type: String + + + + + identityPoolName: + Type: String + + allowUnauthenticatedIdentities: + Type: String + + resourceNameTruncated: + Type: String + + userPoolName: + Type: String + + autoVerifiedAttributes: + Type: CommaDelimitedList + + mfaConfiguration: + Type: String + + mfaTypes: + Type: CommaDelimitedList + + smsAuthenticationMessage: + Type: String + + smsVerificationMessage: + Type: String + + emailVerificationSubject: + Type: String + + emailVerificationMessage: + Type: String + + defaultPasswordPolicy: + Type: String + + passwordPolicyMinLength: + Type: Number + + passwordPolicyCharacters: + Type: CommaDelimitedList + + requiredAttributes: + Type: CommaDelimitedList + + userpoolClientGenerateSecret: + Type: String + + userpoolClientRefreshTokenValidity: + Type: Number + + userpoolClientWriteAttributes: + Type: CommaDelimitedList + + userpoolClientReadAttributes: + Type: CommaDelimitedList + + userpoolClientLambdaRole: + Type: String + + userpoolClientSetAttributes: + Type: String + + resourceName: + Type: String + + authSelections: + Type: String + + useDefault: + Type: String + + usernameAttributes: + Type: CommaDelimitedList + + userPoolGroupList: + Type: CommaDelimitedList + + dependsOn: + Type: CommaDelimitedList + +Conditions: + ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ] + +Resources: + + + # BEGIN SNS ROLE RESOURCE + SNSRole: + # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process + Type: AWS::IAM::Role + Properties: + RoleName: !If [ShouldNotCreateEnvResources, 'hpiotr8c9024fb_sns-role', !Join ['',[ 'sns', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "" + Effect: "Allow" + Principal: + Service: "cognito-idp.amazonaws.com" + Action: + - "sts:AssumeRole" + Condition: + StringEquals: + sts:ExternalId: hpiotr8c9024fb_role_external_id + Policies: + - + PolicyName: hpiotr8c9024fb-sns-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - + Effect: "Allow" + Action: + - "sns:Publish" + Resource: "*" + # BEGIN USER POOL RESOURCES + UserPool: + # Created upon user selection + # Depends on SNS Role for Arn if MFA is enabled + Type: AWS::Cognito::UserPool + UpdateReplacePolicy: Retain + Properties: + UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]] + + Schema: + + - + Name: email + Required: true + Mutable: true + + + + + AutoVerifiedAttributes: !Ref autoVerifiedAttributes + + + EmailVerificationMessage: !Ref emailVerificationMessage + EmailVerificationSubject: !Ref emailVerificationSubject + + Policies: + PasswordPolicy: + MinimumLength: !Ref passwordPolicyMinLength + RequireLowercase: false + RequireNumbers: false + RequireSymbols: false + RequireUppercase: false + + UsernameAttributes: !Ref usernameAttributes + + MfaConfiguration: !Ref mfaConfiguration + SmsVerificationMessage: !Ref smsVerificationMessage + SmsConfiguration: + SnsCallerArn: !GetAtt SNSRole.Arn + ExternalId: hpiotr8c9024fb_role_external_id + + + UserPoolClientWeb: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: hpiotr8c9024fb_app_clientWeb + + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + UserPoolClient: + # Created provide application access to user pool + # Depends on UserPool for ID reference + Type: "AWS::Cognito::UserPoolClient" + Properties: + ClientName: hpiotr8c9024fb_app_client + + GenerateSecret: !Ref userpoolClientGenerateSecret + RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity + UserPoolId: !Ref UserPool + DependsOn: UserPool + # BEGIN USER POOL LAMBDA RESOURCES + UserPoolClientRole: + # Created to execute Lambda which gets userpool app client config values + Type: 'AWS::IAM::Role' + Properties: + RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - 'sts:AssumeRole' + DependsOn: UserPoolClient + UserPoolClientLambda: + # Lambda which gets userpool app client config values + # Depends on UserPool for id + # Depends on UserPoolClientRole for role ARN + Type: 'AWS::Lambda::Function' + Properties: + Code: + ZipFile: !Join + - |+ + - - 'const response = require(''cfn-response'');' + - 'const aws = require(''aws-sdk'');' + - 'const identity = new aws.CognitoIdentityServiceProvider();' + - 'exports.handler = (event, context, callback) => {' + - ' if (event.RequestType == ''Delete'') { ' + - ' response.send(event, context, response.SUCCESS, {})' + - ' }' + - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' + - ' const params = {' + - ' ClientId: event.ResourceProperties.clientId,' + - ' UserPoolId: event.ResourceProperties.userpoolId' + - ' };' + - ' identity.describeUserPoolClient(params).promise()' + - ' .then((res) => {' + - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});' + - ' })' + - ' .catch((err) => {' + - ' response.send(event, context, response.FAILED, {err});' + - ' });' + - ' }' + - '};' + Handler: index.handler + Runtime: nodejs10.x + Timeout: '300' + Role: !GetAtt + - UserPoolClientRole + - Arn + DependsOn: UserPoolClientRole + UserPoolClientLambdaPolicy: + # Sets userpool policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: hpiotr8c9024fb_userpoolclient_lambda_iam_policy + Roles: + - !Ref UserPoolClientRole + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - 'cognito-idp:DescribeUserPoolClient' + Resource: !GetAtt UserPool.Arn + DependsOn: UserPoolClientLambda + UserPoolClientLogPolicy: + # Sets log policy for the role that executes the Userpool Client Lambda + # Depends on UserPool for Arn + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: hpiotr8c9024fb_userpoolclient_lambda_log_policy + Roles: + - !Ref UserPoolClientRole + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'logs:CreateLogGroup' + - 'logs:CreateLogStream' + - 'logs:PutLogEvents' + Resource: !Sub + - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* + - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda} + DependsOn: UserPoolClientLambdaPolicy + UserPoolClientInputs: + # Values passed to Userpool client Lambda + # Depends on UserPool for Id + # Depends on UserPoolClient for Id + # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing + Type: 'Custom::LambdaCallout' + Properties: + ServiceToken: !GetAtt UserPoolClientLambda.Arn + clientId: !Ref UserPoolClient + userpoolId: !Ref UserPool + DependsOn: UserPoolClientLogPolicy + + + + + + + + # BEGIN IDENTITY POOL RESOURCES + + + IdentityPool: + # Always created + Type: AWS::Cognito::IdentityPool + Properties: + IdentityPoolName: !If [ShouldNotCreateEnvResources, 'hpiotreact8c9024fb_identitypool_8c9024fb', !Join ['',['hpiotreact8c9024fb_identitypool_8c9024fb', '__', !Ref env]]] + + CognitoIdentityProviders: + - ClientId: !Ref UserPoolClient + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + - ClientId: !Ref UserPoolClientWeb + ProviderName: !Sub + - cognito-idp.${region}.amazonaws.com/${client} + - { region: !Ref "AWS::Region", client: !Ref UserPool} + + AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities + + + DependsOn: UserPoolClientInputs + + + IdentityPoolRoleMap: + # Created to map Auth and Unauth roles to the identity pool + # Depends on Identity Pool for ID ref + Type: AWS::Cognito::IdentityPoolRoleAttachment + Properties: + IdentityPoolId: !Ref IdentityPool + Roles: + unauthenticated: !Ref unauthRoleArn + authenticated: !Ref authRoleArn + DependsOn: IdentityPool + + +Outputs : + + IdentityPoolId: + Value: !Ref 'IdentityPool' + Description: Id for the identity pool + IdentityPoolName: + Value: !GetAtt IdentityPool.Name + + + + + UserPoolId: + Value: !Ref 'UserPool' + Description: Id for the user pool + UserPoolName: + Value: !Ref userPoolName + AppClientIDWeb: + Value: !Ref 'UserPoolClientWeb' + Description: The user pool app client id for web + AppClientID: + Value: !Ref 'UserPoolClient' + Description: The user pool app client id + AppClientSecret: + Value: !GetAtt UserPoolClientInputs.appSecret + + + + + + + diff --git a/Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/parameters.json b/Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/parameters.json new file mode 100644 index 0000000..a7b85a9 --- /dev/null +++ b/Website/hpiot-react/amplify/backend/auth/hpiotreact8c9024fb/parameters.json @@ -0,0 +1,53 @@ +{ + "identityPoolName": "hpiotreact8c9024fb_identitypool_8c9024fb", + "allowUnauthenticatedIdentities": false, + "resourceNameTruncated": "hpiotr8c9024fb", + "userPoolName": "hpiotreact8c9024fb_userpool_8c9024fb", + "autoVerifiedAttributes": [ + "email" + ], + "mfaConfiguration": "OFF", + "mfaTypes": [ + "SMS Text Message" + ], + "smsAuthenticationMessage": "Your authentication code is {####}", + "smsVerificationMessage": "Your verification code is {####}", + "emailVerificationSubject": "Your verification code", + "emailVerificationMessage": "Your verification code is {####}", + "defaultPasswordPolicy": false, + "passwordPolicyMinLength": 8, + "passwordPolicyCharacters": [], + "requiredAttributes": [ + "email" + ], + "userpoolClientGenerateSecret": true, + "userpoolClientRefreshTokenValidity": 30, + "userpoolClientWriteAttributes": [ + "email" + ], + "userpoolClientReadAttributes": [ + "email" + ], + "userpoolClientLambdaRole": "hpiotr8c9024fb_userpoolclient_lambda_role", + "userpoolClientSetAttributes": false, + "resourceName": "hpiotreact8c9024fb", + "authSelections": "identityPoolAndUserPool", + "authRoleArn": { + "Fn::GetAtt": [ + "AuthRole", + "Arn" + ] + }, + "unauthRoleArn": { + "Fn::GetAtt": [ + "UnauthRole", + "Arn" + ] + }, + "useDefault": "default", + "usernameAttributes": [ + "email" + ], + "userPoolGroupList": [], + "dependsOn": [] +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/backend/awscloudformation/nested-cloudformation-stack.yml b/Website/hpiot-react/amplify/backend/awscloudformation/nested-cloudformation-stack.yml new file mode 100644 index 0000000..3ce7bfe --- /dev/null +++ b/Website/hpiot-react/amplify/backend/awscloudformation/nested-cloudformation-stack.yml @@ -0,0 +1,371 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Root stack for the Amplify AWS CloudFormation provider", + "Parameters": { + "DeploymentBucketName": { + "Description": "Name of the common deployment bucket provided by the parent stack", + "Type": "String", + "Default": "DeploymentBucket" + }, + "AuthRoleName": { + "Type": "String", + "Default": "AuthRoleName" + }, + "UnauthRoleName": { + "Type": "String", + "Default": "UnauthRoleName" + } + }, + "Resources": { + "DeploymentBucket": { + "Type": "AWS::S3::Bucket", + "DeletionPolicy": "Retain", + "Properties": { + "BucketName": { + "Ref": "DeploymentBucketName" + } + } + }, + "AuthRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "RoleName": { + "Ref": "AuthRoleName" + }, + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Deny", + "Principal": { + "Federated": "cognito-identity.amazonaws.com" + }, + "Action": "sts:AssumeRoleWithWebIdentity" + } + ] + } + } + }, + "UnauthRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "RoleName": { + "Ref": "UnauthRoleName" + }, + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Deny", + "Principal": { + "Federated": "cognito-identity.amazonaws.com" + }, + "Action": "sts:AssumeRoleWithWebIdentity" + } + ] + } + } + }, + "hostingS3AndCloudFront": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": "https://s3.amazonaws.com/amplify-hpiot-react-hpiot-162610-deployment/amplify-cfn-templates/hosting/template.json", + "Parameters": { + "bucketName": "hpiot-react", + "env": "hpiot" + } + } + }, + "authhpiotreact8c9024fb": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": "https://s3.amazonaws.com/amplify-hpiot-react-hpiot-162610-deployment/amplify-cfn-templates/auth/hpiotreact8c9024fb-cloudformation-template.yml", + "Parameters": { + "identityPoolName": "hpiotwebapp78e5977f_identitypool_78e5977f", + "allowUnauthenticatedIdentities": false, + "resourceNameTruncated": "hpiotw78e5977f", + "userPoolName": "hpiotwebapp78e5977f_userpool_78e5977f", + "autoVerifiedAttributes": "email", + "mfaConfiguration": "OFF", + "mfaTypes": "SMS Text Message", + "smsAuthenticationMessage": "Your authentication code is {####}", + "smsVerificationMessage": "Your verification code is {####}", + "emailVerificationSubject": "Your verification code", + "emailVerificationMessage": "Your verification code is {####}", + "defaultPasswordPolicy": false, + "passwordPolicyMinLength": 8, + "passwordPolicyCharacters": "", + "requiredAttributes": "email", + "userpoolClientGenerateSecret": true, + "userpoolClientRefreshTokenValidity": 30, + "userpoolClientWriteAttributes": "email", + "userpoolClientReadAttributes": "email", + "userpoolClientLambdaRole": "hpiotw78e5977f_userpoolclient_lambda_role", + "userpoolClientSetAttributes": false, + "resourceName": "hpiotwebapp78e5977f", + "authSelections": "identityPoolAndUserPool", + "authRoleArn": { + "Fn::GetAtt": [ + "AuthRole", + "Arn" + ] + }, + "unauthRoleArn": { + "Fn::GetAtt": [ + "UnauthRole", + "Arn" + ] + }, + "useDefault": "default", + "usernameAttributes": "email, phone_number", + "dependsOn": "", + "env": "hpiot" + } + } + }, + "UpdateRolesWithIDPFunction": { + "DependsOn": [ + "AuthRole", + "UnauthRole", + "authhpiotreact8c9024fb" + ], + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": { + "Fn::Join": [ + "\n", + [ + "const response = require('cfn-response');", + "const aws = require('aws-sdk');", + "let responseData = {};", + "exports.handler = function(event, context) {", + " try {", + " let authRoleName = event.ResourceProperties.authRoleName;", + " let unauthRoleName = event.ResourceProperties.unauthRoleName;", + " let idpId = event.ResourceProperties.idpId;", + " let promises = [];", + " let authParamsJson = { 'Version': '2012-10-17','Statement': [{'Effect': 'Allow','Principal': {'Federated': 'cognito-identity.amazonaws.com'},'Action': 'sts:AssumeRoleWithWebIdentity','Condition': {'StringEquals': {'cognito-identity.amazonaws.com:aud': idpId},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'authenticated'}}}]};", + " let unauthParamsJson = { 'Version': '2012-10-17','Statement': [{'Effect': 'Allow','Principal': {'Federated': 'cognito-identity.amazonaws.com'},'Action': 'sts:AssumeRoleWithWebIdentity','Condition': {'StringEquals': {'cognito-identity.amazonaws.com:aud': idpId},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'unauthenticated'}}}]};", + " if (event.RequestType == 'Delete') {", + " delete authParamsJson.Statement.Condition;", + " delete unauthParamsJson.Statement.Condition;", + " let authParams = { PolicyDocument: JSON.stringify(authParamsJson),RoleName: authRoleName};", + " let unauthParams = {PolicyDocument: JSON.stringify(unauthParamsJson),RoleName: unauthRoleName};", + " const iam = new aws.IAM({ apiVersion: '2010-05-08', region: event.ResourceProperties.region});", + " promises.push(iam.updateAssumeRolePolicy(authParams).promise());", + " promises.push(iam.updateAssumeRolePolicy(unauthParams).promise());", + " Promise.all(promises)", + " .then((res) => {", + " console.log(\"delete response data\" + JSON.stringify(res));", + " response.send(event, context, response.SUCCESS, {});", + " });", + " }", + " if (event.RequestType == 'Update' || event.RequestType == 'Create') {", + " const iam = new aws.IAM({ apiVersion: '2010-05-08', region: event.ResourceProperties.region});", + " let authParams = { PolicyDocument: JSON.stringify(authParamsJson),RoleName: authRoleName};", + " let unauthParams = {PolicyDocument: JSON.stringify(unauthParamsJson),RoleName: unauthRoleName};", + " promises.push(iam.updateAssumeRolePolicy(authParams).promise());", + " promises.push(iam.updateAssumeRolePolicy(unauthParams).promise());", + " Promise.all(promises)", + " .then((res) => {", + " console.log(\"createORupdate\" + res);", + " console.log(\"response data\" + JSON.stringify(res));", + " response.send(event, context, response.SUCCESS, {});", + " });", + " }", + " } catch(err) {", + " console.log(err.stack);", + " responseData = {Error: err};", + " response.send(event, context, response.FAILED, responseData);", + " throw err;", + " }", + "};" + ] + ] + } + }, + "Handler": "index.handler", + "Runtime": "nodejs10.x", + "Timeout": "300", + "Role": { + "Fn::GetAtt": [ + "UpdateRolesWithIDPFunctionRole", + "Arn" + ] + } + } + }, + "UpdateRolesWithIDPFunctionOutputs": { + "Type": "Custom::LambdaCallout", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "UpdateRolesWithIDPFunction", + "Arn" + ] + }, + "region": { + "Ref": "AWS::Region" + }, + "idpId": { + "Fn::GetAtt": [ + "authhpiotreact8c9024fb", + "Outputs.IdentityPoolId" + ] + }, + "authRoleName": { + "Ref": "AuthRoleName" + }, + "unauthRoleName": { + "Ref": "UnauthRoleName" + } + } + }, + "UpdateRolesWithIDPFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "RoleName": { + "Fn::Join": [ + "", + [ + { + "Ref": "AuthRoleName" + }, + "-idp" + ] + ] + }, + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + }, + "Policies": [ + { + "PolicyName": "UpdateRolesWithIDPFunctionPolicy", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource": "arn:aws:logs:*:*:*" + }, + { + "Effect": "Allow", + "Action": "iam:UpdateAssumeRolePolicy", + "Resource": { + "Fn::GetAtt": [ + "AuthRole", + "Arn" + ] + } + }, + { + "Effect": "Allow", + "Action": "iam:UpdateAssumeRolePolicy", + "Resource": { + "Fn::GetAtt": [ + "UnauthRole", + "Arn" + ] + } + } + ] + } + } + ] + } + } + }, + "Outputs": { + "Region": { + "Description": "CloudFormation provider root stack Region", + "Value": { + "Ref": "AWS::Region" + }, + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-Region" + } + } + }, + "StackName": { + "Description": "CloudFormation provider root stack ID", + "Value": { + "Ref": "AWS::StackName" + }, + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-StackName" + } + } + }, + "StackId": { + "Description": "CloudFormation provider root stack name", + "Value": { + "Ref": "AWS::StackId" + }, + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-StackId" + } + } + }, + "DeploymentBucketName": { + "Description": "CloudFormation provider root stack deployment bucket name", + "Value": { + "Ref": "DeploymentBucketName" + }, + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-DeploymentBucketName" + } + } + }, + "AuthRoleArn": { + "Value": { + "Fn::GetAtt": [ + "AuthRole", + "Arn" + ] + } + }, + "UnauthRoleArn": { + "Value": { + "Fn::GetAtt": [ + "UnauthRole", + "Arn" + ] + } + }, + "AuthRoleName": { + "Value": { + "Ref": "AuthRole" + } + }, + "UnauthRoleName": { + "Value": { + "Ref": "UnauthRole" + } + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/backend/backend-config.json b/Website/hpiot-react/amplify/backend/backend-config.json new file mode 100644 index 0000000..2694335 --- /dev/null +++ b/Website/hpiot-react/amplify/backend/backend-config.json @@ -0,0 +1,16 @@ +{ + "hosting": { + "S3AndCloudFront": { + "service": "S3AndCloudFront", + "providerPlugin": "awscloudformation" + } + }, + "auth": { + "hpiotreact8c9024fb": { + "service": "Cognito", + "providerPlugin": "awscloudformation", + "dependsOn": [], + "customAuth": false + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/parameters.json b/Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/parameters.json new file mode 100644 index 0000000..629829f --- /dev/null +++ b/Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/parameters.json @@ -0,0 +1,3 @@ +{ + "bucketName": "hpiot-react" +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/template.json b/Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/template.json new file mode 100644 index 0000000..d98d689 --- /dev/null +++ b/Website/hpiot-react/amplify/backend/hosting/S3AndCloudFront/template.json @@ -0,0 +1,113 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "Hosting resource stack creation using Amplify CLI", + "Parameters": { + "env": { + "Type": "String" + }, + "bucketName": { + "Type": "String" + } + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + } + }, + "Resources": { + "S3Bucket": { + "Type": "AWS::S3::Bucket", + "DeletionPolicy": "Retain", + "Properties": { + "BucketName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + { + "Ref": "bucketName" + }, + { + "Fn::Join": [ + "", + [ + { + "Ref": "bucketName" + }, + "-", + { + "Ref": "env" + } + ] + ] + } + ] + }, + "AccessControl": "Private", + "WebsiteConfiguration": { + "IndexDocument": "index.html", + "ErrorDocument": "index.html" + }, + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedHeaders": [ + "Authorization", + "Content-Length" + ], + "AllowedMethods": [ + "GET" + ], + "AllowedOrigins": [ + "*" + ], + "MaxAge": 3000 + } + ] + } + } + } + }, + "Outputs": { + "Region": { + "Value": { + "Ref": "AWS::Region" + } + }, + "HostingBucketName": { + "Description": "Hosting bucket name", + "Value": { + "Ref": "S3Bucket" + } + }, + "WebsiteURL": { + "Value": { + "Fn::GetAtt": [ + "S3Bucket", + "WebsiteURL" + ] + }, + "Description": "URL for website hosted on S3" + }, + "S3BucketSecureURL": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "S3Bucket", + "DomainName" + ] + } + ] + ] + }, + "Description": "Name of S3 bucket to hold website content" + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/amplify/team-provider-info.json b/Website/hpiot-react/amplify/team-provider-info.json new file mode 100644 index 0000000..3d764dc --- /dev/null +++ b/Website/hpiot-react/amplify/team-provider-info.json @@ -0,0 +1,20 @@ +{ + "hpiot": { + "awscloudformation": { + "AuthRoleName": "amplify-hpiot-react-hpiot-162610-authRole", + "UnauthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-unauthRole", + "AuthRoleArn": "arn:aws:iam::860246592755:role/amplify-hpiot-react-hpiot-162610-authRole", + "Region": "us-east-1", + "DeploymentBucketName": "amplify-hpiot-react-hpiot-162610-deployment", + "UnauthRoleName": "amplify-hpiot-react-hpiot-162610-unauthRole", + "StackName": "amplify-hpiot-react-hpiot-162610", + "StackId": "arn:aws:cloudformation:us-east-1:860246592755:stack/amplify-hpiot-react-hpiot-162610/1913c1f0-64a8-11ea-baa2-0ee5b74c6229", + "AmplifyAppId": "d3hyexpjn33q6q" + }, + "categories": { + "auth": { + "hpiotreact8c9024fb": {} + } + } + } +} \ No newline at end of file diff --git a/Website/hpiot-react/package-lock.json b/Website/hpiot-react/package-lock.json new file mode 100644 index 0000000..8a9b461 --- /dev/null +++ b/Website/hpiot-react/package-lock.json @@ -0,0 +1,19010 @@ +{ + "name": "hpiot-react", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@aws-amplify/analytics": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-2.2.6.tgz", + "integrity": "sha512-k9aNdeEVNugEgeRQDRtXxqoeqe0MQKWlVglHu1LLfN47Ux8EtGG8m1119MiGVol7eh58/+ZUL1fErNiZf26wWg==", + "requires": { + "@aws-amplify/cache": "^2.1.6", + "@aws-amplify/core": "^2.2.5", + "uuid": "^3.2.1" + } + }, + "@aws-amplify/api": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@aws-amplify/api/-/api-2.1.6.tgz", + "integrity": "sha512-Q3LUgscgkpJwK+tl9Ibc1asbSjyzb6IGxkodSNig8ieCXsX/bLpbsStBATl92pnDyCR6q3CDcewd09E4jEqlSQ==", + "requires": { + "@aws-amplify/auth": "^2.1.6", + "@aws-amplify/cache": "^2.1.6", + "@aws-amplify/core": "^2.2.5", + "axios": "^0.19.0", + "graphql": "14.0.0", + "uuid": "^3.2.1", + "zen-observable": "^0.8.6" + } + }, + "@aws-amplify/auth": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@aws-amplify/auth/-/auth-2.1.6.tgz", + "integrity": "sha512-8D5qtzuS3iiTUQk193fR5mztvOLWgk4kaVLMJG67kXWObCe1Rw73FAsCKRy1fqjSrT9z40c16eJso7m7YFBFRQ==", + "requires": { + "@aws-amplify/cache": "^2.1.6", + "@aws-amplify/core": "^2.2.5", + "amazon-cognito-identity-js": "^3.2.5", + "crypto-js": "3.1.9-1" + } + }, + "@aws-amplify/cache": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@aws-amplify/cache/-/cache-2.1.6.tgz", + "integrity": "sha512-muEix+GT5D8DiMOsOfEEe8rGouw4ZZIB/MT9qJxRDy0lsmF/CSkpqTtn/ES2m+bux8KH6EWXIedDle/+duFdZw==", + "requires": { + "@aws-amplify/core": "^2.2.5" + } + }, + "@aws-amplify/core": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@aws-amplify/core/-/core-2.2.5.tgz", + "integrity": "sha512-l5DxgdO/OmnXnhefOFQdMAfx3Q5PX7s3IB8odi3MB+KErtaUm6rOXAkYE8r9IASQdbYvf9Ea4OzeM8Ztpdw/CQ==", + "requires": { + "aws-sdk": "2.518.0", + "url": "^0.11.0", + "zen-observable": "^0.8.6" + } + }, + "@aws-amplify/interactions": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@aws-amplify/interactions/-/interactions-2.1.6.tgz", + "integrity": "sha512-qNOdVIjbCQ9FNtQAvMChIXSdADYLJd/hKtWc/viHQojqrb8qFMLjcVUMePlvxqrJoghbidYDYXX/icU/Z0pJGQ==", + "requires": { + "@aws-amplify/core": "^2.2.5" + } + }, + "@aws-amplify/predictions": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@aws-amplify/predictions/-/predictions-2.1.6.tgz", + "integrity": "sha512-1CZCUxz67M+nBXhALDeD7y4M/hCojzC7nR9GPIECZF4VIDjNNePUHtdit/3IgeEfoxA48ekhoZkcod6mdvy9bg==", + "requires": { + "@aws-amplify/core": "^2.2.5", + "@aws-amplify/storage": "^2.2.1", + "@aws-sdk/eventstream-marshaller": "0.1.0-preview.2", + "@aws-sdk/util-utf8-node": "0.1.0-preview.1", + "uuid": "^3.2.1" + } + }, + "@aws-amplify/pubsub": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@aws-amplify/pubsub/-/pubsub-2.1.7.tgz", + "integrity": "sha512-zVwJCBuhYNgPjFHUOkCbx7VEMWXvaiREdbnw6lk26lfXGd3Ot8gFY84e5DZEArZlg+gkuAzIEW3/eCCHD4BFVg==", + "requires": { + "@aws-amplify/auth": "^2.1.6", + "@aws-amplify/cache": "^2.1.6", + "@aws-amplify/core": "^2.2.5", + "graphql": "14.0.0", + "paho-mqtt": "^1.1.0", + "uuid": "^3.2.1", + "zen-observable": "^0.8.6" + } + }, + "@aws-amplify/storage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@aws-amplify/storage/-/storage-2.2.1.tgz", + "integrity": "sha512-dsHVj9ElzmYiy1kbomK4BNty2R4mV6CgLKAHQ/NwUtWRqT200dMNMfYD2Qvbjv8dL2XICalOV+t5VhPkwMBvJg==", + "requires": { + "@aws-amplify/core": "^2.2.5" + } + }, + "@aws-amplify/ui": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@aws-amplify/ui/-/ui-1.1.5.tgz", + "integrity": "sha512-lMC43ZsBMKXmsoZevk1EYESVEQh4jlcL4LSMTtHRC1CUrYPIf4EssqPkbMmJEvs3J+8JIcV5aOL5o5enBmaKug==" + }, + "@aws-amplify/xr": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@aws-amplify/xr/-/xr-1.1.6.tgz", + "integrity": "sha512-FneWKS1rCxH2HWHNv8b1RBRwakS1wVFt4UMlDT8jvXFZD6nzKXSmj2MoHvoGR97jn2PAxbUM1vSwHtzSl6wNkA==", + "requires": { + "@aws-amplify/core": "^2.2.5" + } + }, + "@aws-crypto/crc32": { + "version": "0.1.0-preview.4", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-0.1.0-preview.4.tgz", + "integrity": "sha512-Faxpmo6pUPvfwE8ELdJo9K9bdIjsra+AM2Cq2Fvydd4xJRHpKLWzQ3kdz324auMkHKbn4veTDo3sZRuSbh/Pug==", + "requires": { + "tslib": "^1.9.3" + } + }, + "@aws-sdk/eventstream-marshaller": { + "version": "0.1.0-preview.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-marshaller/-/eventstream-marshaller-0.1.0-preview.2.tgz", + "integrity": "sha512-StNivqLMGk+6Blp7eBYgLvidD9HEhthzNz7dBBAQPELx3Nd3imodzSvckDw5ZkuWt6ViP+aAl8HgQvJmD71M5Q==", + "requires": { + "@aws-crypto/crc32": "^0.1.0-preview.1", + "@aws-sdk/types": "^0.1.0-preview.1", + "@aws-sdk/util-hex-encoding": "^0.1.0-preview.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/is-array-buffer": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-0.1.0-preview.1.tgz", + "integrity": "sha512-9Qrr9w6sNX19N0eO7JBYjp86OPcOyjDPe580L5ISDKo7XfuzK20IC2TeGTZ77okhRTsm8rF5UgP9scBu59jwoA==", + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/types": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-0.1.0-preview.1.tgz", + "integrity": "sha512-CcZpxyN2G0I7+Jyj0om3LafYX7d30JWJAAQ+53Ysjau7jyL/xLMMkLZgniQPV8BMV7uKLXyf4hwu8JSs0Ejb+w==" + }, + "@aws-sdk/util-buffer-from": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-0.1.0-preview.1.tgz", + "integrity": "sha512-i46iuFQA05+92L/epK7befgoxw6DM38LnaHjHNxRoJeIYUllZvpJst74FRCJ5UvVOaMDvHO3woWG+dY8/KVABw==", + "requires": { + "@aws-sdk/is-array-buffer": "^0.1.0-preview.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/util-hex-encoding": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-0.1.0-preview.1.tgz", + "integrity": "sha512-97ZMVcJpIXwOQN2RntPimav6G5iod/QHEbqGrmaECXyjXzSrexKHRYjpQAtmJ7geZTMsofoRSdj3qZCymjn7Uw==", + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/util-utf8-node": { + "version": "0.1.0-preview.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-node/-/util-utf8-node-0.1.0-preview.1.tgz", + "integrity": "sha512-PSUsSJ0nnMPS389f0R3kIVR0BElnEb22Ofj40iO5HCtw9gZ1ot+enFdbOmW4m1e5+ED9U/Hqxqc7QhFWWF4NUQ==", + "requires": { + "@aws-sdk/util-buffer-from": "^0.1.0-preview.1", + "tslib": "^1.8.0" + } + }, + "@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" + } + }, + "@babel/compat-data": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.6.tgz", + "integrity": "sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q==", + "requires": { + "browserslist": "^4.8.5", + "invariant": "^2.2.4", + "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/core": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz", + "integrity": "sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helpers": "^7.8.4", + "@babel/parser": "^7.8.4", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.0", + "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==" + } + } + }, + "@babel/generator": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.7.tgz", + "integrity": "sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew==", + "requires": { + "@babel/types": "^7.8.7", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", + "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", + "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-builder-react-jsx": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz", + "integrity": "sha512-JT8mfnpTkKNCboTqZsQTdGo3l3Ik3l7QIt9hh0O9DYiwVel37VoJpILKM4YFbP2euF32nkQSb+F9cUk9b7DDXQ==", + "requires": { + "@babel/types": "^7.8.3", + "esutils": "^2.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz", + "integrity": "sha512-doAA5LAKhsFCR0LAFIf+r2RSMmC+m8f/oQ+URnUET/rWeEzC0yTRmAGyWkD4sSu3xwbS7MYQ2u+xlt1V5R56KQ==", + "requires": { + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz", + "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==", + "requires": { + "@babel/compat-data": "^7.8.6", + "browserslist": "^4.9.1", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "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.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz", + "integrity": "sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg==", + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-split-export-declaration": "^7.8.3" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.6.tgz", + "integrity": "sha512-bPyujWfsHhV/ztUkwGHz/RPV1T1TDEsSZDsN42JPehndA+p1KKTh3npvTadux0ZhCrytx9tvjpWNowKby3tM6A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-regex": "^7.8.3", + "regexpu-core": "^4.6.0" + } + }, + "@babel/helper-define-map": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", + "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/types": "^7.8.3", + "lodash": "^4.17.13" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", + "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", + "requires": { + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", + "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-imports": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-transforms": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz", + "integrity": "sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg==", + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-simple-access": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.8.6", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==" + }, + "@babel/helper-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", + "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", + "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-wrap-function": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-replace-supers": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/helper-simple-access": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "requires": { + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-wrap-function": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", + "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helpers": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", + "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", + "requires": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.7.tgz", + "integrity": "sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A==" + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", + "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", + "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", + "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@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-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz", + "integrity": "sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz", + "integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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-decorators": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz", + "integrity": "sha512-8Hg4dNNT9/LcA1zQlfwuKR8BUc/if7Q7NkTam9sGTcJphLwpf2g4S42uhspQrIrR+dpzE0dtTqBVFoHl8GtnnQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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-flow": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz", + "integrity": "sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz", + "integrity": "sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", + "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz", + "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.8.3.tgz", + "integrity": "sha512-GO1MQ/SGGGoiEXY0e0bSpHimJvxqB7lktLLIq2pv8xG7WZ8IMEle74jIe1FhprHBWjwjZtXHkycDLZXIWM5Wfg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", + "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", + "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", + "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", + "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz", + "integrity": "sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-define-map": "^7.8.3", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-split-export-declaration": "^7.8.3", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", + "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz", + "integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", + "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", + "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", + "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.8.3.tgz", + "integrity": "sha512-g/6WTWG/xbdd2exBBzMfygjX/zw4eyNC4X8pRaq7aRHRoDUCzAIu3kGYIXviOv8BjCuWm8vDBwjHcjiRNgXrPA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-flow": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz", + "integrity": "sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", + "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", + "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", + "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz", + "integrity": "sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==", + "requires": { + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz", + "integrity": "sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==", + "requires": { + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-simple-access": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz", + "integrity": "sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==", + "requires": { + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz", + "integrity": "sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==", + "requires": { + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", + "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", + "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", + "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.7.tgz", + "integrity": "sha512-brYWaEPTRimOctz2NDA3jnBbDi7SVN2T4wYuu0aqSzxC3nozFZngGaw29CJ9ZPweB7k+iFmZuoG3IVPIcXmD2g==", + "requires": { + "@babel/helper-call-delegate": "^7.8.7", + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", + "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.8.3.tgz", + "integrity": "sha512-glrzN2U+egwRfkNFtL34xIBYTxbbUF2qJTP8HD3qETBBqzAWSeNB821X0GjU06+dNpq/UyCIjI72FmGE5NNkQQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@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/plugin-transform-react-jsx": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz", + "integrity": "sha512-r0h+mUiyL595ikykci+fbwm9YzmuOrUBi0b+FDIKmi3fPQyFokWVEMJnRWHJPPQEjyFJyna9WZC6Viv6UHSv1g==", + "requires": { + "@babel/helper-builder-react-jsx": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.8.3.tgz", + "integrity": "sha512-01OT7s5oa0XTLf2I8XGsL8+KqV9lx3EZV+jxn/L2LQ97CGKila2YMroTkCEIE0HV/FF7CMSRsIAybopdN9NTdg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz", + "integrity": "sha512-PLMgdMGuVDtRS/SzjNEQYUT8f4z1xb2BAT54vM1X5efkVuYBf5WyGUMbpmARcfq3NaglIwz08UVQK4HHHbC6ag==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz", + "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==", + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", + "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.8.3.tgz", + "integrity": "sha512-/vqUt5Yh+cgPZXXjmaG9NT8aVfThKk7G4OqkVhrXqwsC5soMn/qTCxs36rZ2QFhpfTJcjw4SNDIZ4RUb8OL4jQ==", + "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.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", + "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", + "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", + "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-regex": "^7.8.3" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", + "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", + "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.7.tgz", + "integrity": "sha512-7O0UsPQVNKqpHeHLpfvOG4uXmlw+MOxYvUv6Otc9uH5SYMIxvF6eBdjkWvC3f9G+VXe0RsNExyAQBeTRug/wqQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-typescript": "^7.8.3" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", + "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/preset-env": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.7.tgz", + "integrity": "sha512-BYftCVOdAYJk5ASsznKAUl53EMhfBbr8CJ1X+AJLfGPscQkwJFiaV/Wn9DPH/7fzm2v6iRYJKYHSqyynTGw0nw==", + "requires": { + "@babel/compat-data": "^7.8.6", + "@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-object-rest-spread": "^7.8.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@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-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.8.6", + "@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.8.6", + "@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.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.8.3", + "@babel/plugin-transform-modules-systemjs": "^7.8.3", + "@babel/plugin-transform-modules-umd": "^7.8.3", + "@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/types": "^7.8.7", + "browserslist": "^4.8.5", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "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-react": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.8.3.tgz", + "integrity": "sha512-9hx0CwZg92jGb7iHYQVgi0tOEHP/kM60CtWJQnmbATSPIQQ2xYzfoCI3EdqAhFBeeJwYMdWQuDUHMsuDbH9hyQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-react-display-name": "^7.8.3", + "@babel/plugin-transform-react-jsx": "^7.8.3", + "@babel/plugin-transform-react-jsx-self": "^7.8.3", + "@babel/plugin-transform-react-jsx-source": "^7.8.3" + } + }, + "@babel/preset-typescript": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz", + "integrity": "sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-transform-typescript": "^7.8.3" + } + }, + "@babel/runtime": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.7.tgz", + "integrity": "sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.8.7.tgz", + "integrity": "sha512-sc7A+H4I8kTd7S61dgB9RomXu/C+F4IrRr4Ytze4dnfx7AXEpCrejSNpjx7vq6y/Bak9S6Kbk65a/WgMLtg43Q==", + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/traverse": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.6", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.7.tgz", + "integrity": "sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "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==" + }, + "@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==" + } + } + }, + "@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" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/source-map": { + "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==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/test-result": { + "version": "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" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/types": { + "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" + } + }, + "@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==" + }, + "@reach/observe-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@reach/observe-rect/-/observe-rect-1.1.0.tgz", + "integrity": "sha512-kE+jvoj/OyJV24C03VvLt5zclb9ArJi04wWXMMFwQvdZjdHoBlN4g0ZQFjyy/ejPF1Z/dpUD5dhRdBiUmIGZTA==" + }, + "@sheerun/mutationobserver-shim": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz", + "integrity": "sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q==" + }, + "@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" + } + }, + "@testing-library/dom": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-6.15.0.tgz", + "integrity": "sha512-8N24c4XwOigPicwc8n4ECgEoJW2/mMzRJBxu4Uo0zhLERZTbNzqpL5fyCigu7JGUXX+ITuiK4z9/lnHbYRHLwQ==", + "requires": { + "@babel/runtime": "^7.8.4", + "@sheerun/mutationobserver-shim": "^0.3.2", + "@types/testing-library__dom": "^6.12.1", + "aria-query": "^4.0.2", + "dom-accessibility-api": "^0.3.0", + "pretty-format": "^25.1.0", + "wait-for-expect": "^3.0.2" + }, + "dependencies": { + "@jest/types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz", + "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "@types/yargs": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz", + "integrity": "sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.0.2.tgz", + "integrity": "sha512-S1G1V790fTaigUSM/Gd0NngzEfiMy9uTUfMyHhKhVyy4cH5O/eTuR01ydhGL0z4Za1PXFTRGH3qL8VhUQuEO5w==", + "requires": { + "@babel/runtime": "^7.7.4", + "@babel/runtime-corejs3": "^7.7.4" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "pretty-format": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz", + "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==", + "requires": { + "@jest/types": "^25.1.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@testing-library/jest-dom": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-4.2.4.tgz", + "integrity": "sha512-j31Bn0rQo12fhCWOUWy9fl7wtqkp7In/YP2p5ZFyRuiiB9Qs3g+hS4gAmDWONbAHcRmVooNJ5eOHQDCOmUFXHg==", + "requires": { + "@babel/runtime": "^7.5.1", + "chalk": "^2.4.1", + "css": "^2.2.3", + "css.escape": "^1.5.1", + "jest-diff": "^24.0.0", + "jest-matcher-utils": "^24.0.0", + "lodash": "^4.17.11", + "pretty-format": "^24.0.0", + "redent": "^3.0.0" + } + }, + "@testing-library/react": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-9.5.0.tgz", + "integrity": "sha512-di1b+D0p+rfeboHO5W7gTVeZDIK5+maEgstrZbWZSSvxDyfDRkkyBE1AJR5Psd6doNldluXlCWqXriUfqu/9Qg==", + "requires": { + "@babel/runtime": "^7.8.4", + "@testing-library/dom": "^6.15.0", + "@types/testing-library__react": "^9.1.2" + } + }, + "@testing-library/user-event": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-7.2.1.tgz", + "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==" + }, + "@types/babel__core": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.6.tgz", + "integrity": "sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg==", + "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.1", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", + "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.9.tgz", + "integrity": "sha512-jEFQ8L1tuvPjOI8lnpaf73oCJe+aoxL6ygqSy6c8LcW98zaC+4mzWuQIRCEvKeCOu+lbqdXcg4Uqmm1S8AP1tw==", + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "@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/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==" + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==" + }, + "@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.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==" + }, + "@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": "13.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.0.tgz", + "integrity": "sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ==" + }, + "@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.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" + }, + "@types/react": { + "version": "16.9.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.23.tgz", + "integrity": "sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw==", + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, + "@types/react-dom": { + "version": "16.9.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.5.tgz", + "integrity": "sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg==", + "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/testing-library__dom": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-6.12.1.tgz", + "integrity": "sha512-cgqnEjxKk31tQt29j4baSWaZPNjQf3bHalj2gcHQTpW5SuHRal76gOpF0vypeEo6o+sS5inOvvNdzLY0B3FB2A==", + "requires": { + "pretty-format": "^24.3.0" + } + }, + "@types/testing-library__react": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@types/testing-library__react/-/testing-library__react-9.1.3.tgz", + "integrity": "sha512-iCdNPKU3IsYwRK9JieSYAiX0+aYDXOGAmrC/3/M7AqqSDKnWWVv07X+Zk1uFSL7cMTUYzv4lQRfohucEocn5/w==", + "requires": { + "@types/react-dom": "*", + "@types/testing-library__dom": "*", + "pretty-format": "^25.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz", + "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + } + }, + "@types/yargs": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz", + "integrity": "sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "pretty-format": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz", + "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==", + "requires": { + "@jest/types": "^25.1.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@types/yargs": { + "version": "13.0.8", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", + "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "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.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.23.0.tgz", + "integrity": "sha512-8iA4FvRsz8qTjR0L/nK9RcRUN3QtIHQiOm69FzV7WS3SE+7P7DyGGwh3k4UNR2JBbk+Ej2Io+jLAaqKibNhmtw==", + "requires": { + "@typescript-eslint/experimental-utils": "2.23.0", + "eslint-utils": "^1.4.3", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.23.0.tgz", + "integrity": "sha512-OswxY59RcXH3NNPmq+4Kis2CYZPurRU6mG5xPcn24CjFyfdVli5mySwZz/g/xDbJXgDsYqNGq7enV0IziWGXVQ==", + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.23.0", + "eslint-scope": "^5.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.23.0.tgz", + "integrity": "sha512-k61pn/Nepk43qa1oLMiyqApC6x5eP5ddPz6VUYXCAuXxbmRLqkPYzkFRKl42ltxzB2luvejlVncrEpflgQoSUg==", + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.23.0", + "@typescript-eslint/typescript-estree": "2.23.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.23.0.tgz", + "integrity": "sha512-pmf7IlmvXdlEXvE/JWNNJpEvwBV59wtJqA8MLAxMKLXNKVRC3HZBXR/SlZLPWTCcwOSg9IM7GeRSV3SIerGVqw==", + "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": "^6.3.0", + "tsutils": "^3.17.1" + } + }, + "@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.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==" + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" + }, + "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.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" + } + } + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==" + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz", + "integrity": "sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA==", + "requires": { + "assert": "1.4.1", + "camelcase": "5.0.0", + "loader-utils": "1.2.3", + "object-path": "0.11.4", + "regex-parser": "2.2.10" + }, + "dependencies": { + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" + }, + "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" + } + } + } + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "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.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==" + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" + }, + "amazon-cognito-identity-js": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-3.2.5.tgz", + "integrity": "sha512-DIJM6Spo4YErBxhCqCuQNVWwHG2XBE57Cvrt97L4mSziCTq612E9jerBxEb2+Iy/xjFZpL4Yzqxe+j3rJmBWEQ==", + "requires": { + "buffer": "4.9.1", + "crypto-js": "3.1.9-1", + "js-cookie": "^2.1.4" + }, + "dependencies": { + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + } + } + }, + "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": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "requires": { + "util": "0.10.3" + } + }, + "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==" + }, + "autoprefixer": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.4.tgz", + "integrity": "sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g==", + "requires": { + "browserslist": "^4.8.3", + "caniuse-lite": "^1.0.30001020", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.26", + "postcss-value-parser": "^4.0.2" + } + }, + "aws-amplify": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/aws-amplify/-/aws-amplify-2.2.6.tgz", + "integrity": "sha512-yops+OW4Sc503KO6r76n065Na6PZ6BNFpieeLRuMeCBaWJ+9qJR59Xj5h0FZor+8nWMiGF5kd9TqSVTX2ecnPg==", + "requires": { + "@aws-amplify/analytics": "^2.2.6", + "@aws-amplify/api": "^2.1.6", + "@aws-amplify/auth": "^2.1.6", + "@aws-amplify/cache": "^2.1.6", + "@aws-amplify/core": "^2.2.5", + "@aws-amplify/interactions": "^2.1.6", + "@aws-amplify/predictions": "^2.1.6", + "@aws-amplify/pubsub": "^2.1.7", + "@aws-amplify/storage": "^2.2.1", + "@aws-amplify/ui": "^1.1.5", + "@aws-amplify/xr": "^1.1.6" + } + }, + "aws-amplify-react": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/aws-amplify-react/-/aws-amplify-react-3.1.7.tgz", + "integrity": "sha512-karMa91pCiCVa/DS19SVR6K2Z+0bRWs6tSKiArpP8RPEnp91WGPgmMRmczAQPH3zM88wLGeeXDsHsM5UypgFxw==", + "requires": { + "qrcode.react": "^0.8.0", + "regenerator-runtime": "^0.11.1" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "aws-sdk": { + "version": "2.518.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.518.0.tgz", + "integrity": "sha512-hwtKKf93TFyd3qugDW54ElpkUXhPe+ArPIHadre6IAFjCJiv08L8DaZKLRyclDnKfTavKe+f/PhdSEYo1QUHiA==", + "requires": { + "buffer": "4.9.1", + "events": "1.1.1", + "ieee754": "1.1.8", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "dependencies": { + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, + "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.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "axobject-query": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.2.tgz", + "integrity": "sha512-ICt34ZmrVt8UQnvPl6TVyDTkmhXmAyAT4Jh5ugfGUX4MOrZ+U/ZY6/sdylRw3qGNr9Ub5AJsaHeDMzNLehRdOQ==" + }, + "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.0.3", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz", + "integrity": "sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.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.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.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==" + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "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" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "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.6", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.6.tgz", + "integrity": "sha512-1aGDUfL1qOOIoqk9QKGIo2lANk+C7ko/fqH0uIyC71x3PEGz0uVP8ISgfEsFuG+FKmjHTvFK/nNM8dowpmUxLA==" + }, + "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.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.1.1.tgz", + "integrity": "sha512-YkWP2UwY//TLltNlEBRngDOrYhvSLb+CA330G7T9M5UhGEMWe+JK/8IXJc5p2fDTSfSiETf+PY0+PYXFMix81Q==", + "requires": { + "@babel/core": "7.8.4", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-proposal-decorators": "7.8.3", + "@babel/plugin-proposal-numeric-separator": "7.8.3", + "@babel/plugin-transform-flow-strip-types": "7.8.3", + "@babel/plugin-transform-react-display-name": "7.8.3", + "@babel/plugin-transform-runtime": "7.8.3", + "@babel/preset-env": "7.8.4", + "@babel/preset-react": "7.8.3", + "@babel/preset-typescript": "7.8.3", + "@babel/runtime": "7.8.4", + "babel-plugin-macros": "2.8.0", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/preset-env": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.4.tgz", + "integrity": "sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w==", + "requires": { + "@babel/compat-data": "^7.8.4", + "@babel/helper-compilation-targets": "^7.8.4", + "@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-object-rest-spread": "^7.8.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@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-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.8.3", + "@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.8.4", + "@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.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.8.3", + "@babel/plugin-transform-modules-systemjs": "^7.8.3", + "@babel/plugin-transform-modules-umd": "^7.8.3", + "@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.4", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.3", + "@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/types": "^7.8.3", + "browserslist": "^4.8.5", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/runtime": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.4.tgz", + "integrity": "sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + }, + "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": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "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" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.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.9.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.9.1.tgz", + "integrity": "sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw==", + "requires": { + "caniuse-lite": "^1.0.30001030", + "electron-to-chromium": "^1.3.363", + "node-releases": "^1.1.50" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-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": "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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-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" + } + }, + "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.30001033", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001033.tgz", + "integrity": "sha512-8Ibzxee6ibc5q88cM1usPsMpJOG5CTq0s/dKOmlekPbDGKt+UrnOOTPSjQz3kVo6yL7N4SB5xd+FGLHQmbzh6A==" + }, + "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.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "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.3.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": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "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" + } + } + } + }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "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": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "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" + } + }, + "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" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "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.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "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=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==" + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==" + }, + "core-js-compat": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", + "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", + "requires": { + "browserslist": "^4.8.3", + "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.6.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz", + "integrity": "sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw==" + }, + "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.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-blank-pseudo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-has-pseudo": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", + "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^5.0.0-rc.4" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "css-loader": { + "version": "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" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-what": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==" + }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" + }, + "cssdb": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", + "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "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.0.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.2.tgz", + "integrity": "sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg==", + "requires": { + "css-tree": "1.0.0-alpha.37" + } + }, + "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.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz", + "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==" + }, + "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" + } + }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "d3-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz", + "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg==" + }, + "d3-delaunay": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-5.2.1.tgz", + "integrity": "sha512-ZZdeJl6cKRyqYVFYK+/meXvWIrAvZsZTD7WSxl4OPXCmuXNgDyACAClAJHD63zL25TA+IJGURUNO7rFseNFCYw==", + "requires": { + "delaunator": "4" + } + }, + "d3-format": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.3.tgz", + "integrity": "sha512-mm/nE2Y9HgGyjP+rKIekeITVgBtX97o1nrvHCWX8F/yBYyevUTvu9vb5pUnKwrcSw7o7GuwMOWjS9gFDs4O+uQ==" + }, + "d3-interpolate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", + "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "requires": { + "d3-path": "1" + } + }, + "d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" + }, + "d3-time-format": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.3.tgz", + "integrity": "sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA==", + "requires": { + "d3-time": "1" + } + }, + "d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decimal.js-light": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.0.tgz", + "integrity": "sha512-b3VJCbd2hwUpeRGG3Toob+CRo8W22xplipNhP3tN7TSVB/cyMX71P1vM2Xjc9H74uV6dS2hDDmo/rHq8L87Upg==" + }, + "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==" + } + } + }, + "delaunator": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-4.0.1.tgz", + "integrity": "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag==" + }, + "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" + } + }, + "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-accessibility-api": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.3.0.tgz", + "integrity": "sha512-PzwHEmsRP3IGY4gv/Ug+rMeaTIyTJvadCb+ujYXYeIylbHJezIyNToe8KfEgHTCEYyC+/bUghYOGg8yMGlZ6vA==" + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" + } + } + }, + "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" + } + }, + "dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "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.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "electron-to-chromium": { + "version": "1.3.372", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.372.tgz", + "integrity": "sha512-77a4jYC52OdisHM+Tne7dgWEvQT1FoNu/jYl279pP88ZtG4ZRIPyhQwAKxj6C2rzsyC1OwsOds9JlZtNncSz6g==" + }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "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" + } + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + }, + "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.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.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" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", + "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "eslint": { + "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": { + "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.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.0.tgz", + "integrity": "sha512-WrHjoGpKr1kLLiWDD81tme9jMM0hk5cMxasLSdyno6DdPt+IfLOrDJBVo6jN7tn4y1nzhs43TmUaZWO6Sf0blw==", + "requires": { + "confusing-browser-globals": "^1.0.9" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", + "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", + "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.5.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz", + "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==", + "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=" + }, + "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.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz", + "integrity": "sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==", + "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" + } + }, + "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-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.18.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz", + "integrity": "sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ==", + "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.14.2" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "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.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "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" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + }, + "espree": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.0.tgz", + "integrity": "sha512-Xs8airJ7RQolnDIbLtRutmfvSsAe0xqMMAantCN/GMoqf81TFbeI1T7Jpd56qYu1uuh32dOG5W/X9uO+ghPXzA==", + "requires": { + "acorn": "^7.1.0", + "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.1.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz", + "integrity": "sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q==", + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "requires": { + "estraverse": "^4.1.0" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" + }, + "events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==" + }, + "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=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + } + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, + "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.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" + }, + "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" + } + }, + "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": "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" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" + }, + "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": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "follow-redirects": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz", + "integrity": "sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==", + "requires": { + "debug": "^3.0.0" + }, + "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" + } + } + } + }, + "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": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-extra": { + "version": "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": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.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.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==" + }, + "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-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.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "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.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "graphql": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.0.tgz", + "integrity": "sha512-HGVcnO6B25YZcSt6ZsH6/N+XkYuPA7yMqJmlJ4JWxWlS4Tr8SHI56R1Ocs8Eor7V7joEZPRXPDH8RRdll1w44Q==", + "requires": { + "iterall": "^1.2.2" + } + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" + }, + "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.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" + }, + "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.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "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.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "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==" + }, + "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" + } + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" + }, + "html-encoding-sniffer": { + "version": "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.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=" + }, + "html-escaper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", + "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==" + }, + "html-minifier-terser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.0.4.tgz", + "integrity": "sha512-fHwmKQ+GzhlqdxEtwrqLT7MSuheiA+rif5/dZgbz3GjoMXJzcRzy1L9NXoiiyxrnap+q5guSiv8Tz5lrh9g42g==", + "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-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" + }, + "http-proxy": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "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=" + }, + "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.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "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" + } + }, + "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.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.6.tgz", + "integrity": "sha512-7SVO4h+QIdMq6XcqIqrNte3gS5MzCCKZdsq9DO4PJziBFNYzP3PGFbDjgadDb//MCahzgjCxvQ/O2wa7kx9o4w==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "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.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "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" + } + }, + "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" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" + }, + "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.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "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-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.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz", + "integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==" + }, + "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-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-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul-lib-coverage": { + "version": "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": { + "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": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "istanbul-reports": { + "version": "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" + } + }, + "iterall": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", + "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" + }, + "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.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" + }, + "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.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "optional": true, + "requires": { + "node-pre-gyp": "*" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "3.2.6", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "optional": true, + "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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "optional": true + }, + "minipass": { + "version": "2.9.0", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "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.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==" + }, + "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" + } + }, + "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==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "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" + } + } + } + }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, + "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.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "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-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.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "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" + } + }, + "jsx-ast-utils": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz", + "integrity": "sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==", + "requires": { + "array-includes": "^3.0.3", + "object.assign": "^4.1.0" + } + }, + "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=" + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "requires": { + "invert-kv": "^2.0.0" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.2.tgz", + "integrity": "sha512-70IzT/0/L+M20jUlEqZhZyArTU6VKLRTYRDAYN26g4jfzpJqjipLL3/hgYpySqI9PwsVRHHFja0LfEmsx9X2Cw==", + "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" + } + }, + "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": "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" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "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.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, + "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.6.7", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz", + "integrity": "sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A==" + }, + "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" + } + }, + "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" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "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==" + } + } + }, + "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-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "requires": { + "p-defer": "^1.0.0" + } + }, + "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" + } + }, + "math-expression-evaluator": { + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz", + "integrity": "sha512-L0j0tFVZBQQLeEjmWOvDLoRciIY8gQGWahvkztXUal8jH8R5Rlqo9GCvgqvXcy9LQhEWdQCVvzqAbxgYNt4blQ==" + }, + "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=" + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "merge-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.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" + }, + "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" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "min-indent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", + "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=" + }, + "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.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "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.2", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz", + "integrity": "sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA==", + "requires": { + "minipass": "^3.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": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "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.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, + "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" + } + }, + "node-forge": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "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=" + } + } + } + } + }, + "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.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.51.tgz", + "integrity": "sha512-1eQEs6HFYY1kMXQPOLzCf7HdjReErmvn85tZESMczdCNVWP3Y7URYLBAyYynuI7yef1zj4HN5q+oB2x67QU0lw==", + "requires": { + "semver": "^6.3.0" + } + }, + "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" + } + }, + "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" + } + }, + "npx": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/npx/-/npx-10.2.2.tgz", + "integrity": "sha512-eImmySusyeWphzs5iNh791XbZnZG0FSNvM4KSah34pdQQIDsdTDhIwg1sjN3AIVcjGLpbQ/YcfqHPshKZQK1fA==", + "requires": { + "libnpx": "10.2.2", + "npm": "5.1.0" + }, + "dependencies": { + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "boxen": { + "version": "1.3.0", + "bundled": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtins": { + "version": "1.0.3", + "bundled": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true + }, + "capture-stack-trace": { + "version": "1.0.1", + "bundled": true + }, + "chalk": { + "version": "2.4.2", + "bundled": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "ci-info": { + "version": "1.6.0", + "bundled": true + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true + }, + "cliui": { + "version": "4.1.0", + "bundled": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.3", + "bundled": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "configstore": { + "version": "3.1.2", + "bundled": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "bundled": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true + }, + "dot-prop": { + "version": "4.2.0", + "bundled": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "5.0.1", + "bundled": true + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true + }, + "end-of-stream": { + "version": "1.4.4", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.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" + } + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "get-caller-file": { + "version": "1.0.3", + "bundled": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "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" + } + }, + "global-dirs": { + "version": "0.1.1", + "bundled": true, + "requires": { + "ini": "^1.3.4" + } + }, + "got": { + "version": "6.7.1", + "bundled": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "bundled": true + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "hosted-git-info": { + "version": "2.8.5", + "bundled": true + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true + }, + "invert-kv": { + "version": "2.0.0", + "bundled": true + }, + "is-ci": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "is-installed-globally": { + "version": "0.1.0", + "bundled": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true + }, + "is-obj": { + "version": "1.0.1", + "bundled": true + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true + }, + "is-retry-allowed": { + "version": "1.2.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lcid": { + "version": "2.0.0", + "bundled": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "libnpx": { + "version": "10.2.2", + "bundled": true, + "requires": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^11.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "bundled": true + }, + "lru-cache": { + "version": "4.1.5", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "bundled": true, + "requires": { + "pify": "^3.0.0" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "bundled": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "mem": { + "version": "4.3.0", + "bundled": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "nice-try": { + "version": "1.0.5", + "bundled": true + }, + "npm": { + "version": "5.1.0", + "bundled": true, + "requires": { + "JSONStream": "~1.3.1", + "abbrev": "~1.1.0", + "ansi-regex": "~3.0.0", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "~1.1.2", + "archy": "~1.0.0", + "bluebird": "~3.5.0", + "cacache": "~9.2.9", + "call-limit": "~1.1.0", + "chownr": "~1.0.1", + "cmd-shim": "~2.0.2", + "columnify": "~1.5.4", + "config-chain": "~1.1.11", + "debuglog": "*", + "detect-indent": "~5.0.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "fstream": "~1.0.11", + "fstream-npm": "~1.2.1", + "glob": "~7.1.2", + "graceful-fs": "~4.1.11", + "has-unicode": "~2.0.1", + "hosted-git-info": "~2.5.0", + "iferr": "~0.1.5", + "imurmurhash": "*", + "inflight": "~1.0.6", + "inherits": "~2.0.3", + "ini": "~1.3.4", + "init-package-json": "~1.10.1", + "lazy-property": "~1.0.0", + "lockfile": "~1.0.3", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "~4.1.1", + "mississippi": "~1.3.0", + "mkdirp": "~0.5.1", + "move-concurrently": "~1.0.1", + "node-gyp": "~3.6.2", + "nopt": "~4.0.1", + "normalize-package-data": "~2.4.0", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "~3.0.0", + "npm-package-arg": "~5.1.2", + "npm-registry-client": "~8.4.0", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "~1.4.3", + "osenv": "~0.1.4", + "pacote": "~2.7.38", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "~1.0.1", + "read-installed": "~4.0.3", + "read-package-json": "~2.0.9", + "read-package-tree": "~5.1.6", + "readable-stream": "~2.3.2", + "readdir-scoped-modules": "*", + "request": "~2.81.0", + "retry": "~0.10.1", + "rimraf": "~2.6.1", + "safe-buffer": "~5.1.1", + "semver": "~5.3.0", + "sha": "~2.0.1", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "~4.1.6", + "strip-ansi": "~4.0.0", + "tar": "~2.2.1", + "text-table": "~0.2.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "~1.1.0", + "unpipe": "~1.0.0", + "update-notifier": "~2.2.0", + "uuid": "~3.1.0", + "validate-npm-package-license": "*", + "validate-npm-package-name": "~3.0.0", + "which": "~1.2.14", + "worker-farm": "~1.3.1", + "wrappy": "~1.0.2", + "write-file-atomic": "~2.1.0" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.1", + "bundled": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "dependencies": { + "jsonparse": { + "version": "1.3.1", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + } + } + }, + "abbrev": { + "version": "1.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "aproba": { + "version": "1.1.2", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "bluebird": { + "version": "3.5.0", + "bundled": true + }, + "cacache": { + "version": "9.2.9", + "bundled": true, + "requires": { + "bluebird": "^3.5.0", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^1.3.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.1", + "ssri": "^4.1.6", + "unique-filename": "^1.1.0", + "y18n": "^3.2.1" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.1", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true + } + } + }, + "call-limit": { + "version": "1.1.0", + "bundled": true + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "^1.0.3" + }, + "dependencies": { + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.2", + "bundled": true + } + } + } + } + } + } + }, + "config-chain": { + "version": "1.1.11", + "bundled": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "proto-list": { + "version": "1.2.4", + "bundled": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + }, + "dependencies": { + "asap": { + "version": "2.0.5", + "bundled": true + } + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "fstream-npm": { + "version": "1.2.1", + "bundled": true, + "requires": { + "fstream-ignore": "^1.0.0", + "inherits": "2" + }, + "dependencies": { + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "inherits": "2", + "minimatch": "^3.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "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" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hosted-git-info": { + "version": "2.5.0", + "bundled": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "init-package-json": { + "version": "1.10.1", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1" + } + } + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true + }, + "lockfile": { + "version": "1.0.3", + "bundled": true + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + }, + "dependencies": { + "lodash._createset": { + "version": "4.0.3", + "bundled": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true + } + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true + }, + "lru-cache": { + "version": "4.1.1", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "mississippi": { + "version": "1.3.0", + "bundled": true, + "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": "^1.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "duplexify": { + "version": "3.5.0", + "bundled": true, + "requires": { + "end-of-stream": "1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "end-of-stream": { + "version": "1.0.0", + "bundled": true, + "requires": { + "once": "~1.3.0" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "bundled": true, + "requires": { + "wrappy": "1" + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "end-of-stream": { + "version": "1.4.0", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "flush-write-stream": { + "version": "1.0.2", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "cyclist": { + "version": "0.2.2", + "bundled": true + } + } + }, + "pump": { + "version": "1.0.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.3.5", + "bundled": true, + "requires": { + "duplexify": "^3.1.2", + "inherits": "^2.0.1", + "pump": "^1.0.0" + } + }, + "stream-each": { + "version": "1.2.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "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": { + "copy-concurrently": { + "version": "1.0.3", + "bundled": true, + "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" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "^1.1.1" + } + } + } + }, + "node-gyp": { + "version": "3.6.2", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "2", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1" + } + } + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "^1.0.0" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.1", + "bundled": true + } + } + } + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "3.0.0", + "bundled": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-package-arg": { + "version": "5.1.2", + "bundled": true, + "requires": { + "hosted-git-info": "^2.4.2", + "osenv": "^0.1.4", + "semver": "^5.1.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-registry-client": { + "version": "8.4.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0", + "npmlog": "2 || ^3.1.0 || ^4.0.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3", + "ssri": "^4.1.2" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + } + } + }, + "npm-user-validate": { + "version": "1.0.0", + "bundled": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + }, + "dependencies": { + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "delegates": { + "version": "1.0.0", + "bundled": true + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + }, + "dependencies": { + "number-is-nan": { + "version": "1.0.1", + "bundled": true + } + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "requires": { + "string-width": "^1.0.2" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.4.3", + "bundled": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + } + } + }, + "pacote": { + "version": "2.7.38", + "bundled": true, + "requires": { + "bluebird": "^3.5.0", + "cacache": "^9.2.9", + "glob": "^7.1.2", + "lru-cache": "^4.1.1", + "make-fetch-happen": "^2.4.13", + "minimatch": "^3.0.4", + "mississippi": "^1.2.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^5.1.2", + "npm-pick-manifest": "^1.0.4", + "osenv": "^0.1.4", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^4.0.0", + "safe-buffer": "^5.1.1", + "semver": "^5.3.0", + "ssri": "^4.1.6", + "tar-fs": "^1.15.3", + "tar-stream": "^1.5.4", + "unique-filename": "^1.1.0", + "which": "^1.2.12" + }, + "dependencies": { + "make-fetch-happen": { + "version": "2.4.13", + "bundled": true, + "requires": { + "agentkeepalive": "^3.3.0", + "cacache": "^9.2.9", + "http-cache-semantics": "^3.7.3", + "http-proxy-agent": "^2.0.0", + "https-proxy-agent": "^2.0.0", + "lru-cache": "^4.1.1", + "mississippi": "^1.2.0", + "node-fetch-npm": "^2.0.1", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.0", + "ssri": "^4.1.6" + }, + "dependencies": { + "agentkeepalive": { + "version": "3.3.0", + "bundled": true, + "requires": { + "humanize-ms": "^1.2.1" + }, + "dependencies": { + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ms": "^2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "http-cache-semantics": { + "version": "3.7.3", + "bundled": true + }, + "http-proxy-agent": { + "version": "2.0.0", + "bundled": true, + "requires": { + "agent-base": "4", + "debug": "2" + }, + "dependencies": { + "agent-base": { + "version": "4.1.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.1.1", + "bundled": true + } + } + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "https-proxy-agent": { + "version": "2.0.0", + "bundled": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^2.4.1" + }, + "dependencies": { + "agent-base": { + "version": "4.1.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.1.1", + "bundled": true + } + } + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "node-fetch-npm": { + "version": "2.0.1", + "bundled": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-helpfulerror": "^1.0.3", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "encoding": { + "version": "0.1.12", + "bundled": true, + "requires": { + "iconv-lite": "~0.4.13" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.18", + "bundled": true + } + } + }, + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "^1.1.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "socks-proxy-agent": { + "version": "3.0.0", + "bundled": true, + "requires": { + "agent-base": "^4.0.1", + "socks": "^1.1.10" + }, + "dependencies": { + "agent-base": { + "version": "4.1.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.1.1", + "bundled": true + } + } + } + } + }, + "socks": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" + }, + "dependencies": { + "ip": { + "version": "1.1.5", + "bundled": true + }, + "smart-buffer": { + "version": "1.1.15", + "bundled": true + } + } + } + } + } + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "npm-pick-manifest": { + "version": "1.0.4", + "bundled": true, + "requires": { + "npm-package-arg": "^5.1.2", + "semver": "^5.3.0" + } + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "err-code": { + "version": "1.1.2", + "bundled": true + } + } + }, + "protoduck": { + "version": "4.0.0", + "bundled": true, + "requires": { + "genfun": "^4.0.1" + }, + "dependencies": { + "genfun": { + "version": "4.0.1", + "bundled": true + } + } + }, + "tar-fs": { + "version": "1.15.3", + "bundled": true, + "requires": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + }, + "dependencies": { + "pump": { + "version": "1.0.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + }, + "dependencies": { + "end-of-stream": { + "version": "1.4.0", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + } + } + } + } + }, + "tar-stream": { + "version": "1.5.4", + "bundled": true, + "requires": { + "bl": "^1.0.0", + "end-of-stream": "^1.0.0", + "readable-stream": "^2.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "bl": { + "version": "1.2.1", + "bundled": true, + "requires": { + "readable-stream": "^2.0.5" + } + }, + "end-of-stream": { + "version": "1.4.0", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "~0.0.4" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.7", + "bundled": true + } + } + }, + "read-cmd-shim": { + "version": "1.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "dependencies": { + "util-extend": { + "version": "1.0.3", + "bundled": true + } + } + }, + "read-package-json": { + "version": "2.0.9", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-helpfulerror": "^1.0.2", + "normalize-package-data": "^2.0.0" + }, + "dependencies": { + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "^1.1.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "read-package-tree": { + "version": "5.1.6", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.2", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.0", + "string_decoder": "~1.0.0", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "1.0.3", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "~1.0.0" + }, + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + }, + "dependencies": { + "asynckit": { + "version": "0.4.0", + "bundled": true + } + } + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "requires": { + "ajv": "^4.9.1", + "har-schema": "^1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "bundled": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + }, + "dependencies": { + "co": { + "version": "4.6.0", + "bundled": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "requires": { + "jsonify": "~0.0.0" + }, + "dependencies": { + "jsonify": { + "version": "0.0.0", + "bundled": true + } + } + } + } + }, + "har-schema": { + "version": "1.0.5", + "bundled": true + } + } + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.x.x" + } + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.x.x" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + } + } + }, + "sshpk": { + "version": "1.13.1", + "bundled": true, + "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", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + } + } + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "requires": { + "mime-db": "~1.27.0" + }, + "dependencies": { + "mime-db": { + "version": "1.27.0", + "bundled": true + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true + }, + "qs": { + "version": "6.4.0", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "requires": { + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "bundled": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.0.1" + } + } + } + }, + "retry": { + "version": "0.10.1", + "bundled": true + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true + }, + "semver": { + "version": "5.3.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" + } + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + } + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "ssri": { + "version": "4.1.6", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + } + } + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + }, + "dependencies": { + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "~2.0.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "unique-filename": { + "version": "1.1.0", + "bundled": true, + "requires": { + "unique-slug": "^2.0.0" + }, + "dependencies": { + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4" + } + } + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "update-notifier": { + "version": "2.2.0", + "bundled": true, + "requires": { + "boxen": "^1.0.0", + "chalk": "^1.0.0", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "boxen": { + "version": "1.1.0", + "bundled": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^1.1.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^0.1.0", + "widest-line": "^1.0.0" + }, + "dependencies": { + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "camelcase": { + "version": "4.1.0", + "bundled": true + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true + }, + "string-width": { + "version": "2.1.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "term-size": { + "version": "0.1.1", + "bundled": true, + "requires": { + "execa": "^0.4.0" + }, + "dependencies": { + "execa": { + "version": "0.4.0", + "bundled": true, + "requires": { + "cross-spawn-async": "^2.1.1", + "is-stream": "^1.1.0", + "npm-run-path": "^1.0.0", + "object-assign": "^4.0.1", + "path-key": "^1.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn-async": { + "version": "2.2.5", + "bundled": true, + "requires": { + "lru-cache": "^4.0.0", + "which": "^1.2.8" + } + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "npm-run-path": { + "version": "1.0.0", + "bundled": true, + "requires": { + "path-key": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "path-key": { + "version": "1.0.0", + "bundled": true + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "widest-line": { + "version": "1.0.0", + "bundled": true, + "requires": { + "string-width": "^1.0.1" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + }, + "dependencies": { + "number-is-nan": { + "version": "1.0.1", + "bundled": true + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "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" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "configstore": { + "version": "3.1.0", + "bundled": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "4.1.1", + "bundled": true, + "requires": { + "is-obj": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "bundled": true + } + } + }, + "make-dir": { + "version": "1.0.0", + "bundled": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "bundled": true + } + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "requires": { + "crypto-random-string": "^1.0.0" + }, + "dependencies": { + "crypto-random-string": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true + }, + "is-npm": { + "version": "1.0.0", + "bundled": true + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "requires": { + "package-json": "^4.0.0" + }, + "dependencies": { + "package-json": { + "version": "4.0.1", + "bundled": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "dependencies": { + "got": { + "version": "6.7.1", + "bundled": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "requires": { + "capture-stack-trace": "^1.0.0" + }, + "dependencies": { + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true + } + } + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "lowercase-keys": { + "version": "1.0.0", + "bundled": true + }, + "timed-out": { + "version": "4.0.1", + "bundled": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "requires": { + "prepend-http": "^1.0.1" + }, + "dependencies": { + "prepend-http": { + "version": "1.0.4", + "bundled": true + } + } + } + } + }, + "registry-auth-token": { + "version": "3.3.1", + "bundled": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "rc": { + "version": "1.2.1", + "bundled": true, + "requires": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.4.2", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "^1.0.1" + }, + "dependencies": { + "rc": { + "version": "1.2.1", + "bundled": true, + "requires": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.4.2", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "requires": { + "semver": "^5.0.3" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true + } + } + }, + "uuid": { + "version": "3.1.0", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + }, + "dependencies": { + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-license-ids": "^1.0.2" + }, + "dependencies": { + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true + } + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "bundled": true + } + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "^1.0.3" + }, + "dependencies": { + "builtins": { + "version": "1.0.3", + "bundled": true + } + } + }, + "which": { + "version": "1.2.14", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "bundled": true + } + } + }, + "worker-farm": { + "version": "1.3.1", + "bundled": true, + "requires": { + "errno": ">=0.1.1 <0.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + }, + "dependencies": { + "errno": { + "version": "0.1.4", + "bundled": true, + "requires": { + "prr": "~0.0.0" + }, + "dependencies": { + "prr": { + "version": "0.0.0", + "bundled": true + } + } + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "2.1.0", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + } + } + }, + "npm-package-arg": { + "version": "6.1.1", + "bundled": true, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-locale": { + "version": "3.1.0", + "bundled": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "bundled": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "bundled": true, + "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" + } + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "bundled": true + }, + "p-finally": { + "version": "1.0.0", + "bundled": true + }, + "p-is-promise": { + "version": "2.1.0", + "bundled": true + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true + }, + "package-json": { + "version": "4.0.1", + "bundled": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true + }, + "pify": { + "version": "3.0.0", + "bundled": true + }, + "prepend-http": { + "version": "1.0.4", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "registry-auth-token": { + "version": "3.4.0", + "bundled": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "^1.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.0", + "bundled": true + }, + "semver": { + "version": "5.7.1", + "bundled": true + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "requires": { + "semver": "^5.0.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "5.5.0", + "bundled": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "term-size": { + "version": "1.2.0", + "bundled": true, + "requires": { + "execa": "^0.7.0" + } + }, + "timed-out": { + "version": "4.0.1", + "bundled": true + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true + }, + "update-notifier": { + "version": "2.5.0", + "bundled": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true + }, + "widest-line": { + "version": "2.0.1", + "bundled": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "2.4.3", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + }, + "yargs": { + "version": "11.1.1", + "bundled": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + }, + "dependencies": { + "y18n": { + "version": "3.2.1", + "bundled": true + } + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "requires": { + "camelcase": "^4.1.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=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "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.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==" + }, + "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-path": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", + "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=" + }, + "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.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "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.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/open/-/open-7.0.3.tgz", + "integrity": "sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA==", + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "dependencies": { + "is-wsl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==" + } + } + }, + "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-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "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-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" + }, + "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-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "requires": { + "p-try": "^2.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" + } + }, + "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" + } + }, + "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==" + }, + "paho-mqtt": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/paho-mqtt/-/paho-mqtt-1.1.0.tgz", + "integrity": "sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA==" + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "param-case": { + "version": "3.0.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" + } + }, + "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.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.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" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "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.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "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.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==" + }, + "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": "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" + } + }, + "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" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.0.tgz", + "integrity": "sha512-ZcMGn/xF/fCOq+9kWMP9vVVxjIkMCja72oy3lziR7UHy0hHFZ57iVpQ71OtveVbmzeCmphBg8pxNdk/hlK99aQ==", + "requires": { + "ts-pnp": "^1.1.2" + } + }, + "portfinder": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + }, + "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" + } + } + } + }, + "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.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-attribute-case-insensitive": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", + "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^6.0.2" + } + }, + "postcss-browser-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz", + "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==", + "requires": { + "postcss": "^7" + } + }, + "postcss-calc": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz", + "integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==", + "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.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.0.tgz", + "integrity": "sha512-M8BFYKOvCrI2aITzDad7kWuXXTm0YhGdP9Q8HanmN4EF1Hmcgs1KK5rSHylt/lUJe8yLxiSwWAHdScoEiIxztg==", + "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.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "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.2", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz", + "integrity": "sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==", + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.16", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.0" + } + }, + "postcss-modules-scope": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz", + "integrity": "sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ==", + "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.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "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.0.3", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz", + "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==" + }, + "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.3.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz", + "integrity": "sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==" + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "requires": { + "renderkid": "^2.0.1", + "utila": "~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==" + } + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "requires": { + "asap": "~2.0.6" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "prompts": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.1.tgz", + "integrity": "sha512-qIP2lQyCwYbdzcqHIUi2HAxiWixhoM9OdLCWf8txXsapC/X9YdsCoeyRIXE/GP+Q0J37Q7+XN/MFqbUa7IzXNA==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.4" + } + }, + "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.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" + }, + "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" + } + }, + "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=" + }, + "qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=" + }, + "qrcode.react": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-0.8.0.tgz", + "integrity": "sha512-16wKpuFvLwciIq2YAsfmPUCnSR8GrYPsXRK5KVdcIuX0+W/MKZbBkFhl44ttRx4TWZHqRjfztoWOxdPF0Hb9JA==", + "requires": { + "prop-types": "^15.6.0", + "qr.js": "0.0.0" + } + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" + }, + "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.13.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", + "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", + "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-charts": { + "version": "2.0.0-beta.6", + "resolved": "https://registry.npmjs.org/react-charts/-/react-charts-2.0.0-beta.6.tgz", + "integrity": "sha512-GxcErCb/TSCsgug4uumSyzhXflwtQRwsN6nGA1e8dIqh9Z6gRFgDZF6DNCmvuHLibnu0JfLDmyaG7+MFgBzuDQ==", + "requires": { + "@reach/observe-rect": "^1.0.3", + "d3-delaunay": "^5.1.6", + "d3-scale": "^3.2.0", + "d3-shape": "^1.3.7", + "d3-voronoi": "^1.1.2", + "raf": "^3.4.1" + }, + "dependencies": { + "d3-scale": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.1.tgz", + "integrity": "sha512-huz5byJO/6MPpz6Q8d4lg7GgSpTjIZW/l+1MQkzKfu2u8P6hjaXaStOpmyrD6ymKoW87d2QVFCKvSjLwjzx/rA==", + "requires": { + "d3-array": "1.2.0 - 2", + "d3-format": "1", + "d3-interpolate": "^1.2.0", + "d3-time": "1", + "d3-time-format": "2" + } + } + } + }, + "react-dev-utils": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.0.tgz", + "integrity": "sha512-MwrvQW2TFjLblhqpDNeqCXHBkz3G5vc7k4wntgutAJZX4ia3o07eGKo6uYGhUOeJ0hfOxcpJFNFk7+4XCc1S8g==", + "requires": { + "@babel/code-frame": "7.8.3", + "address": "1.1.2", + "browserslist": "4.8.6", + "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.6", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "strip-ansi": "6.0.0", + "text-table": "0.2.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==" + }, + "browserslist": { + "version": "4.8.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz", + "integrity": "sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==", + "requires": { + "caniuse-lite": "^1.0.30001023", + "electron-to-chromium": "^1.3.341", + "node-releases": "^1.1.47" + } + }, + "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==" + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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-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.13.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", + "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-error-overlay": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.6.tgz", + "integrity": "sha512-Yzpno3enVzSrSCnnljmr4b/2KUQSMZaPuqmS26t9k4nW7uwJk6STWmH9heNjPuvqUTO3jOSPkHoKgO4+Dw7uIw==" + }, + "react-is": { + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", + "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==" + }, + "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-resize-detector": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-2.3.0.tgz", + "integrity": "sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ==", + "requires": { + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "prop-types": "^15.6.0", + "resize-observer-polyfill": "^1.5.0" + } + }, + "react-scripts": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.0.tgz", + "integrity": "sha512-pBqaAroFoHnFAkuX+uSK9Th1uEh2GYdGY2IG1I9/7HmuEf+ls3lLCk1p2GFYRSrLMz6ieQR/SyN6TLIGK3hKRg==", + "requires": { + "@babel/core": "7.8.4", + "@svgr/webpack": "4.3.3", + "@typescript-eslint/eslint-plugin": "^2.10.0", + "@typescript-eslint/parser": "^2.10.0", + "babel-eslint": "10.0.3", + "babel-jest": "^24.9.0", + "babel-loader": "8.0.6", + "babel-plugin-named-asset-import": "^0.3.6", + "babel-preset-react-app": "^9.1.1", + "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.0", + "eslint-loader": "3.0.3", + "eslint-plugin-flowtype": "4.6.0", + "eslint-plugin-import": "2.20.0", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-react": "7.18.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.0", + "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.0", + "resolve": "1.15.0", + "resolve-url-loader": "3.1.1", + "sass-loader": "8.0.2", + "semver": "6.3.0", + "style-loader": "0.23.1", + "terser-webpack-plugin": "2.3.4", + "ts-pnp": "1.1.5", + "url-loader": "2.3.0", + "webpack": "4.41.5", + "webpack-dev-server": "3.10.2", + "webpack-manifest-plugin": "2.2.0", + "workbox-webpack-plugin": "4.3.1" + } + }, + "react-smooth": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-1.0.5.tgz", + "integrity": "sha512-eW057HT0lFgCKh8ilr0y2JaH2YbNcuEdFpxyg7Gf/qDKk9hqGMyXryZJ8iMGJEuKH0+wxS0ccSsBBB3W8yCn8w==", + "requires": { + "lodash": "~4.17.4", + "prop-types": "^15.6.0", + "raf": "^3.4.0", + "react-transition-group": "^2.5.0" + } + }, + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "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" + } + }, + "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.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "requires": { + "picomatch": "^2.0.7" + } + }, + "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" + } + }, + "recharts": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-1.8.5.tgz", + "integrity": "sha512-tM9mprJbXVEBxjM7zHsIy6Cc41oO/pVYqyAsOHLxlJrbNBuLs0PHB3iys2M+RqCF0//k8nJtZF6X6swSkWY3tg==", + "requires": { + "classnames": "^2.2.5", + "core-js": "^2.6.10", + "d3-interpolate": "^1.3.0", + "d3-scale": "^2.1.0", + "d3-shape": "^1.2.0", + "lodash": "^4.17.5", + "prop-types": "^15.6.0", + "react-resize-detector": "^2.3.0", + "react-smooth": "^1.0.5", + "recharts-scale": "^0.4.2", + "reduce-css-calc": "^1.3.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==" + } + } + }, + "recharts-scale": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.3.tgz", + "integrity": "sha512-t8p5sccG9Blm7c1JQK/ak9O8o95WGhNXD7TXg/BW5bYbVlr6eCeRBNpgyigD4p6pSSMehC5nSvBUPj6F68rbFA==", + "requires": { + "decimal.js-light": "^2.4.1" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "requires": { + "minimatch": "3.0.4" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "requires": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } + } + }, + "reduce-function-call": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", + "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz", + "integrity": "sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g==" + }, + "regenerator-transform": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.2.tgz", + "integrity": "sha512-V4+lGplCM/ikqi5/mkkpJ06e9Bujq1NFmNLvsCs56zg3ZbzrnUzAtizZ24TXxtRX/W2jcdScwQCnbL0CICTFkQ==", + "requires": { + "@babel/runtime": "^7.8.4", + "private": "^0.1.8" + } + }, + "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.10", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.10.tgz", + "integrity": "sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA==" + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==" + }, + "regexpu-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==" + }, + "regjsparser": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.3.tgz", + "integrity": "sha512-8uZvYbnfAtEm9Ab8NTb3hdLwL4g/LQzEYP7Xs27T96abJCCE2d6r3cPZPQEsLKy0vRSGVNG+/zVGtLr86HQduA==", + "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.3", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", + "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.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.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "requires": { + "lodash": "^4.17.15" + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "requires": { + "request-promise-core": "1.1.3", + "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=" + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "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-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.1", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz", + "integrity": "sha512-K1N5xUjj7v0l2j/3Sgs5b8CjrrgtC70SmdCuZiJ8tSyb5J+uk3FoeZ4b7yTnH6j7ngI+Bc5bldHJIa8hYdu2gQ==", + "requires": { + "adjust-sourcemap-loader": "2.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" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "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": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", + "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", + "requires": { + "is-promise": "^2.1.0" + } + }, + "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.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "requires": { + "tslib": "^1.9.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==" + }, + "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.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + }, + "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.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "requires": { + "node-forge": "0.9.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": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==" + }, + "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==" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "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.4", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", + "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==" + }, + "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=" + } + } + }, + "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" + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "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.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" + }, + "spdy": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", + "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": "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" + } + }, + "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": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string-length": { + "version": "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.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.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" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + } + } + }, + "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-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" + }, + "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" + } + }, + "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==" + }, + "terser": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.6.tgz", + "integrity": "sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "terser-webpack-plugin": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.4.tgz", + "integrity": "sha512-Nv96Nws2R2nrFOpbzF6IxRDpIkkIfmhvOws+IqMvYdFLO7o6wAILWFKONFgaYy8+T4LVz77DQW0f7wOeDEAjrg==", + "requires": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.2.0", + "jest-worker": "^25.1.0", + "p-limit": "^2.2.2", + "schema-utils": "^2.6.4", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.4.3", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "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" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz", + "integrity": "sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg==", + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.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" + } + }, + "make-dir": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", + "requires": { + "semver": "^6.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" + } + }, + "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==" + }, + "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" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "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=" + }, + "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.5", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.5.tgz", + "integrity": "sha512-ti7OGMOUOzo66wLF3liskw6YQIaSsBgc4GOAlWRnIEj8htCxJUxskanMUoJOD6MDCRAXo36goXJZch+nOS0VMA==" + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.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=" + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==" + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==" + }, + "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=" + } + } + }, + "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.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "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.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + } + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==" + }, + "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" + } + }, + "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" + } + }, + "wait-for-expect": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", + "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==" + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "requires": { + "makeerror": "1.0.x" + } + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "dependencies": { + "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.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "optional": true, + "requires": { + "node-pre-gyp": "*" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "3.2.6", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "optional": true, + "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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "optional": true + }, + "minipass": { + "version": "2.9.0", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "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-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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "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.41.5", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.5.tgz", + "integrity": "sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==", + "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.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" + }, + "cacache": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "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" + } + }, + "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" + } + }, + "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" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + } + } + }, + "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" + } + }, + "webpack-dev-server": { + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.2.tgz", + "integrity": "sha512-pxZKPYb+n77UN8u9YxXT4IaIrGcNtijh/mi8TXbErHmczw0DtPnMTTjHj+eNjkqLOaAZM/qD7V59j/qJsEiaZA==", + "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.2.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.6", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.25", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.4.0", + "spdy": "^4.0.1", + "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": "12.0.5" + }, + "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" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.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" + } + } + } + }, + "fsevents": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "optional": true, + "requires": { + "node-pre-gyp": "*" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.3", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "3.2.6", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.6", + "bundled": true, + "optional": true, + "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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "optional": true + }, + "minipass": { + "version": "2.9.0", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "optional": true + } + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "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" + } + }, + "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=" + }, + "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" + } + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "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-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.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_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" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^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" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "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" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + }, + "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" + } + }, + "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==" + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.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.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.0.tgz", + "integrity": "sha512-6qI/tTx7OVtA4qNqD0OyutbM6Z9EKu4rxWm/2Y3FDEBQ4/2X2XAnyuRXMzAE2+1BPyqzksJZtrIwblOHg0IEzA==", + "requires": { + "@babel/runtime": "^7.8.7" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "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.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==" + }, + "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" + } + } + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + } + } +} diff --git a/Website/hpiot-react/package.json b/Website/hpiot-react/package.json new file mode 100644 index 0000000..e51ed0c --- /dev/null +++ b/Website/hpiot-react/package.json @@ -0,0 +1,40 @@ +{ + "name": "hpiot-react", + "version": "0.1.0", + "private": true, + "dependencies": { + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.5.0", + "@testing-library/user-event": "^7.2.1", + "aws-amplify": "^2.2.6", + "aws-amplify-react": "^3.1.7", + "core-js": "^3.6.4", + "npx": "^10.2.2", + "react": "^16.13.1", + "react-charts": "^2.0.0-beta.6", + "react-dom": "^16.13.1", + "react-scripts": "3.4.0", + "recharts": "^1.8.5" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/Website/hpiot-react/public/favicon.ico b/Website/hpiot-react/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ed5a0e9514521441aa290cbcdb0496ed5e26bdcd GIT binary patch literal 3230 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 + + + + + + + + + + + + HP IoT + + + +
+ + + diff --git a/Website/hpiot-react/public/logo192.png b/Website/hpiot-react/public/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..fc44b0a3796c0e0a64c3d858ca038bd4570465d9 GIT binary patch literal 5347 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 b{|{}U^kRn2wo}j7|0ATu<;8xA7zX}7|B6mN literal 0 HcmV?d00001 diff --git a/Website/hpiot-react/public/manifest.json b/Website/hpiot-react/public/manifest.json new file mode 100644 index 0000000..080d6c7 --- /dev/null +++ b/Website/hpiot-react/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/Website/hpiot-react/public/robots.txt b/Website/hpiot-react/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/Website/hpiot-react/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/Website/hpiot-react/src/App.css b/Website/hpiot-react/src/App.css new file mode 100644 index 0000000..3676185 --- /dev/null +++ b/Website/hpiot-react/src/App.css @@ -0,0 +1,19 @@ +.App { + text-align: center; +} + +.App-header { + background-color: #282c34; + min-height: 4vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + diff --git a/Website/hpiot-react/src/App.js b/Website/hpiot-react/src/App.js new file mode 100644 index 0000000..7d22398 --- /dev/null +++ b/Website/hpiot-react/src/App.js @@ -0,0 +1,119 @@ +import React from 'react'; +import './App.css'; +import LineChart from './charts/LineChart'; +import BarChart from './charts/BarChart'; +import { WebSocketSubject } from 'rxjs/webSocket'; +import { Subject } from 'rxjs'; +import Amplify from 'aws-amplify'; +import awsconfig from './aws-exports'; +import { withAuthenticator } from 'aws-amplify-react'; // or 'aws-amplify-react-native'; +import {Auth} from 'aws-amplify'; +Amplify.configure(awsconfig); + + + let serverMessages = []; + let socket$ = new WebSocketSubject(); + let roles = []; + let groups = []; + let currentRole = ""; + let roleSubject = new Subject(); + let token = ""; + + +class Dashboard extends React.Component { + constructor(props) { + super(props); + this.state = { + promiseIsResolved: false + }; + + } + updateList(obj) { + //console.log(serverMessages); + //console.log(obj); + const index = serverMessages.findIndex((e) => e.location === obj.location); + + if (index === -1) { + serverMessages.push(obj); + + } else { + Object.keys(obj).forEach(element => { + serverMessages[index][element] = obj[element]; + }); + } + } + setRole(index) { + this.setState({promiseIsResolved: false}) + currentRole = roles[1]; + socket$.complete(); + serverMessages = []; + this.componentDidMount(); + } + componentDidMount(){ + Auth.currentAuthenticatedUser().then(data => { + //console.log(data); + roles = data.signInUserSession.idToken.payload['cognito:roles']; + groups = data.signInUserSession.idToken.payload['cognito:groups']; + groups.forEach( (element, index, array) => { + array[index] = element.replace(/_/g, ' '); + }); + if (! currentRole) { + currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0]; + } + token = data.signInUserSession.accessToken.jwtToken; + roleSubject.subscribe({ + next: r => r + }); + socket$ = new WebSocketSubject('wss://3fseaywb8b.execute-api.us-east-1.amazonaws.com/prototype?token=' + token + + '&role=' + currentRole); + socket$.subscribe((message) => { + if (message instanceof Array) { + message.forEach(element => { + this.updateList(element); + }); + } else { + this.updateList(message); + } + serverMessages.sort((a, b) => a.location.localeCompare(b.location)); + this.setState({promiseIsResolved: true}); + console.log(serverMessages); + }, + (err) => console.error(err), + () => console.warn('Complete: Websocket closed') + ); + socket$.next({action: 'getDashboardData', policy: currentRole}); + + }).catch((err) => + err + ); + } + render() { + if(!this.state.promiseIsResolved){return null} + else{ + return ( +
+
+
+
+
+ + +
+
+ ) + } + + } +} + +function App() { + + return ( +
+ + +
+ ); +} + +export default withAuthenticator(App, {includeGreetings: true}); diff --git a/Website/hpiot-react/src/App.test.js b/Website/hpiot-react/src/App.test.js new file mode 100644 index 0000000..4db7ebc --- /dev/null +++ b/Website/hpiot-react/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + const { getByText } = render(); + const linkElement = getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/Website/hpiot-react/src/aws-exports-old.js b/Website/hpiot-react/src/aws-exports-old.js new file mode 100644 index 0000000..26572cf --- /dev/null +++ b/Website/hpiot-react/src/aws-exports-old.js @@ -0,0 +1,16 @@ +// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten. + +const awsmobile = { + "aws_project_region": "us-east-1", + "aws_content_delivery_bucket": "hpiot-react-hpiot", + "aws_content_delivery_bucket_region": "us-east-1", + "aws_content_delivery_url": "http://hpiot-react-hpiot.s3-website-us-east-1.amazonaws.com", + "aws_cognito_identity_pool_id": "us-east-1:20972146-c6fe-4ada-a723-d1debcc7d074", + "aws_cognito_region": "us-east-1", + "aws_user_pools_id": "us-east-1_L6XsGIASX", + "aws_user_pools_web_client_id": "63ieddff77nfc3i151m8l8k3ip", + "oauth": {} +}; + + +export default awsmobile; diff --git a/Website/hpiot-react/src/aws-exports.js b/Website/hpiot-react/src/aws-exports.js new file mode 100644 index 0000000..240d354 --- /dev/null +++ b/Website/hpiot-react/src/aws-exports.js @@ -0,0 +1,18 @@ +// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten. + +const awsmobile = { + "aws_project_region": "us-east-1", + "aws_content_delivery_bucket": "hpiot-react-hpiot", + "aws_content_delivery_bucket_region": "us-east-1", + "aws_content_delivery_url": "http://hpiot-react-hpiot.s3-website-us-east-1.amazonaws.com", + "aws_cognito_identity_pool_id": "us-east-1:c018fdcf-3b1a-45db-a70e-daf34e217f8f", + "aws_cognito_region": "us-east-1", + "aws_user_pools_id": "us-east-1_XcUWWJXMT", + "aws_user_pools_web_client_id": "ms2jhuludm93g9qfpuio8m9k6", + "oauth": {}, + "aws_user_files_s3_bucket": "hpiotuserstorage-devs", + "aws_user_files_s3_bucket_region": "us-east-1" +}; + + +export default awsmobile; diff --git a/Website/hpiot-react/src/charts/BarChart.js b/Website/hpiot-react/src/charts/BarChart.js new file mode 100644 index 0000000..94517e0 --- /dev/null +++ b/Website/hpiot-react/src/charts/BarChart.js @@ -0,0 +1,37 @@ +import React, { PureComponent } from 'react'; +import { + BarChart, Bar, Brush, ReferenceLine, XAxis, YAxis, CartesianGrid, Tooltip, Legend, +} from 'recharts'; + + + +export default class Example extends PureComponent { + constructor(props) { + super(props); + this.state = { + data: this.props.data, + } + } + render() { + return ( + + + + + + + + + + + + ); + } +} diff --git a/Website/hpiot-react/src/charts/LineChart.js b/Website/hpiot-react/src/charts/LineChart.js new file mode 100644 index 0000000..4e5b435 --- /dev/null +++ b/Website/hpiot-react/src/charts/LineChart.js @@ -0,0 +1,144 @@ +import React, { PureComponent } from 'react'; +import { + Label, LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip, ReferenceArea, Brush +} from 'recharts'; + + + +const getAxisYDomain = (from, to, ref, offset, data) => { + const refData = data.slice(from - 1, to); + let [bottom, top] = [refData[0][ref], refData[0][ref]]; + refData.forEach((d) => { + if (d[ref] > top) top = d[ref]; + if (d[ref] < bottom) bottom = d[ref]; + }); + + return [(bottom | 0) - offset, (top | 0) + offset]; +}; + + +export default class Example extends PureComponent { + + constructor(props) { + super(props); + this.state = { + data: this.props.data, + left: 'dataMin', + right: 'dataMax', + refAreaLeft: '', + refAreaRight: '', + top: 'dataMax+1', + bottom: 'dataMin-1', + top2: 'dataMax+20', + bottom2: 'dataMin-20', + animation: true, + }; + } + + zoom() { + let { refAreaLeft, refAreaRight, data } = this.state; + if (refAreaLeft === refAreaRight || refAreaRight === '') { + this.setState(() => ({ + refAreaLeft: '', + refAreaRight: '', + })); + return; + } + + // xAxis domain + if (refAreaLeft > refAreaRight) [refAreaLeft, refAreaRight] = [refAreaRight, refAreaLeft]; + + // yAxis domain + let refAreaLeftNum = data.findIndex((e) => e.location === refAreaLeft); + let refAreaRightNum = data.findIndex((e) => e.location === refAreaRight); + console.log(refAreaLeft,refAreaRight); + const [bottom, top] = getAxisYDomain(refAreaLeftNum, refAreaRightNum, 'volumeflow', 5, data); + const [bottom2, top2] = getAxisYDomain(refAreaLeftNum, refAreaRightNum, 'depth', 50, data); + + this.setState(() => ({ + refAreaLeft: '', + refAreaRight: '', + data: data.slice(), + left: refAreaLeft, + right: refAreaRight, + bottom, + top, + bottom2, + top2, + })); + } + + zoomOut() { + const { data } = this.state; + this.setState(() => ({ + data: data.slice(), + refAreaLeft: '', + refAreaRight: '', + left: 'dataMin', + right: 'dataMax', + top: 'dataMax+1', + bottom: 'dataMin', + top2: 'dataMax+50', + bottom2: 'dataMin+50', + })); + } + + render() { + const { + data, barIndex, left, right, refAreaLeft, refAreaRight, top, bottom, top2, bottom2, + } = this.state; + return ( +
+ + + this.setState({ refAreaLeft: e.activeLabel })} + //onMouseMove={e => this.state.refAreaLeft && this.setState({ refAreaRight: e.activeLabel })} + //onMouseUp={this.zoom.bind(this)} + > + + + + + + + + + + + { + (refAreaLeft && refAreaRight) ? ( + ) : null + } + + +
+ ); + } +} diff --git a/Website/hpiot-react/src/index.css b/Website/hpiot-react/src/index.css new file mode 100644 index 0000000..ec2585e --- /dev/null +++ b/Website/hpiot-react/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/Website/hpiot-react/src/index.js b/Website/hpiot-react/src/index.js new file mode 100644 index 0000000..87d1be5 --- /dev/null +++ b/Website/hpiot-react/src/index.js @@ -0,0 +1,12 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; +import * as serviceWorker from './serviceWorker'; + +ReactDOM.render(, document.getElementById('root')); + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://bit.ly/CRA-PWA +serviceWorker.unregister(); diff --git a/Website/hpiot-react/src/logo.svg b/Website/hpiot-react/src/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/Website/hpiot-react/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Website/hpiot-react/src/serviceWorker.js b/Website/hpiot-react/src/serviceWorker.js new file mode 100644 index 0000000..c4838eb --- /dev/null +++ b/Website/hpiot-react/src/serviceWorker.js @@ -0,0 +1,141 @@ +// 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}$/ + ) +); + +export function register(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, 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, 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(); + }) + .catch(error => { + console.error(error.message); + }); + } +} diff --git a/Website/hpiot-react/src/setupTests.js b/Website/hpiot-react/src/setupTests.js new file mode 100644 index 0000000..74b1a27 --- /dev/null +++ b/Website/hpiot-react/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom/extend-expect'; diff --git a/Website/hpiot-react/yarn.lock b/Website/hpiot-react/yarn.lock new file mode 100644 index 0000000..8a66c2f --- /dev/null +++ b/Website/hpiot-react/yarn.lock @@ -0,0 +1,12884 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aws-amplify/analytics@^2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@aws-amplify/analytics/-/analytics-2.2.6.tgz#d57b5204280bd95ef3e432bdd016f0e6400b9a47" + integrity sha512-k9aNdeEVNugEgeRQDRtXxqoeqe0MQKWlVglHu1LLfN47Ux8EtGG8m1119MiGVol7eh58/+ZUL1fErNiZf26wWg== + dependencies: + "@aws-amplify/cache" "^2.1.6" + "@aws-amplify/core" "^2.2.5" + uuid "^3.2.1" + +"@aws-amplify/api@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@aws-amplify/api/-/api-2.1.6.tgz#b15ac333fb8cbc1e69850df699e9248889d563ff" + integrity sha512-Q3LUgscgkpJwK+tl9Ibc1asbSjyzb6IGxkodSNig8ieCXsX/bLpbsStBATl92pnDyCR6q3CDcewd09E4jEqlSQ== + dependencies: + "@aws-amplify/auth" "^2.1.6" + "@aws-amplify/cache" "^2.1.6" + "@aws-amplify/core" "^2.2.5" + axios "^0.19.0" + graphql "14.0.0" + uuid "^3.2.1" + zen-observable "^0.8.6" + +"@aws-amplify/auth@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@aws-amplify/auth/-/auth-2.1.6.tgz#f7202329e041d920420b396f76376c5c9ecb884c" + integrity sha512-8D5qtzuS3iiTUQk193fR5mztvOLWgk4kaVLMJG67kXWObCe1Rw73FAsCKRy1fqjSrT9z40c16eJso7m7YFBFRQ== + dependencies: + "@aws-amplify/cache" "^2.1.6" + "@aws-amplify/core" "^2.2.5" + amazon-cognito-identity-js "^3.2.5" + crypto-js "3.1.9-1" + +"@aws-amplify/cache@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@aws-amplify/cache/-/cache-2.1.6.tgz#c787015cf2730e8ef5268625b3022579bd71df5e" + integrity sha512-muEix+GT5D8DiMOsOfEEe8rGouw4ZZIB/MT9qJxRDy0lsmF/CSkpqTtn/ES2m+bux8KH6EWXIedDle/+duFdZw== + dependencies: + "@aws-amplify/core" "^2.2.5" + +"@aws-amplify/core@^2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@aws-amplify/core/-/core-2.2.5.tgz#8ae764df608acc609de9ecdc89f7640ed26496ae" + integrity sha512-l5DxgdO/OmnXnhefOFQdMAfx3Q5PX7s3IB8odi3MB+KErtaUm6rOXAkYE8r9IASQdbYvf9Ea4OzeM8Ztpdw/CQ== + dependencies: + aws-sdk "2.518.0" + url "^0.11.0" + zen-observable "^0.8.6" + +"@aws-amplify/interactions@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@aws-amplify/interactions/-/interactions-2.1.6.tgz#4760c2991e4ae39077c551432ed4fad43f4f29c6" + integrity sha512-qNOdVIjbCQ9FNtQAvMChIXSdADYLJd/hKtWc/viHQojqrb8qFMLjcVUMePlvxqrJoghbidYDYXX/icU/Z0pJGQ== + dependencies: + "@aws-amplify/core" "^2.2.5" + +"@aws-amplify/predictions@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@aws-amplify/predictions/-/predictions-2.1.6.tgz#16b243907eae9483ac1579b407a0019cd78f0233" + integrity sha512-1CZCUxz67M+nBXhALDeD7y4M/hCojzC7nR9GPIECZF4VIDjNNePUHtdit/3IgeEfoxA48ekhoZkcod6mdvy9bg== + dependencies: + "@aws-amplify/core" "^2.2.5" + "@aws-amplify/storage" "^2.2.1" + "@aws-sdk/eventstream-marshaller" "0.1.0-preview.2" + "@aws-sdk/util-utf8-node" "0.1.0-preview.1" + uuid "^3.2.1" + +"@aws-amplify/pubsub@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@aws-amplify/pubsub/-/pubsub-2.1.7.tgz#6ead5bbc2a88a05c0e7158928ca2ee5f6f176a8b" + integrity sha512-zVwJCBuhYNgPjFHUOkCbx7VEMWXvaiREdbnw6lk26lfXGd3Ot8gFY84e5DZEArZlg+gkuAzIEW3/eCCHD4BFVg== + dependencies: + "@aws-amplify/auth" "^2.1.6" + "@aws-amplify/cache" "^2.1.6" + "@aws-amplify/core" "^2.2.5" + graphql "14.0.0" + paho-mqtt "^1.1.0" + uuid "^3.2.1" + zen-observable "^0.8.6" + +"@aws-amplify/storage@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@aws-amplify/storage/-/storage-2.2.1.tgz#d0d731702506124989c4acc4a8d0491d602dcca3" + integrity sha512-dsHVj9ElzmYiy1kbomK4BNty2R4mV6CgLKAHQ/NwUtWRqT200dMNMfYD2Qvbjv8dL2XICalOV+t5VhPkwMBvJg== + dependencies: + "@aws-amplify/core" "^2.2.5" + +"@aws-amplify/ui@^1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@aws-amplify/ui/-/ui-1.1.5.tgz#1c5fe4e37926be01514317adf12056b35056733d" + integrity sha512-lMC43ZsBMKXmsoZevk1EYESVEQh4jlcL4LSMTtHRC1CUrYPIf4EssqPkbMmJEvs3J+8JIcV5aOL5o5enBmaKug== + +"@aws-amplify/xr@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@aws-amplify/xr/-/xr-1.1.6.tgz#8bba366a373aefe5f12492565672279fe2d6ce74" + integrity sha512-FneWKS1rCxH2HWHNv8b1RBRwakS1wVFt4UMlDT8jvXFZD6nzKXSmj2MoHvoGR97jn2PAxbUM1vSwHtzSl6wNkA== + dependencies: + "@aws-amplify/core" "^2.2.5" + +"@aws-crypto/crc32@^0.1.0-preview.1": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-0.1.0.tgz#c886c09f36958f076195a8accb71901bf8015424" + integrity sha512-iG2x3lF3H+ChYEJMu3zS7dYpYMLkdUs8AqOsjsvP9nv20KDJYbCVfMY2wDm5FLXTfCBzHIQNYscFuS1gQtPV+Q== + dependencies: + tslib "^1.9.3" + +"@aws-sdk/eventstream-marshaller@0.1.0-preview.2": + version "0.1.0-preview.2" + resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-marshaller/-/eventstream-marshaller-0.1.0-preview.2.tgz#494d0fa41c7a313a83209239006eb5f083af6fe9" + integrity sha512-StNivqLMGk+6Blp7eBYgLvidD9HEhthzNz7dBBAQPELx3Nd3imodzSvckDw5ZkuWt6ViP+aAl8HgQvJmD71M5Q== + dependencies: + "@aws-crypto/crc32" "^0.1.0-preview.1" + "@aws-sdk/types" "^0.1.0-preview.1" + "@aws-sdk/util-hex-encoding" "^0.1.0-preview.1" + tslib "^1.8.0" + +"@aws-sdk/is-array-buffer@^0.1.0-preview.1": + version "0.1.0-preview.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/is-array-buffer/-/is-array-buffer-0.1.0-preview.1.tgz#63cd8488faaf1a537817d0ef57fec3aa3bf030c4" + integrity sha512-9Qrr9w6sNX19N0eO7JBYjp86OPcOyjDPe580L5ISDKo7XfuzK20IC2TeGTZ77okhRTsm8rF5UgP9scBu59jwoA== + dependencies: + tslib "^1.8.0" + +"@aws-sdk/types@^0.1.0-preview.1": + version "0.1.0-preview.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-0.1.0-preview.1.tgz#6119574f873ec9a8ee2e5c1fbfb3ddcc9059c2f3" + integrity sha512-CcZpxyN2G0I7+Jyj0om3LafYX7d30JWJAAQ+53Ysjau7jyL/xLMMkLZgniQPV8BMV7uKLXyf4hwu8JSs0Ejb+w== + +"@aws-sdk/util-buffer-from@^0.1.0-preview.1": + version "0.1.0-preview.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-buffer-from/-/util-buffer-from-0.1.0-preview.1.tgz#b40c674044bf0997e0f170f692fbdaf7f5edd78c" + integrity sha512-i46iuFQA05+92L/epK7befgoxw6DM38LnaHjHNxRoJeIYUllZvpJst74FRCJ5UvVOaMDvHO3woWG+dY8/KVABw== + dependencies: + "@aws-sdk/is-array-buffer" "^0.1.0-preview.1" + tslib "^1.8.0" + +"@aws-sdk/util-hex-encoding@^0.1.0-preview.1": + version "0.1.0-preview.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-hex-encoding/-/util-hex-encoding-0.1.0-preview.1.tgz#198a5c351bb52baf7b80d5f3ce1cdd000e251bf5" + integrity sha512-97ZMVcJpIXwOQN2RntPimav6G5iod/QHEbqGrmaECXyjXzSrexKHRYjpQAtmJ7geZTMsofoRSdj3qZCymjn7Uw== + dependencies: + tslib "^1.8.0" + +"@aws-sdk/util-utf8-node@0.1.0-preview.1": + version "0.1.0-preview.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-node/-/util-utf8-node-0.1.0-preview.1.tgz#f776a087039df1825b83d9d8680a47f8172721ca" + integrity sha512-PSUsSJ0nnMPS389f0R3kIVR0BElnEb22Ofj40iO5HCtw9gZ1ot+enFdbOmW4m1e5+ED9U/Hqxqc7QhFWWF4NUQ== + dependencies: + "@aws-sdk/util-buffer-from" "^0.1.0-preview.1" + tslib "^1.8.0" + +"@babel/code-frame@7.8.3", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + +"@babel/compat-data@^7.8.4", "@babel/compat-data@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.6.tgz#7eeaa0dfa17e50c7d9c0832515eee09b56f04e35" + integrity sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q== + dependencies: + browserslist "^4.8.5" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" + integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helpers" "^7.8.4" + "@babel/parser" "^7.8.4" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.1.0", "@babel/core@^7.4.5": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.7.tgz#b69017d221ccdeb203145ae9da269d72cf102f3b" + integrity sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.7" + "@babel/helpers" "^7.8.4" + "@babel/parser" "^7.8.7" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.4.0", "@babel/generator@^7.8.4", "@babel/generator@^7.8.6", "@babel/generator@^7.8.7": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.8.tgz#cdcd58caab730834cee9eeadb729e833b625da3e" + integrity sha512-HKyUVu69cZoclptr8t8U5b6sx6zoWjh8jiUhnuj3MpZuKT2dJ8zPTuiy31luq32swhI0SpwItCIlU8XW7BZeJg== + dependencies: + "@babel/types" "^7.8.7" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-builder-react-jsx@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz#dee98d7d79cc1f003d80b76fe01c7f8945665ff6" + integrity sha512-JT8mfnpTkKNCboTqZsQTdGo3l3Ik3l7QIt9hh0O9DYiwVel37VoJpILKM4YFbP2euF32nkQSb+F9cUk9b7DDXQ== + dependencies: + "@babel/types" "^7.8.3" + esutils "^2.0.0" + +"@babel/helper-call-delegate@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz#28a279c2e6c622a6233da548127f980751324cab" + integrity sha512-doAA5LAKhsFCR0LAFIf+r2RSMmC+m8f/oQ+URnUET/rWeEzC0yTRmAGyWkD4sSu3xwbS7MYQ2u+xlt1V5R56KQ== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.7" + +"@babel/helper-compilation-targets@^7.8.4", "@babel/helper-compilation-targets@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" + integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== + dependencies: + "@babel/compat-data" "^7.8.6" + browserslist "^4.9.1" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-class-features-plugin@^7.8.3": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz#243a5b46e2f8f0f674dc1387631eb6b28b851de0" + integrity sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" + +"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" + integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.7.0" + +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== + dependencies: + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-transforms@^7.8.3": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz#6a13b5eecadc35692047073a64e42977b97654a4" + integrity sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.8.6" + lodash "^4.17.13" + +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== + dependencies: + lodash "^4.17.13" + +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" + integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" + +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helpers@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" + integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + +"@babel/highlight@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" + integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.4", "@babel/parser@^7.8.6", "@babel/parser@^7.8.7": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.8.tgz#4c3b7ce36db37e0629be1f0d50a571d2f86f6cd4" + integrity sha512-mO5GWzBPsPf6865iIbzNE0AvkKF3NE+2S3eRUpE+FE07BOAkXh6G+GW/Pj01hhXjve1WScbaIO4UlY1JKeqCcA== + +"@babel/plugin-proposal-async-generator-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + +"@babel/plugin-proposal-class-properties@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz#5e06654af5cd04b608915aada9b2a6788004464e" + integrity sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-proposal-decorators@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz#2156860ab65c5abf068c3f67042184041066543e" + integrity sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w== + dependencies: + "@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@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-numeric-separator@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" + integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + +"@babel/plugin-proposal-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" + integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz#ae10b3214cb25f7adb1f3bc87ba42ca10b7e2543" + integrity sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" + integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.8" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-decorators@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz#8d2c15a9f1af624b0025f961682a9d53d3001bda" + integrity sha512-8Hg4dNNT9/LcA1zQlfwuKR8BUc/if7Q7NkTam9sGTcJphLwpf2g4S42uhspQrIrR+dpzE0dtTqBVFoHl8GtnnQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-flow@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz#f2c883bd61a6316f2c89380ae5122f923ba4527f" + integrity sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz#521b06c83c40480f1e58b4fd33b92eceb1d6ea94" + integrity sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" + integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-typescript@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.8.3.tgz#c1f659dda97711a569cef75275f7e15dcaa6cabc" + integrity sha512-GO1MQ/SGGGoiEXY0e0bSpHimJvxqB7lktLLIq2pv8xG7WZ8IMEle74jIe1FhprHBWjwjZtXHkycDLZXIWM5Wfg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-arrow-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.8.3", "@babel/plugin-transform-classes@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz#77534447a477cbe5995ae4aee3e39fbc8090c46d" + integrity sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-destructuring@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b" + integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-dotall-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-duplicate-keys@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-flow-strip-types@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.8.3.tgz#da705a655466b2a9b36046b57bf0cbcd53551bd4" + integrity sha512-g/6WTWG/xbdd2exBBzMfygjX/zw4eyNC4X8pRaq7aRHRoDUCzAIu3kGYIXviOv8BjCuWm8vDBwjHcjiRNgXrPA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-flow" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.8.4", "@babel/plugin-transform-for-of@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz#a051bd1b402c61af97a27ff51b468321c7c2a085" + integrity sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-member-expression-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-modules-amd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" + integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" + integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" + integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-umd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" + integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + +"@babel/plugin-transform-new-target@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-object-super@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.8.4", "@babel/plugin-transform-parameters@^7.8.7": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.8.tgz#0381de466c85d5404565243660c4496459525daf" + integrity sha512-hC4Ld/Ulpf1psQciWWwdnUspQoQco2bMzSrwU6TmzRlvoYQe4rQFy9vnCZDTlVeCQj0JPfL+1RX0V8hCJvkgBA== + dependencies: + "@babel/helper-call-delegate" "^7.8.7" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-property-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-react-constant-elements@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.8.3.tgz#784c25294bddaad2323eb4ff0c9f4a3f6c87d6bc" + integrity sha512-glrzN2U+egwRfkNFtL34xIBYTxbbUF2qJTP8HD3qETBBqzAWSeNB821X0GjU06+dNpq/UyCIjI72FmGE5NNkQQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-react-display-name@7.8.3", "@babel/plugin-transform-react-display-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.8.3.tgz#70ded987c91609f78353dd76d2fb2a0bb991e8e5" + integrity sha512-3Jy/PCw8Fe6uBKtEgz3M82ljt+lTg+xJaM4og+eyu83qLT87ZUSckn0wy7r31jflURWLO83TW6Ylf7lyXj3m5A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-react-jsx-self@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.8.3.tgz#c4f178b2aa588ecfa8d077ea80d4194ee77ed702" + integrity sha512-01OT7s5oa0XTLf2I8XGsL8+KqV9lx3EZV+jxn/L2LQ97CGKila2YMroTkCEIE0HV/FF7CMSRsIAybopdN9NTdg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + +"@babel/plugin-transform-react-jsx-source@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz#951e75a8af47f9f120db731be095d2b2c34920e0" + integrity sha512-PLMgdMGuVDtRS/SzjNEQYUT8f4z1xb2BAT54vM1X5efkVuYBf5WyGUMbpmARcfq3NaglIwz08UVQK4HHHbC6ag== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + +"@babel/plugin-transform-react-jsx@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz#4220349c0390fdefa505365f68c103562ab2fc4a" + integrity sha512-r0h+mUiyL595ikykci+fbwm9YzmuOrUBi0b+FDIKmi3fPQyFokWVEMJnRWHJPPQEjyFJyna9WZC6Viv6UHSv1g== + dependencies: + "@babel/helper-builder-react-jsx" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + +"@babel/plugin-transform-regenerator@^7.8.3", "@babel/plugin-transform-regenerator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-runtime@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.8.3.tgz#c0153bc0a5375ebc1f1591cb7eea223adea9f169" + integrity sha512-/vqUt5Yh+cgPZXXjmaG9NT8aVfThKk7G4OqkVhrXqwsC5soMn/qTCxs36rZ2QFhpfTJcjw4SNDIZ4RUb8OL4jQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + resolve "^1.8.1" + semver "^5.5.1" + +"@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-sticky-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + +"@babel/plugin-transform-template-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-typeof-symbol@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-typescript@^7.8.3": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.7.tgz#48bccff331108a7b3a28c3a4adc89e036dc3efda" + integrity sha512-7O0UsPQVNKqpHeHLpfvOG4uXmlw+MOxYvUv6Otc9uH5SYMIxvF6eBdjkWvC3f9G+VXe0RsNExyAQBeTRug/wqQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-typescript" "^7.8.3" + +"@babel/plugin-transform-unicode-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/preset-env@7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.4.tgz#9dac6df5f423015d3d49b6e9e5fa3413e4a72c4e" + integrity sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w== + dependencies: + "@babel/compat-data" "^7.8.4" + "@babel/helper-compilation-targets" "^7.8.4" + "@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-object-rest-spread" "^7.8.3" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.8.3" + "@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-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.8.3" + "@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.8.4" + "@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.8.3" + "@babel/plugin-transform-modules-commonjs" "^7.8.3" + "@babel/plugin-transform-modules-systemjs" "^7.8.3" + "@babel/plugin-transform-modules-umd" "^7.8.3" + "@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.4" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.3" + "@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/types" "^7.8.3" + browserslist "^4.8.5" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/preset-env@^7.4.5": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.7.tgz#1fc7d89c7f75d2d70c2b6768de6c2e049b3cb9db" + integrity sha512-BYftCVOdAYJk5ASsznKAUl53EMhfBbr8CJ1X+AJLfGPscQkwJFiaV/Wn9DPH/7fzm2v6iRYJKYHSqyynTGw0nw== + dependencies: + "@babel/compat-data" "^7.8.6" + "@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-object-rest-spread" "^7.8.3" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.8.3" + "@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-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.8.6" + "@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.8.6" + "@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.8.3" + "@babel/plugin-transform-modules-commonjs" "^7.8.3" + "@babel/plugin-transform-modules-systemjs" "^7.8.3" + "@babel/plugin-transform-modules-umd" "^7.8.3" + "@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/types" "^7.8.7" + browserslist "^4.8.5" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/preset-react@7.8.3", "@babel/preset-react@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.8.3.tgz#23dc63f1b5b0751283e04252e78cf1d6589273d2" + integrity sha512-9hx0CwZg92jGb7iHYQVgi0tOEHP/kM60CtWJQnmbATSPIQQ2xYzfoCI3EdqAhFBeeJwYMdWQuDUHMsuDbH9hyQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-react-display-name" "^7.8.3" + "@babel/plugin-transform-react-jsx" "^7.8.3" + "@babel/plugin-transform-react-jsx-self" "^7.8.3" + "@babel/plugin-transform-react-jsx-source" "^7.8.3" + +"@babel/preset-typescript@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz#90af8690121beecd9a75d0cc26c6be39d1595d13" + integrity sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-typescript" "^7.8.3" + +"@babel/runtime-corejs3@^7.7.4": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.7.tgz#8209d9dff2f33aa2616cb319c83fe159ffb07b8c" + integrity sha512-sc7A+H4I8kTd7S61dgB9RomXu/C+F4IrRr4Ytze4dnfx7AXEpCrejSNpjx7vq6y/Bak9S6Kbk65a/WgMLtg43Q== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.4" + +"@babel/runtime@7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308" + integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ== + dependencies: + regenerator-runtime "^0.13.2" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.7.tgz#8fefce9802db54881ba59f90bb28719b4996324d" + integrity sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.1.2": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.4.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff" + integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.6" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.7.tgz#1fc9729e1acbb2337d5b6977a63979b4819f5d1d" + integrity sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + +"@csstools/normalize.css@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" + integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== + +"@hapi/address@2.x.x": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" + integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== + +"@hapi/bourne@1.x.x": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" + integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== + +"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== + +"@hapi/joi@^15.0.0": + version "15.1.1" + resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" + integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== + dependencies: + "@hapi/address" "2.x.x" + "@hapi/bourne" "1.x.x" + "@hapi/hoek" "8.x.x" + "@hapi/topo" "3.x.x" + +"@hapi/topo@3.x.x": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" + integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== + dependencies: + "@hapi/hoek" "^8.3.0" + +"@jest/console@^24.7.1", "@jest/console@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" + integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== + dependencies: + "@jest/source-map" "^24.9.0" + chalk "^2.0.1" + slash "^2.0.0" + +"@jest/core@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" + integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== + dependencies: + "@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" + +"@jest/environment@^24.3.0", "@jest/environment@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" + integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== + dependencies: + "@jest/fake-timers" "^24.9.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + jest-mock "^24.9.0" + +"@jest/fake-timers@^24.3.0", "@jest/fake-timers@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" + integrity sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A== + dependencies: + "@jest/types" "^24.9.0" + jest-message-util "^24.9.0" + jest-mock "^24.9.0" + +"@jest/reporters@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" + integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== + dependencies: + "@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@^24.3.0", "@jest/source-map@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" + integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.1.15" + source-map "^0.6.0" + +"@jest/test-result@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" + integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== + dependencies: + "@jest/console" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/istanbul-lib-coverage" "^2.0.0" + +"@jest/test-sequencer@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" + integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== + dependencies: + "@jest/test-result" "^24.9.0" + jest-haste-map "^24.9.0" + jest-runner "^24.9.0" + jest-runtime "^24.9.0" + +"@jest/transform@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" + integrity sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ== + dependencies: + "@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@^24.3.0", "@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + +"@jest/types@^25.1.0": + version "25.1.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.1.0.tgz#b26831916f0d7c381e11dbb5e103a72aed1b4395" + integrity sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" + integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== + +"@reach/observe-rect@^1.0.3": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@reach/observe-rect/-/observe-rect-1.1.0.tgz#4e967a93852b6004c3895d9ed8d4e5b41895afde" + integrity sha512-kE+jvoj/OyJV24C03VvLt5zclb9ArJi04wWXMMFwQvdZjdHoBlN4g0ZQFjyy/ejPF1Z/dpUD5dhRdBiUmIGZTA== + +"@sheerun/mutationobserver-shim@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" + integrity sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw== + +"@svgr/babel-plugin-add-jsx-attribute@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1" + integrity sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig== + +"@svgr/babel-plugin-remove-jsx-attribute@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz#297550b9a8c0c7337bea12bdfc8a80bb66f85abc" + integrity sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ== + +"@svgr/babel-plugin-remove-jsx-empty-expression@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz#c196302f3e68eab6a05e98af9ca8570bc13131c7" + integrity sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w== + +"@svgr/babel-plugin-replace-jsx-attribute-value@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz#310ec0775de808a6a2e4fd4268c245fd734c1165" + integrity sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w== + +"@svgr/babel-plugin-svg-dynamic-title@^4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz#2cdedd747e5b1b29ed4c241e46256aac8110dd93" + integrity sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w== + +"@svgr/babel-plugin-svg-em-dimensions@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz#9a94791c9a288108d20a9d2cc64cac820f141391" + integrity sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w== + +"@svgr/babel-plugin-transform-react-native-svg@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz#151487322843359a1ca86b21a3815fd21a88b717" + integrity sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw== + +"@svgr/babel-plugin-transform-svg-component@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz#5f1e2f886b2c85c67e76da42f0f6be1b1767b697" + integrity sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw== + +"@svgr/babel-preset@^4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-4.3.3.tgz#a75d8c2f202ac0e5774e6bfc165d028b39a1316c" + integrity sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A== + dependencies: + "@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@^4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-4.3.3.tgz#b37b89d5b757dc66e8c74156d00c368338d24293" + integrity sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w== + dependencies: + "@svgr/plugin-jsx" "^4.3.3" + camelcase "^5.3.1" + cosmiconfig "^5.2.1" + +"@svgr/hast-util-to-babel-ast@^4.3.2": + version "4.3.2" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz#1d5a082f7b929ef8f1f578950238f630e14532b8" + integrity sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg== + dependencies: + "@babel/types" "^7.4.4" + +"@svgr/plugin-jsx@^4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz#e2ba913dbdfbe85252a34db101abc7ebd50992fa" + integrity sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w== + dependencies: + "@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@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz#daac0a3d872e3f55935c6588dd370336865e9e32" + integrity sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w== + dependencies: + cosmiconfig "^5.2.1" + merge-deep "^3.0.2" + svgo "^1.2.2" + +"@svgr/webpack@4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-4.3.3.tgz#13cc2423bf3dff2d494f16b17eb7eacb86895017" + integrity sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg== + dependencies: + "@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" + +"@testing-library/dom@^6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-6.15.0.tgz#042abea7b4685b70d9a919100da9024507dc20bb" + integrity sha512-8N24c4XwOigPicwc8n4ECgEoJW2/mMzRJBxu4Uo0zhLERZTbNzqpL5fyCigu7JGUXX+ITuiK4z9/lnHbYRHLwQ== + dependencies: + "@babel/runtime" "^7.8.4" + "@sheerun/mutationobserver-shim" "^0.3.2" + "@types/testing-library__dom" "^6.12.1" + aria-query "^4.0.2" + dom-accessibility-api "^0.3.0" + pretty-format "^25.1.0" + wait-for-expect "^3.0.2" + +"@testing-library/jest-dom@^4.2.4": + version "4.2.4" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-4.2.4.tgz#00dfa0cbdd837d9a3c2a7f3f0a248ea6e7b89742" + integrity sha512-j31Bn0rQo12fhCWOUWy9fl7wtqkp7In/YP2p5ZFyRuiiB9Qs3g+hS4gAmDWONbAHcRmVooNJ5eOHQDCOmUFXHg== + dependencies: + "@babel/runtime" "^7.5.1" + chalk "^2.4.1" + css "^2.2.3" + css.escape "^1.5.1" + jest-diff "^24.0.0" + jest-matcher-utils "^24.0.0" + lodash "^4.17.11" + pretty-format "^24.0.0" + redent "^3.0.0" + +"@testing-library/react@^9.5.0": + version "9.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-9.5.0.tgz#71531655a7890b61e77a1b39452fbedf0472ca5e" + integrity sha512-di1b+D0p+rfeboHO5W7gTVeZDIK5+maEgstrZbWZSSvxDyfDRkkyBE1AJR5Psd6doNldluXlCWqXriUfqu/9Qg== + dependencies: + "@babel/runtime" "^7.8.4" + "@testing-library/dom" "^6.15.0" + "@types/testing-library__react" "^9.1.2" + +"@testing-library/user-event@^7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-7.2.1.tgz#2ad4e844175a3738cb9e7064be5ea070b8863a1c" + integrity sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA== + +"@types/babel__core@^7.1.0": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.6.tgz#16ff42a5ae203c9af1c6e190ed1f30f83207b610" + integrity sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg== + dependencies: + "@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.1" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" + integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" + integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.9.tgz#be82fab304b141c3eee81a4ce3b034d0eba1590a" + integrity sha512-jEFQ8L1tuvPjOI8lnpaf73oCJe+aoxL6ygqSy6c8LcW98zaC+4mzWuQIRCEvKeCOu+lbqdXcg4Uqmm1S8AP1tw== + dependencies: + "@babel/types" "^7.3.0" + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/eslint-visitor-keys@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" + integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== + +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/glob@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" + integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" + integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + +"@types/json-schema@^7.0.3": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" + integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== + +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +"@types/node@*": + version "13.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589" + integrity sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + +"@types/q@^1.5.1": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" + integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== + +"@types/react-dom@*": + version "16.9.5" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7" + integrity sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "16.9.23" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.23.tgz#1a66c6d468ba11a8943ad958a8cb3e737568271c" + integrity sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + +"@types/stack-utils@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" + integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== + +"@types/testing-library__dom@*", "@types/testing-library__dom@^6.12.1": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-6.14.0.tgz#1aede831cb4ed4a398448df5a2c54b54a365644e" + integrity sha512-sMl7OSv0AvMOqn1UJ6j1unPMIHRXen0Ita1ujnMX912rrOcawe4f7wu0Zt9GIQhBhJvH2BaibqFgQ3lP+Pj2hA== + dependencies: + pretty-format "^24.3.0" + +"@types/testing-library__react@^9.1.2": + version "9.1.3" + resolved "https://registry.yarnpkg.com/@types/testing-library__react/-/testing-library__react-9.1.3.tgz#35eca61cc6ea923543796f16034882a1603d7302" + integrity sha512-iCdNPKU3IsYwRK9JieSYAiX0+aYDXOGAmrC/3/M7AqqSDKnWWVv07X+Zk1uFSL7cMTUYzv4lQRfohucEocn5/w== + dependencies: + "@types/react-dom" "*" + "@types/testing-library__dom" "*" + pretty-format "^25.1.0" + +"@types/yargs-parser@*": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" + integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + +"@types/yargs@^13.0.0": + version "13.0.8" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.8.tgz#a38c22def2f1c2068f8971acb3ea734eb3c64a99" + integrity sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^15.0.0": + version "15.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" + integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^2.10.0": + version "2.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.23.0.tgz#aa7133bfb7b685379d9eafe4ae9e08b9037e129d" + integrity sha512-8iA4FvRsz8qTjR0L/nK9RcRUN3QtIHQiOm69FzV7WS3SE+7P7DyGGwh3k4UNR2JBbk+Ej2Io+jLAaqKibNhmtw== + dependencies: + "@typescript-eslint/experimental-utils" "2.23.0" + eslint-utils "^1.4.3" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + tsutils "^3.17.1" + +"@typescript-eslint/experimental-utils@2.23.0": + version "2.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.23.0.tgz#5d2261c8038ec1698ca4435a8da479c661dc9242" + integrity sha512-OswxY59RcXH3NNPmq+4Kis2CYZPurRU6mG5xPcn24CjFyfdVli5mySwZz/g/xDbJXgDsYqNGq7enV0IziWGXVQ== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.23.0" + eslint-scope "^5.0.0" + +"@typescript-eslint/parser@^2.10.0": + version "2.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.23.0.tgz#f3d4e2928ff647fe77fc2fcef1a3534fee6a3212" + integrity sha512-k61pn/Nepk43qa1oLMiyqApC6x5eP5ddPz6VUYXCAuXxbmRLqkPYzkFRKl42ltxzB2luvejlVncrEpflgQoSUg== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "2.23.0" + "@typescript-eslint/typescript-estree" "2.23.0" + eslint-visitor-keys "^1.1.0" + +"@typescript-eslint/typescript-estree@2.23.0": + version "2.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.23.0.tgz#d355960fab96bd550855488dcc34b9a4acac8d36" + integrity sha512-pmf7IlmvXdlEXvE/JWNNJpEvwBV59wtJqA8MLAxMKLXNKVRC3HZBXR/SlZLPWTCcwOSg9IM7GeRSV3SIerGVqw== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^6.3.0" + tsutils "^3.17.1" + +"@webassemblyjs/ast@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" + integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== + dependencies: + "@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@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" + integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== + +"@webassemblyjs/helper-api-error@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" + integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== + +"@webassemblyjs/helper-buffer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" + integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== + +"@webassemblyjs/helper-code-frame@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" + integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== + dependencies: + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/helper-fsm@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" + integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== + +"@webassemblyjs/helper-module-context@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" + integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== + dependencies: + "@webassemblyjs/ast" "1.8.5" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" + integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== + +"@webassemblyjs/helper-wasm-section@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" + integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + +"@webassemblyjs/ieee754@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" + integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" + integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" + integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== + +"@webassemblyjs/wasm-edit@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" + integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/helper-wasm-section" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-opt" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/wasm-gen@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" + integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wasm-opt@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" + integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + +"@webassemblyjs/wasm-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" + integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wast-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" + integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/floating-point-hex-parser" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-code-frame" "1.8.5" + "@webassemblyjs/helper-fsm" "1.8.5" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" + integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +JSONStream@~1.3.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abab@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" + integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== + +abbrev@1, abbrev@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-globals@^4.1.0, acorn-globals@^4.3.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" + integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + +acorn-jsx@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" + integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== + +acorn-walk@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== + +acorn@^5.5.3: + version "5.7.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" + integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== + +acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== + +acorn@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" + integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== + +address@1.1.2, address@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" + integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== + +adjust-sourcemap-loader@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz#6471143af75ec02334b219f54bc7970c52fb29a4" + integrity sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA== + dependencies: + assert "1.4.1" + camelcase "5.0.0" + loader-utils "1.2.3" + object-path "0.11.4" + regex-parser "2.2.10" + +agent-base@4, agent-base@^4.1.0, agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.3.0: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" + +aggregate-error@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" + integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" + integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== + +ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY= + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" + integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +amazon-cognito-identity-js@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-3.2.5.tgz#ddab4ef55288a3b8f973b97bbd418b68d47bfcda" + integrity sha512-DIJM6Spo4YErBxhCqCuQNVWwHG2XBE57Cvrt97L4mSziCTq612E9jerBxEb2+Iy/xjFZpL4Yzqxe+j3rJmBWEQ== + dependencies: + buffer "4.9.1" + crypto-js "3.1.9-1" + js-cookie "^2.1.4" + +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38= + dependencies: + string-width "^2.0.0" + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-escapes@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.2.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + dependencies: + type-fest "^0.11.0" + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0, ansi-regex@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.0.0, ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= + +ansistyles@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk= + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +aproba@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" + integrity sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw== + +archy@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +aria-query@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + +aria-query@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.0.2.tgz#250687b4ccde1ab86d127da0432ae3552fc7b145" + integrity sha512-S1G1V790fTaigUSM/Gd0NngzEfiMy9uTUfMyHhKhVyy4cH5O/eTuR01ydhGL0z4Za1PXFTRGH3qL8VhUQuEO5w== + dependencies: + "@babel/runtime" "^7.7.4" + "@babel/runtime-corejs3" "^7.7.4" + +arity-n@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745" + integrity sha1-2edrEXM+CFacCEeuezmyhgswt0U= + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-includes@^3.0.3, array-includes@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +array.prototype.flat@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asap@^2.0.0, asap@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= + +assert@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^9.6.1: + version "9.7.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378" + integrity sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g== + dependencies: + browserslist "^4.8.3" + caniuse-lite "^1.0.30001020" + chalk "^2.4.2" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.26" + postcss-value-parser "^4.0.2" + +aws-amplify-react@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/aws-amplify-react/-/aws-amplify-react-3.1.7.tgz#cf74dce6b2d271ab3b8b271b3830e976080ae940" + integrity sha512-karMa91pCiCVa/DS19SVR6K2Z+0bRWs6tSKiArpP8RPEnp91WGPgmMRmczAQPH3zM88wLGeeXDsHsM5UypgFxw== + dependencies: + qrcode.react "^0.8.0" + regenerator-runtime "^0.11.1" + +aws-amplify@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/aws-amplify/-/aws-amplify-2.2.6.tgz#cf53c22aa4f8b45df2c0f0dab011553e48966da3" + integrity sha512-yops+OW4Sc503KO6r76n065Na6PZ6BNFpieeLRuMeCBaWJ+9qJR59Xj5h0FZor+8nWMiGF5kd9TqSVTX2ecnPg== + dependencies: + "@aws-amplify/analytics" "^2.2.6" + "@aws-amplify/api" "^2.1.6" + "@aws-amplify/auth" "^2.1.6" + "@aws-amplify/cache" "^2.1.6" + "@aws-amplify/core" "^2.2.5" + "@aws-amplify/interactions" "^2.1.6" + "@aws-amplify/predictions" "^2.1.6" + "@aws-amplify/pubsub" "^2.1.7" + "@aws-amplify/storage" "^2.2.1" + "@aws-amplify/ui" "^1.1.5" + "@aws-amplify/xr" "^1.1.6" + +aws-sdk@2.518.0: + version "2.518.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.518.0.tgz#a0412cfcb41fd02e18d9e8b20c1dce356160fcc2" + integrity sha512-hwtKKf93TFyd3qugDW54ElpkUXhPe+ArPIHadre6IAFjCJiv08L8DaZKLRyclDnKfTavKe+f/PhdSEYo1QUHiA== + dependencies: + buffer "4.9.1" + events "1.1.1" + ieee754 "1.1.8" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8= + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.2.1, aws4@^1.8.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" + integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== + +axios@^0.19.0: + version "0.19.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" + integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== + dependencies: + follow-redirects "1.5.10" + +axobject-query@^2.0.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799" + integrity sha512-ICt34ZmrVt8UQnvPl6TVyDTkmhXmAyAT4Jh5ugfGUX4MOrZ+U/ZY6/sdylRw3qGNr9Ub5AJsaHeDMzNLehRdOQ== + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-eslint@10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" + integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-extract-comments@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21" + integrity sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ== + dependencies: + babylon "^6.18.0" + +babel-jest@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" + integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== + dependencies: + "@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@8.0.6: + version "8.0.6" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" + integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== + dependencies: + find-cache-dir "^2.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + pify "^4.0.1" + +babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854" + integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + find-up "^3.0.0" + istanbul-lib-instrument "^3.3.0" + test-exclude "^5.2.3" + +babel-plugin-jest-hoist@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" + integrity sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw== + dependencies: + "@types/babel__traverse" "^7.0.6" + +babel-plugin-macros@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + +babel-plugin-named-asset-import@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.6.tgz#c9750a1b38d85112c9e166bf3ef7c5dbc605f4be" + integrity sha512-1aGDUfL1qOOIoqk9QKGIo2lANk+C7ko/fqH0uIyC71x3PEGz0uVP8ISgfEsFuG+FKmjHTvFK/nNM8dowpmUxLA== + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= + +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY= + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-react-remove-prop-types@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" + integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== + +babel-preset-jest@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" + integrity sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg== + dependencies: + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + babel-plugin-jest-hoist "^24.9.0" + +babel-preset-react-app@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-9.1.1.tgz#d1ceb47cbe48b285fdd5c562c54c432ed5a41e0e" + integrity sha512-YkWP2UwY//TLltNlEBRngDOrYhvSLb+CA330G7T9M5UhGEMWe+JK/8IXJc5p2fDTSfSiETf+PY0+PYXFMix81Q== + dependencies: + "@babel/core" "7.8.4" + "@babel/plugin-proposal-class-properties" "7.8.3" + "@babel/plugin-proposal-decorators" "7.8.3" + "@babel/plugin-proposal-numeric-separator" "7.8.3" + "@babel/plugin-transform-flow-strip-types" "7.8.3" + "@babel/plugin-transform-react-display-name" "7.8.3" + "@babel/plugin-transform-runtime" "7.8.3" + "@babel/preset-env" "7.8.4" + "@babel/preset-react" "7.8.3" + "@babel/preset-typescript" "7.8.3" + "@babel/runtime" "7.8.4" + babel-plugin-macros "2.8.0" + babel-plugin-transform-react-remove-prop-types "0.4.24" + +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bluebird@~3.5.0: + version "3.5.5" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" + integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + 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" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + 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@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= + dependencies: + hoek "2.x.x" + +boxen@^1.0.0, boxen@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browser-resolve@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== + dependencies: + resolve "1.1.7" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@4.8.6: + version "4.8.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.6.tgz#96406f3f5f0755d272e27a66f4163ca821590a7e" + integrity sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg== + dependencies: + caniuse-lite "^1.0.30001023" + electron-to-chromium "^1.3.341" + node-releases "^1.1.47" + +browserslist@^4.0.0, browserslist@^4.6.2, browserslist@^4.6.4, browserslist@^4.8.3, browserslist@^4.8.5, browserslist@^4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.9.1.tgz#01ffb9ca31a1aef7678128fc6a2253316aa7287c" + integrity sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw== + dependencies: + caniuse-lite "^1.0.30001030" + electron-to-chromium "^1.3.363" + node-releases "^1.1.50" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cacache@^10.0.0: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cacache@^12.0.2: + version "12.0.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" + integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cacache@^13.0.1: + version "13.0.1" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" + integrity sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w== + dependencies: + chownr "^1.1.2" + figgy-pudding "^3.5.1" + fs-minipass "^2.0.0" + glob "^7.1.4" + graceful-fs "^4.2.2" + infer-owner "^1.0.4" + lru-cache "^5.1.1" + minipass "^3.0.0" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + p-map "^3.0.0" + promise-inflight "^1.0.1" + rimraf "^2.7.1" + ssri "^7.0.0" + unique-filename "^1.1.1" + +cacache@^9.2.9: + version "9.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-9.3.0.tgz#9cd58f2dd0b8c8cacf685b7067b416d6d3cf9db1" + integrity sha512-Vbi8J1XfC8v+FbQ6QkOtKXsHpPnB0i9uMeYFJoj40EbdOsEqWB3DPpNjfsnYBkqOPYA8UvrqH6FZPpBP0zdN7g== + dependencies: + bluebird "^3.5.0" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^1.3.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.1" + ssri "^4.1.6" + unique-filename "^1.1.0" + y18n "^3.2.1" + +cacache@~9.2.9: + version "9.2.9" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-9.2.9.tgz#f9d7ffe039851ec94c28290662afa4dd4bb9e8dd" + integrity sha512-ghg1j5OyTJ6qsrqU++dN23QiTDxb5AZCFGsF3oB+v9v/gY+F4X8L/0gdQMEjd+8Ot3D29M2etX5PKozHRn2JQw== + dependencies: + bluebird "^3.5.0" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^1.3.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.1" + ssri "^4.1.6" + unique-filename "^1.1.0" + y18n "^3.2.1" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +call-limit@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.1.tgz#ef15f2670db3f1992557e2d965abc459e6e358d4" + integrity sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ== + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" + integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== + dependencies: + pascal-case "^3.1.1" + tslib "^1.10.0" + +camelcase@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" + integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + +camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^4.0.0, camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001023, caniuse-lite@^1.0.30001030: + version "1.0.30001035" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001035.tgz#2bb53b8aa4716b2ed08e088d4dc816a5fe089a1e" + integrity sha512-C1ZxgkuA4/bUEdMbU5WrGY4+UhMFFiXrgNAfxiMIqWgFTWfv/xsZCS2xEHT2LMq7xAZfuAnu6mcqyDl0ZR6wLQ== + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +capture-stack-trace@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" + integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== + +case-sensitive-paths-webpack-plugin@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7" + integrity sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^1.0.0, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + 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" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@^2.0.2, chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" + integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.3.0" + optionalDependencies: + fsevents "~2.1.2" + +chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= + +chrome-trace-event@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== + dependencies: + tslib "^1.9.0" + +ci-info@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classnames@^2.2.5: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + +clean-css@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" + integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-deep@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" + integrity sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY= + dependencies: + 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" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +cmd-shim@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + integrity sha1-b8vamUg6j9FdfTChlspp1oii79s= + dependencies: + graceful-fs "^4.1.2" + mkdirp "~0.5.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0, color-convert@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" + integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +columnify@~1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + +combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.11.0, commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +common-tags@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compose-function@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" + integrity sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8= + dependencies: + arity-n "^1.0.4" + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0, concat-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config-chain@~1.1.11: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +configstore@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw== + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +confusing-browser-globals@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" + integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@1.7.0, convert-source-map@^1.4.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^0.3.3: + version "0.3.5" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" + integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA= + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js-compat@^3.6.2: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" + integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== + dependencies: + browserslist "^4.8.3" + semver "7.0.0" + +core-js-pure@^3.0.0: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" + integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== + +core-js@^2.4.0, core-js@^2.6.10: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + +core-js@^3.5.0: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647" + integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw== + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^5.0.0, cosmiconfig@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= + dependencies: + capture-stack-trace "^1.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + 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@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" + integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= + dependencies: + boom "2.x.x" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-js@3.1.9-1: + version "3.1.9-1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.9-1.tgz#fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8" + integrity sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg= + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= + +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== + dependencies: + postcss "^7.0.5" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + +css-loader@3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.2.tgz#d3fdb3358b43f233b78501c5ed7b1c6da6133202" + integrity sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.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" + +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +css-what@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1" + integrity sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw== + +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s= + +css@^2.0.0, css@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + +cssdb@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" + integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== + dependencies: + 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@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@^4.1.10: + version "4.1.10" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" + integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.7" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d" + integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg== + dependencies: + css-tree "1.0.0-alpha.37" + +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@^0.3.4: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^1.0.0, cssstyle@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== + dependencies: + cssom "0.3.x" + +csstype@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098" + integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q== + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +"d3-array@1.2.0 - 2": + version "2.4.0" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.4.0.tgz#87f8b9ad11088769c82b5ea846bcb1cc9393f242" + integrity sha512-KQ41bAF2BMakf/HdKT865ALd4cgND6VcIztVQZUTt0+BH3RWy6ZYnHghVXf6NFjt2ritLr8H1T8LreAAlfiNcw== + +d3-array@^1.2.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" + integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== + +d3-collection@1: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e" + integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A== + +d3-color@1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.0.tgz#89c45a995ed773b13314f06460df26d60ba0ecaf" + integrity sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg== + +d3-delaunay@^5.1.6: + version "5.2.1" + resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-5.2.1.tgz#0c4b280eb00194986ac4a3df9c81d32bf216cb36" + integrity sha512-ZZdeJl6cKRyqYVFYK+/meXvWIrAvZsZTD7WSxl4OPXCmuXNgDyACAClAJHD63zL25TA+IJGURUNO7rFseNFCYw== + dependencies: + delaunator "4" + +d3-format@1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.3.tgz#4e8eb4dff3fdcb891a8489ec6e698601c41b96f1" + integrity sha512-mm/nE2Y9HgGyjP+rKIekeITVgBtX97o1nrvHCWX8F/yBYyevUTvu9vb5pUnKwrcSw7o7GuwMOWjS9gFDs4O+uQ== + +d3-interpolate@1, d3-interpolate@^1.2.0, d3-interpolate@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987" + integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA== + dependencies: + d3-color "1" + +d3-path@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + +d3-scale@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f" + integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw== + dependencies: + d3-array "^1.2.0" + d3-collection "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-scale@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.2.1.tgz#da1684adce7261b4bc7a76fe193d887f0e909e69" + integrity sha512-huz5byJO/6MPpz6Q8d4lg7GgSpTjIZW/l+1MQkzKfu2u8P6hjaXaStOpmyrD6ymKoW87d2QVFCKvSjLwjzx/rA== + dependencies: + d3-array "1.2.0 - 2" + d3-format "1" + d3-interpolate "^1.2.0" + d3-time "1" + d3-time-format "2" + +d3-shape@^1.2.0, d3-shape@^1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +d3-time-format@2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.2.3.tgz#0c9a12ee28342b2037e5ea1cf0b9eb4dd75f29cb" + integrity sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA== + dependencies: + d3-time "1" + +d3-time@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" + integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== + +d3-voronoi@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" + integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg== + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +damerau-levenshtein@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791" + integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.0.0, data-urls@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0, debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= + +decamelize@^1.1.1, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decimal.js-light@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.0.tgz#ca7faf504c799326df94b0ab920424fdfc125348" + integrity sha512-b3VJCbd2hwUpeRGG3Toob+CRo8W22xplipNhP3tN7TSVB/cyMX71P1vM2Xjc9H74uV6dS2hDDmo/rHq8L87Upg== + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + 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-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@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" + +delaunator@4: + version "4.0.1" + resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-4.0.1.tgz#3d779687f57919a7a418f8ab947d3bddb6846957" + integrity sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-indent@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= + +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= + +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +detect-port-alt@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +dezalgo@^1.0.0, dezalgo@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + dependencies: + asap "^2.0.0" + wrappy "1" + +diff-sequences@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" + integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== + dependencies: + arrify "^1.0.1" + path-type "^3.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-accessibility-api@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.3.0.tgz#511e5993dd673b97c87ea47dba0e3892f7e0c983" + integrity sha512-PzwHEmsRP3IGY4gv/Ug+rMeaTIyTJvadCb+ujYXYeIylbHJezIyNToe8KfEgHTCEYyC+/bUghYOGg8yMGlZ6vA== + +dom-converter@^0.2: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-helpers@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" + integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== + dependencies: + "@babel/runtime" "^7.1.2" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domelementtype@1, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" + integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== + +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== + dependencies: + webidl-conversions "^4.0.2" + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1, domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.3.tgz#21d3b52efaaba2ea5fda875bb1aa8124521cf4aa" + integrity sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== + dependencies: + is-obj "^1.0.0" + +dot-prop@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== + dependencies: + is-obj "^2.0.0" + +dotenv-expand@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" + integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== + +dotenv@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + +dotenv@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" + integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +editor@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + integrity sha1-YMf4e9YrzGqJT6jM1q+3gjok90I= + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.341, electron-to-chromium@^1.3.363: + version "1.3.376" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.376.tgz#7cb7b5205564a06c8f8ecfbe832cbd47a1224bb1" + integrity sha512-cv/PYVz5szeMz192ngilmezyPNFkUjuynuL2vNdiqIrio440nfTDdc0JJU0TS2KHLSVCs9gBbt4CFqM+HcBnjw== + +elliptic@^6.0.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" + integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== + dependencies: + 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" + +emoji-regex@^7.0.1, emoji-regex@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" + integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" + integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + +"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: + version "1.17.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" + integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@2.0.3, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escodegen@^1.11.0, escodegen@^1.9.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" + integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-config-react-app@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.0.tgz#135110ba56a9e378f7acfe5f36e2ae76a2317899" + integrity sha512-WrHjoGpKr1kLLiWDD81tme9jMM0hk5cMxasLSdyno6DdPt+IfLOrDJBVo6jN7tn4y1nzhs43TmUaZWO6Sf0blw== + dependencies: + confusing-browser-globals "^1.0.9" + +eslint-import-resolver-node@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" + integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== + dependencies: + debug "^2.6.9" + resolve "^1.13.1" + +eslint-loader@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-3.0.3.tgz#e018e3d2722381d982b1201adb56819c73b480ca" + integrity sha512-+YRqB95PnNvxNp1HEjQmvf9KNvCin5HXYYseOXVC2U0KEcw4IkQ2IQEBG46j7+gW39bMzeu0GsUhVbBY3Votpw== + dependencies: + 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@^2.4.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz#7878f7504824e1b857dd2505b59a8e5eda26a708" + integrity sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q== + dependencies: + debug "^2.6.9" + pkg-dir "^2.0.0" + +eslint-plugin-flowtype@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz#82b2bd6f21770e0e5deede0228e456cb35308451" + integrity sha512-W5hLjpFfZyZsXfo5anlu7HM970JBDqbEshAJUkeczP6BFCIfJXuiIBQXyberLRtOStT0OGPF8efeTbxlHk4LpQ== + dependencies: + lodash "^4.17.15" + +eslint-plugin-import@2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz#d749a7263fb6c29980def8e960d380a6aa6aecaa" + integrity sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ== + dependencies: + 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" + +eslint-plugin-jsx-a11y@6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" + integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== + dependencies: + "@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" + +eslint-plugin-react-hooks@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04" + integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA== + +eslint-plugin-react@7.18.0: + version "7.18.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz#2317831284d005b30aff8afb7c4e906f13fa8e7e" + integrity sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ== + dependencies: + 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.14.2" + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.3" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.1.0.tgz#c5c0b66f383e7656404f86b31334d72524eddb48" + integrity sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q== + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +esutils@^2.0.0, esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" + integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + +events@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + +events@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.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" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expect@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" + integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== + dependencies: + "@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@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + 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" + +ext@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" + integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== + dependencies: + type "^2.0.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + +fast-glob@^2.0.2: + version "2.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" + integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== + dependencies: + "@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" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.1: + version "0.11.3" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" + integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +file-loader@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.3.0.tgz#780f040f729b3d18019f20605f723e844b8a58af" + integrity sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA== + dependencies: + loader-utils "^1.2.3" + schema-utils "^2.5.0" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filesize@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.0.1.tgz#f850b509909c7c86f7e450ea19006c31c2ed3d2f" + integrity sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + 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" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-cache-dir@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@4.1.0, find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + +follow-redirects@^1.0.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.10.0.tgz#01f5263aee921c6a54fb91667f08f4155ce169eb" + integrity sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ== + dependencies: + debug "^3.0.0" + +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +fork-ts-checker-webpack-plugin@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz#a1642c0d3e65f50c2cc1742e9c0a80f441f86b19" + integrity sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ== + dependencies: + 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" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + integrity sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE= + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-1.3.0.tgz#88413baaa5f9a597cfde9221d86986cd3c061dfd" + integrity sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0= + dependencies: + inherits "~2.0.1" + readable-stream "~1.1.10" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-vacuum@~1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" + integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY= + dependencies: + graceful-fs "^4.1.2" + path-is-inside "^1.0.1" + rimraf "^2.5.2" + +fs-write-stream-atomic@^1.0.8, fs-write-stream-atomic@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@2.1.2, fsevents@~2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== + +fsevents@^1.2.7: + version "1.2.11" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3" + integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fstream-ignore@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + integrity sha1-nDHa40dnAY/h0kmyTa2mfQktoQU= + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream-npm@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/fstream-npm/-/fstream-npm-1.2.1.tgz#08c4a452f789dcbac4c89a4563c902b2c862fd5b" + integrity sha512-iBHpm/LmD1qw0TlHMAqVd9rwdU6M+EHRUnPkXpRi5G/Hf0FIFH+oZFryodAU2MFNfGRh/CzhUFlMKV3pdeOTDw== + dependencies: + fstream-ignore "^1.0.0" + inherits "2" + +fstream@^1.0.0, fstream@^1.0.12, fstream@~1.0.11: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +genfun@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1" + integrity sha1-7RAEHy5KfxsKOEZtF6XD4n3x38E= + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@^5.0.0, glob-parent@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" + integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + +glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.2: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= + dependencies: + ini "^1.3.4" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +globby@8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" + integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w== + dependencies: + 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" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + +graceful-fs@~4.1.11: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +graphql@14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.0.0.tgz#4ee771c5266d08cb75df2d3ac41e8dd51ce3d599" + integrity sha512-HGVcnO6B25YZcSt6ZsH6/N+XkYuPA7yMqJmlJ4JWxWlS4Tr8SHI56R1Ocs8Eor7V7joEZPRXPDH8RRdll1w44Q== + dependencies: + iterall "^1.2.2" + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + +gzip-size@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" + integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== + dependencies: + duplexer "^0.1.1" + pify "^4.0.1" + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + integrity sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4= + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + integrity sha1-M0gdDxu/9gDdID11gSpqX7oALio= + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +har-validator@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +harmony-reflect@^1.4.6: + version "1.6.1" + resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.1.tgz#c108d4f2bb451efef7a37861fdbdae72c9bdefa9" + integrity sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA== + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-unicode@^2.0.0, has-unicode@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= + +hosted-git-info@^2.1.4, hosted-git-info@^2.4.2, hosted-git-info@^2.7.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +hosted-git-info@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + integrity sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-comment-regex@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" + integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== + dependencies: + whatwg-encoding "^1.0.1" + +html-entities@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= + +html-escaper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491" + integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig== + +html-minifier-terser@^5.0.1: + version "5.0.4" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.0.4.tgz#e8cc02748acb983bd7912ea9660bd31c0702ec32" + integrity sha512-fHwmKQ+GzhlqdxEtwrqLT7MSuheiA+rif5/dZgbz3GjoMXJzcRzy1L9NXoiiyxrnap+q5guSiv8Tz5lrh9g42g== + dependencies: + camel-case "^4.1.1" + clean-css "^4.2.3" + commander "^4.1.1" + he "^1.2.0" + param-case "^3.0.3" + relateurl "^0.2.7" + terser "^4.6.3" + +html-webpack-plugin@4.0.0-beta.11: + version "4.0.0-beta.11" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz#3059a69144b5aecef97708196ca32f9e68677715" + integrity sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg== + dependencies: + 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" + +htmlparser2@^3.3.0: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + 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" + +http-cache-semantics@^3.8.0: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +"http-parser-js@>=0.4.0 <0.4.11": + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= + +http-proxy-agent@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" + integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8= + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https-proxy-agent@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-utils@^4.0.0, icss-utils@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + +identity-obj-proxy@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" + integrity sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ= + dependencies: + harmony-reflect "^1.4.6" + +ieee754@1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + integrity sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q= + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +iferr@^0.1.5, iferr@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +immer@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" + integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= + dependencies: + import-from "^2.1.0" + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-fresh@^3.0.0, import-fresh@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= + dependencies: + resolve-from "^3.0.0" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +infer-owner@^1.0.3, infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4, inflight@~1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0, ini@~1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +init-package-json@~1.10.1: + version "1.10.3" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe" + integrity sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw== + dependencies: + glob "^7.1.1" + npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "1 || 2" + semver "2.x || 3.x || 4 || 5" + validate-npm-package-license "^3.0.1" + validate-npm-package-name "^3.0.0" + +inquirer@7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" + integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ== + dependencies: + 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" + +inquirer@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" + integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^3.0.0" + 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.4.0" + rxjs "^6.5.3" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +invariant@^2.2.2, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.4, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" + integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-buffer@^1.0.2, is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + +is-ci@^1.0.10: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" + integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== + dependencies: + ci-info "^1.5.0" + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + 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-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-docker@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" + integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^1.0.0, is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= + dependencies: + path-is-inside "^1.0.1" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= + +is-regex@^1.0.4, is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== + dependencies: + has "^1.0.3" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-retry-allowed@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + +is-root@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-wsl@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" + integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== + +istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" + integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== + dependencies: + "@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@^2.0.4: + version "2.0.8" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" + integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== + dependencies: + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + supports-color "^6.1.0" + +istanbul-lib-source-maps@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" + source-map "^0.6.1" + +istanbul-reports@^2.2.6: + version "2.2.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" + integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== + dependencies: + html-escaper "^2.0.0" + +iterall@^1.2.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + +jest-changed-files@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" + integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== + dependencies: + "@jest/types" "^24.9.0" + execa "^1.0.0" + throat "^4.0.0" + +jest-cli@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" + integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== + dependencies: + "@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-config@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" + integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== + dependencies: + "@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@^24.0.0, jest-diff@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" + integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== + dependencies: + chalk "^2.0.1" + diff-sequences "^24.9.0" + jest-get-type "^24.9.0" + pretty-format "^24.9.0" + +jest-docblock@^24.3.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" + integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== + dependencies: + detect-newline "^2.1.0" + +jest-each@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" + integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== + dependencies: + "@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-fourteen@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz#4cd0042f58b4ab666950d96532ecb2fc188f96fb" + integrity sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q== + dependencies: + "@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" + +jest-environment-jsdom@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" + integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== + dependencies: + "@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-node@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" + integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== + dependencies: + "@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@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" + integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== + +jest-haste-map@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" + integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== + dependencies: + "@jest/types" "^24.9.0" + anymatch "^2.0.0" + fb-watchman "^2.0.0" + 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" + optionalDependencies: + fsevents "^1.2.7" + +jest-jasmine2@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" + integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== + dependencies: + "@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@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" + integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== + dependencies: + jest-get-type "^24.9.0" + pretty-format "^24.9.0" + +jest-matcher-utils@^24.0.0, jest-matcher-utils@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" + integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== + dependencies: + chalk "^2.0.1" + jest-diff "^24.9.0" + jest-get-type "^24.9.0" + pretty-format "^24.9.0" + +jest-message-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" + integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== + dependencies: + "@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@^24.0.0, jest-mock@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" + integrity sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w== + dependencies: + "@jest/types" "^24.9.0" + +jest-pnp-resolver@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" + integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== + +jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" + integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== + +jest-resolve-dependencies@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" + integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== + dependencies: + "@jest/types" "^24.9.0" + jest-regex-util "^24.3.0" + jest-snapshot "^24.9.0" + +jest-resolve@24.9.0, jest-resolve@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" + integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== + dependencies: + "@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-runner@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" + integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== + dependencies: + "@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@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" + integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== + dependencies: + "@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@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" + integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== + +jest-snapshot@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" + integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== + dependencies: + "@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" + +jest-util@^24.0.0, jest-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" + integrity sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg== + dependencies: + "@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" + +jest-validate@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" + integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== + dependencies: + "@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@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz#e5be959698a7fa2302229a5082c488c3c8780a4a" + integrity sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q== + dependencies: + 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" + +jest-watcher@^24.3.0, jest-watcher@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" + integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== + dependencies: + "@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" + +jest-worker@^24.6.0, jest-worker@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" + integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== + dependencies: + merge-stream "^2.0.0" + supports-color "^6.1.0" + +jest-worker@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.1.0.tgz#75d038bad6fdf58eba0d2ec1835856c497e3907a" + integrity sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg== + dependencies: + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest@24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" + integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== + dependencies: + import-local "^2.0.0" + jest-cli "^24.9.0" + +jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= + +js-cookie@^2.1.4: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + +js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^11.5.1: + version "11.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== + dependencies: + 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" + +jsdom@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-14.1.0.tgz#916463b6094956b0a6c1782c94e380cd30e1981b" + integrity sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng== + dependencies: + 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" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" + integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== + dependencies: + minimist "^1.2.0" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz#8a9364e402448a3ce7f14d357738310d9248054f" + integrity sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA== + dependencies: + array-includes "^3.0.3" + object.assign "^4.1.0" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" + integrity sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU= + dependencies: + is-buffer "^1.0.2" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +last-call-webpack-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" + integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== + dependencies: + lodash "^4.17.5" + webpack-sources "^1.1.0" + +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU= + dependencies: + package-json "^4.0.0" + +lazy-cache@^0.2.3: + version "0.2.7" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" + integrity sha1-f+3fLctu23fRHvHRF6tf/fCrG2U= + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= + +lazy-property@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147" + integrity sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc= + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libnpx@10.2.2: + version "10.2.2" + resolved "https://registry.yarnpkg.com/libnpx/-/libnpx-10.2.2.tgz#5a4171b9b92dd031463ef66a4af9f5cbd6b09572" + integrity sha512-ujaYToga1SAX5r7FU5ShMFi88CWpY75meNZtr6RtEyv4l2ZK3+Wgvxq2IqlwWBiDZOqhumdeiocPS1aKrCMe3A== + dependencies: + dotenv "^5.0.1" + npm-package-arg "^6.0.0" + rimraf "^2.6.2" + safe-buffer "^5.1.0" + update-notifier "^2.3.0" + which "^1.3.0" + y18n "^4.0.0" + yargs "^11.0.0" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +loader-fs-cache@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.2.tgz#54cedf6b727e1779fd8f01205f05f6e88706f086" + integrity sha512-70IzT/0/L+M20jUlEqZhZyArTU6VKLRTYRDAYN26g4jfzpJqjipLL3/hgYpySqI9PwsVRHHFja0LfEmsx9X2Cw== + dependencies: + find-cache-dir "^0.1.1" + mkdirp "0.5.1" + +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lockfile@~1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" + integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== + dependencies: + signal-exit "^3.0.2" + +lodash._baseuniq@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg= + dependencies: + lodash._createset "~4.0.0" + lodash._root "~3.0.0" + +lodash._createset@~4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash._root@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= + +lodash.clonedeep@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.template@^4.4.0, lodash.template@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= + +lodash.union@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + +lodash.uniq@^4.5.0, lodash.uniq@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash.without@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= + +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@~4.17.4: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +loglevel@^1.6.6: + version "1.6.7" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.7.tgz#b3e034233188c68b889f5b862415306f565e2c56" + integrity sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" + integrity sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ== + dependencies: + tslib "^1.10.0" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@~4.1.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" + integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== + dependencies: + semver "^6.0.0" + +make-fetch-happen@^2.4.13: + version "2.6.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-2.6.0.tgz#8474aa52198f6b1ae4f3094c04e8370d35ea8a38" + integrity sha512-FFq0lNI0ax+n9IWzWpH8A4JdgYiAp2DDYIZ3rsaav8JDe8I+72CzK6PQW/oom15YDZpV5bYW/9INd6nIJ2ZfZw== + dependencies: + agentkeepalive "^3.3.0" + cacache "^10.0.0" + http-cache-semantics "^3.8.0" + http-proxy-agent "^2.0.0" + https-proxy-agent "^2.1.0" + lru-cache "^4.1.1" + mississippi "^1.2.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^3.0.1" + ssri "^5.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-expression-evaluator@^1.2.14: + version "1.2.22" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.22.tgz#c14dcb3d8b4d150e5dcea9c68c8dad80309b0d5e" + integrity sha512-L0j0tFVZBQQLeEjmWOvDLoRciIY8gQGWahvkztXUal8jH8R5Rlqo9GCvgqvXcy9LQhEWdQCVvzqAbxgYNt4blQ== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-deep@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2" + integrity sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA== + dependencies: + arr-union "^3.1.0" + clone-deep "^0.2.4" + kind-of "^3.0.2" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.2.3: + version "1.3.0" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" + integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +microevent.ts@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" + integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.43.0, "mime-db@>= 1.43.0 < 2": + version "1.43.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" + integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.7: + version "2.1.26" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" + integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== + dependencies: + mime-db "1.43.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.4: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + +mimic-fn@^2.0.0, mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +min-indent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" + integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= + +mini-css-extract-plugin@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" + integrity sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A== + dependencies: + loader-utils "^1.1.0" + normalize-url "1.9.1" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.1, minimist@^1.2.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.4.tgz#40357ef9582f8cd42ba8eaa274ddcf27f0c979b7" + integrity sha512-wTiNDqe4D2rbTJGZk1qcdZgFtY0/r+iuE6GDT7V0/+Gu5MLpIDm4+CssDECR79OJs/OxLPXMzdxy153b5Qy3hg== + +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz#3dcb6bb4a546e32969c7ad710f2c79a86abba93a" + integrity sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" + integrity sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w== + dependencies: + yallist "^4.0.0" + +mississippi@^1.2.0, mississippi@^1.3.0, mississippi@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-1.3.1.tgz#2a8bb465e86550ac8b36a7b6f45599171d78671e" + integrity sha512-/6rB8YXFbAtsUVRphIRQqB0+9c7VaPHCjVtvto+JqwVxgz8Zz+I+f68/JgQ+Pb4VlZb2svA9OtdXnHHsZz7ltg== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^1.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mixin-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= + dependencies: + for-in "^0.1.3" + is-extendable "^0.1.1" + +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +move-concurrently@^1.0.1, move-concurrently@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.0.0, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +mute-stream@0.0.8, mute-stream@~0.0.4: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.5.0, neo-async@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" + integrity sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw== + dependencies: + lower-case "^2.0.1" + tslib "^1.10.0" + +node-fetch-npm@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.3.tgz#efae4aacb0500444e449a51fc1467397775ebc38" + integrity sha512-DgwoKEsqLnFZtk3ap7GWBHcHwnUhsNmQqEDcdjfQ8GofLEFJ081NAd4Uin3R7RFZBWVJCwHISw1oaEqPgSLloA== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-forge@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" + integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== + +node-gyp@~3.6.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.3.tgz#369fcb09146ae2167f25d8d23d8b49cc1a110d8d" + integrity sha512-7789TDMqJpv5iHxn1cAESCBEC/sBHAFxAvgXAcvzWenEWl0qf6E2Kk/Xwdl5ZclktUJzxJPVa27OMkBvaHKqCQ== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request ">=2.9.0 <2.82.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-notifier@^5.4.2: + version "5.4.3" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" + integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== + dependencies: + growly "^1.3.0" + is-wsl "^1.1.0" + semver "^5.5.0" + shellwords "^0.1.1" + which "^1.3.0" + +node-releases@^1.1.47, node-releases@^1.1.50: + version "1.1.52" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" + integrity sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ== + dependencies: + semver "^6.3.0" + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-package-data@~2.4.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.2.tgz#6b2abd85774e51f7936f1395e45acb905dc849b2" + integrity sha512-YcMnjqeoUckXTPKZSAsPjUPLxH85XotbpqK3w4RyCwdFQSU5FxxBys8buehkSfg0j9fKvV1hn7O0+8reEgkAiw== + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +npm-cache-filename@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + integrity sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE= + +npm-install-checks@~3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.2.tgz#ab2e32ad27baa46720706908e5b14c1852de44d9" + integrity sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg== + dependencies: + semver "^2.3.0 || 3.x || 4 || 5" + +npm-normalize-package-bin@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +"npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0", npm-package-arg@^5.1.2, npm-package-arg@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-5.1.2.tgz#fb18d17bb61e60900d6312619919bd753755ab37" + integrity sha512-wJBsrf0qpypPT7A0LART18hCdyhpCMxeTtcb0X4IZO2jsP6Om7EHN1d9KSKiqD+KVH030RVNpWS9thk+pb7wzA== + dependencies: + hosted-git-info "^2.4.2" + osenv "^0.1.4" + semver "^5.1.0" + validate-npm-package-name "^3.0.0" + +"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" + integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== + dependencies: + hosted-git-info "^2.7.1" + osenv "^0.1.5" + semver "^5.6.0" + validate-npm-package-name "^3.0.0" + +npm-pick-manifest@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-1.0.4.tgz#a5ee6510c1fe7221c0bc0414e70924c14045f7e8" + integrity sha512-MKxNdeyOZysPRTTbHtW0M5Fw38Jo/3ARsoGw5qjCfS+XGjvNB/Gb4qtAZUFmKPM2mVum+eX559eHvKywU856BQ== + dependencies: + npm-package-arg "^5.1.2" + semver "^5.3.0" + +npm-registry-client@~8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.4.0.tgz#d52b901685647fc62a4c03eafecb6ceaa5018d4c" + integrity sha512-PVNfqq0lyRdFnE//nDmn3CC9uqTsr8Bya9KPLIevlXMfkP0m4RpCVyFFk0W1Gfx436kKwyhLA6J+lV+rgR81gQ== + dependencies: + concat-stream "^1.5.2" + graceful-fs "^4.1.6" + normalize-package-data "~1.0.1 || ^2.0.0" + npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0" + once "^1.3.3" + request "^2.74.0" + retry "^0.10.0" + semver "2 >=2.2.1 || 3.x || 4 || 5" + slide "^1.1.3" + ssri "^4.1.2" + optionalDependencies: + npmlog "2 || ^3.1.0 || ^4.0.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-user-validate@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951" + integrity sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE= + +npm@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm/-/npm-5.1.0.tgz#cf8201e044018e9c89532041c90094541982b2c0" + integrity sha512-pt5ClxEmY/dLpb60SmGQQBKi3nB6Ljx1FXmpoCUdAULlGqGVn2uCyXxPCWFbcuHGthT7qGiaGa1wOfs/UjGYMw== + dependencies: + JSONStream "~1.3.1" + abbrev "~1.1.0" + ansi-regex "~3.0.0" + ansicolors "~0.3.2" + ansistyles "~0.1.3" + aproba "~1.1.2" + archy "~1.0.0" + bluebird "~3.5.0" + cacache "~9.2.9" + call-limit "~1.1.0" + chownr "~1.0.1" + cmd-shim "~2.0.2" + columnify "~1.5.4" + config-chain "~1.1.11" + detect-indent "~5.0.0" + dezalgo "~1.0.3" + editor "~1.0.0" + fs-vacuum "~1.2.10" + fs-write-stream-atomic "~1.0.10" + fstream "~1.0.11" + fstream-npm "~1.2.1" + glob "~7.1.2" + graceful-fs "~4.1.11" + has-unicode "~2.0.1" + hosted-git-info "~2.5.0" + iferr "~0.1.5" + inflight "~1.0.6" + inherits "~2.0.3" + ini "~1.3.4" + init-package-json "~1.10.1" + lazy-property "~1.0.0" + lockfile "~1.0.3" + lodash._baseuniq "~4.6.0" + lodash.clonedeep "~4.5.0" + lodash.union "~4.6.0" + lodash.uniq "~4.5.0" + lodash.without "~4.4.0" + lru-cache "~4.1.1" + mississippi "~1.3.0" + mkdirp "~0.5.1" + move-concurrently "~1.0.1" + node-gyp "~3.6.2" + nopt "~4.0.1" + normalize-package-data "~2.4.0" + npm-cache-filename "~1.0.2" + npm-install-checks "~3.0.0" + npm-package-arg "~5.1.2" + npm-registry-client "~8.4.0" + npm-user-validate "~1.0.0" + npmlog "~4.1.2" + once "~1.4.0" + opener "~1.4.3" + osenv "~0.1.4" + pacote "~2.7.38" + path-is-inside "~1.0.2" + promise-inflight "~1.0.1" + read "~1.0.7" + read-cmd-shim "~1.0.1" + read-installed "~4.0.3" + read-package-json "~2.0.9" + read-package-tree "~5.1.6" + readable-stream "~2.3.2" + request "~2.81.0" + retry "~0.10.1" + rimraf "~2.6.1" + safe-buffer "~5.1.1" + semver "~5.3.0" + sha "~2.0.1" + slide "~1.1.6" + sorted-object "~2.0.1" + sorted-union-stream "~2.1.3" + ssri "~4.1.6" + strip-ansi "~4.0.0" + tar "~2.2.1" + text-table "~0.2.0" + uid-number "0.0.6" + umask "~1.1.0" + unique-filename "~1.1.0" + unpipe "~1.0.0" + update-notifier "~2.2.0" + uuid "~3.1.0" + validate-npm-package-name "~3.0.0" + which "~1.2.14" + worker-farm "~1.3.1" + wrappy "~1.0.2" + write-file-atomic "~2.1.0" + +"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@~4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +npx@^10.2.2: + version "10.2.2" + resolved "https://registry.yarnpkg.com/npx/-/npx-10.2.2.tgz#de4be1b76e6bcbf750486925b34a07eed1db01b4" + integrity sha512-eImmySusyeWphzs5iNh791XbZnZG0FSNvM4KSah34pdQQIDsdTDhIwg1sjN3AIVcjGLpbQ/YcfqHPshKZQK1fA== + dependencies: + libnpx "10.2.2" + npm "5.1.0" + +nth-check@^1.0.2, nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nwsapi@^2.0.7, nwsapi@^2.1.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-hash@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.0.3.tgz#d12db044e03cd2ca3d77c0570d87225b02e1e6ea" + integrity sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg== + +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== + +object-is@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.2.tgz#6b80eb84fe451498f65007982f035a5b445edec4" + integrity sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-path@0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.4.tgz#370ae752fbf37de3ea70a861c23bba8915691949" + integrity sha1-NwrnUvvzfePqcKhhwju6iRVpGUk= + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.entries@^1.1.0, object.entries@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b" + integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +object.fromentries@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" + integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0, object.values@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0, once@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" + integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + dependencies: + mimic-fn "^2.1.0" + +open@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/open/-/open-7.0.3.tgz#db551a1af9c7ab4c7af664139930826138531c48" + integrity sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +opener@~1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +optimize-css-assets-webpack-plugin@5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz#e2f1d4d94ad8c0af8967ebd7cf138dcb1ef14572" + integrity sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA== + dependencies: + cssnano "^4.1.10" + last-call-webpack-plugin "^3.0.0" + +optionator@^0.8.1, optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^3.0.0, os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-each-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" + integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= + dependencies: + p-reduce "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + +pacote@~2.7.38: + version "2.7.38" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-2.7.38.tgz#5091f8774298c26c3eca24606037f1bb73db74c1" + integrity sha512-XxHUyHQB7QCVBxoXeVu0yKxT+2PvJucsc0+1E+6f95lMUxEAYERgSAc71ckYXrYr35Ew3xFU/LrhdIK21GQFFA== + dependencies: + bluebird "^3.5.0" + cacache "^9.2.9" + glob "^7.1.2" + lru-cache "^4.1.1" + make-fetch-happen "^2.4.13" + minimatch "^3.0.4" + mississippi "^1.2.0" + normalize-package-data "^2.4.0" + npm-package-arg "^5.1.2" + npm-pick-manifest "^1.0.4" + osenv "^0.1.4" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^4.0.0" + safe-buffer "^5.1.1" + semver "^5.3.0" + ssri "^4.1.6" + tar-fs "^1.15.3" + tar-stream "^1.5.4" + unique-filename "^1.1.0" + which "^1.2.12" + +paho-mqtt@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/paho-mqtt/-/paho-mqtt-1.1.0.tgz#8c10e29eb162e966fb15188d965c3dce505de9d9" + integrity sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA== + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + +param-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.3.tgz#4be41f8399eff621c56eebb829a5e451d9801238" + integrity sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA== + dependencies: + dot-case "^3.0.3" + tslib "^1.10.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0: + version "5.1.5" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" + integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-json@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + lines-and-columns "^1.1.6" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== + +parse5@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" + integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" + integrity sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picomatch@^2.0.4, picomatch@^2.0.7: + version "2.2.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" + integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= + dependencies: + find-up "^1.0.0" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-up@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== + +pnp-webpack-plugin@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.0.tgz#d5c068013a2fdc82224ca50ed179c8fba9036a8e" + integrity sha512-ZcMGn/xF/fCOq+9kWMP9vVVxjIkMCja72oy3lziR7UHy0hHFZ57iVpQ71OtveVbmzeCmphBg8pxNdk/hlK99aQ== + dependencies: + ts-pnp "^1.1.2" + +portfinder@^1.0.25: + version "1.0.25" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" + integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.1" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" + integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^6.0.2" + +postcss-browser-comments@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz#1248d2d935fb72053c8e1f61a84a57292d9f65e9" + integrity sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig== + dependencies: + postcss "^7" + +postcss-calc@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.2.tgz#504efcd008ca0273120568b0792b16cdcde8aac1" + integrity sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ== + dependencies: + postcss "^7.0.27" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-custom-media@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.11: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-flexbugs-fixes@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz#e094a9df1783e2200b7b19f875dcad3b3aff8b20" + integrity sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA== + dependencies: + postcss "^7.0.0" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.0.tgz#71dd3c6c10a0d846c5eda07803439617bbbabacc" + integrity sha512-M8BFYKOvCrI2aITzDad7kWuXXTm0YhGdP9Q8HanmN4EF1Hmcgs1KK5rSHylt/lUJe8yLxiSwWAHdScoEiIxztg== + dependencies: + postcss "^7.0.2" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-initial@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.2.tgz#f018563694b3c16ae8eaabe3c585ac6319637b2d" + integrity sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA== + dependencies: + lodash.template "^4.5.0" + postcss "^7.0.2" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-load-config@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003" + integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q== + dependencies: + cosmiconfig "^5.0.0" + import-cwd "^2.0.0" + +postcss-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== + dependencies: + loader-utils "^1.1.0" + postcss "^7.0.0" + postcss-load-config "^2.0.0" + schema-utils "^1.0.0" + +postcss-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + 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" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + 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" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" + integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ== + dependencies: + icss-utils "^4.1.1" + postcss "^7.0.16" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.0" + +postcss-modules-scope@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba" + integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" + integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== + dependencies: + icss-utils "^4.0.0" + postcss "^7.0.6" + +postcss-nesting@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" + integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== + dependencies: + postcss "^7.0.2" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize/-/postcss-normalize-8.0.1.tgz#90e80a7763d7fdf2da6f2f0f82be832ce4f66776" + integrity sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ== + dependencies: + "@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-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-overflow-shorthand@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== + dependencies: + postcss "^7.0.2" + +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" + integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== + dependencies: + 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@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-safe-parser@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz#8756d9e4c36fdce2c72b091bbc8ca176ab1fcdea" + integrity sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ== + dependencies: + postcss "^7.0.0" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz#c68ff7ba96527499e832724a2674d65603b645c0" + integrity sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" + integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== + dependencies: + dot-prop "^5.2.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" + integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== + dependencies: + is-svg "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz#651ff4593aa9eda8d5d0d66593a2417aeaeb325d" + integrity sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg== + +postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@7.0.21: + version "7.0.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" + integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9" + integrity sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prepend-http@^1.0.0, prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +pretty-bytes@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" + integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg== + +pretty-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" + integrity sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM= + dependencies: + renderkid "^2.0.1" + utila "~0.4" + +pretty-format@^24.0.0, pretty-format@^24.3.0, pretty-format@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + +pretty-format@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.1.0.tgz#ed869bdaec1356fc5ae45de045e2c8ec7b07b0c8" + integrity sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ== + dependencies: + "@jest/types" "^25.1.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + +private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1, promise-inflight@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + +promise@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e" + integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q== + dependencies: + asap "~2.0.6" + +prompts@^2.0.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.1.tgz#b63a9ce2809f106fa9ae1277c275b167af46ea05" + integrity sha512-qIP2lQyCwYbdzcqHIUi2HAxiWixhoM9OdLCWf8txXsapC/X9YdsCoeyRIXE/GP+Q0J37Q7+XN/MFqbUa7IzXNA== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.4" + +promzard@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= + dependencies: + read "1" + +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +protoduck@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-4.0.0.tgz#fe4874d8c7913366cfd9ead12453a22cd3657f8e" + integrity sha1-/kh02MeRM2bP2erRJFOiLNNlf44= + dependencies: + genfun "^4.0.1" + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28: + version "1.7.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c" + integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" + integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8= + +qrcode.react@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-0.8.0.tgz#413b31cc3b62910e39513f7bead945e01c4c34fb" + integrity sha512-16wKpuFvLwciIq2YAsfmPUCnSR8GrYPsXRK5KVdcIuX0+W/MKZbBkFhl44ttRx4TWZHqRjfztoWOxdPF0Hb9JA== + dependencies: + prop-types "^15.6.0" + qr.js "0.0.0" + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM= + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" + integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== + +raf@^3.4.0, raf@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== + dependencies: + performance-now "^2.1.0" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.0.1, rc@^1.1.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-app-polyfill@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz#890f8d7f2842ce6073f030b117de9130a5f385f0" + integrity sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g== + dependencies: + 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-charts@^2.0.0-beta.6: + version "2.0.0-beta.6" + resolved "https://registry.yarnpkg.com/react-charts/-/react-charts-2.0.0-beta.6.tgz#5035c49794aa151f0a51a5aeae066805e5d54edf" + integrity sha512-GxcErCb/TSCsgug4uumSyzhXflwtQRwsN6nGA1e8dIqh9Z6gRFgDZF6DNCmvuHLibnu0JfLDmyaG7+MFgBzuDQ== + dependencies: + "@reach/observe-rect" "^1.0.3" + d3-delaunay "^5.1.6" + d3-scale "^3.2.0" + d3-shape "^1.3.7" + d3-voronoi "^1.1.2" + raf "^3.4.1" + +react-dev-utils@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.0.tgz#b11cc48aa2be2502fb3c27a50d1dfa95cfa9dfe0" + integrity sha512-MwrvQW2TFjLblhqpDNeqCXHBkz3G5vc7k4wntgutAJZX4ia3o07eGKo6uYGhUOeJ0hfOxcpJFNFk7+4XCc1S8g== + dependencies: + "@babel/code-frame" "7.8.3" + address "1.1.2" + browserslist "4.8.6" + 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.6" + recursive-readdir "2.2.2" + shell-quote "1.7.2" + strip-ansi "6.0.0" + text-table "0.2.0" + +react-dom@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" + integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + +react-error-overlay@^6.0.6: + version "6.0.6" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.6.tgz#ac4d9dc4c1b5c536c2c312bf66aa2b09bfa384e2" + integrity sha512-Yzpno3enVzSrSCnnljmr4b/2KUQSMZaPuqmS26t9k4nW7uwJk6STWmH9heNjPuvqUTO3jOSPkHoKgO4+Dw7uIw== + +react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4: + version "16.13.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" + integrity sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA== + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-resize-detector@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-2.3.0.tgz#57bad1ae26a28a62a2ddb678ba6ffdf8fa2b599c" + integrity sha512-oCAddEWWeFWYH5FAcHdBYcZjAw9fMzRUK9sWSx6WvSSOPVRxcHd5zTIGy/mOus+AhN/u6T4TMiWxvq79PywnJQ== + dependencies: + lodash.debounce "^4.0.8" + lodash.throttle "^4.1.1" + prop-types "^15.6.0" + resize-observer-polyfill "^1.5.0" + +react-scripts@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.0.tgz#f413680f0b5b937c8879ba1ffdae9b8c5b364bf5" + integrity sha512-pBqaAroFoHnFAkuX+uSK9Th1uEh2GYdGY2IG1I9/7HmuEf+ls3lLCk1p2GFYRSrLMz6ieQR/SyN6TLIGK3hKRg== + dependencies: + "@babel/core" "7.8.4" + "@svgr/webpack" "4.3.3" + "@typescript-eslint/eslint-plugin" "^2.10.0" + "@typescript-eslint/parser" "^2.10.0" + babel-eslint "10.0.3" + babel-jest "^24.9.0" + babel-loader "8.0.6" + babel-plugin-named-asset-import "^0.3.6" + babel-preset-react-app "^9.1.1" + 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.0" + eslint-loader "3.0.3" + eslint-plugin-flowtype "4.6.0" + eslint-plugin-import "2.20.0" + eslint-plugin-jsx-a11y "6.2.3" + eslint-plugin-react "7.18.0" + eslint-plugin-react-hooks "^1.6.1" + file-loader "4.3.0" + fs-extra "^8.1.0" + 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.0" + 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.0" + resolve "1.15.0" + resolve-url-loader "3.1.1" + sass-loader "8.0.2" + semver "6.3.0" + style-loader "0.23.1" + terser-webpack-plugin "2.3.4" + ts-pnp "1.1.5" + url-loader "2.3.0" + webpack "4.41.5" + webpack-dev-server "3.10.2" + webpack-manifest-plugin "2.2.0" + workbox-webpack-plugin "4.3.1" + optionalDependencies: + fsevents "2.1.2" + +react-smooth@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-1.0.5.tgz#94ae161d7951cdd893ccb7099d031d342cb762ad" + integrity sha512-eW057HT0lFgCKh8ilr0y2JaH2YbNcuEdFpxyg7Gf/qDKk9hqGMyXryZJ8iMGJEuKH0+wxS0ccSsBBB3W8yCn8w== + dependencies: + lodash "~4.17.4" + prop-types "^15.6.0" + raf "^3.4.0" + react-transition-group "^2.5.0" + +react-transition-group@^2.5.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d" + integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg== + dependencies: + dom-helpers "^3.4.0" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react-lifecycles-compat "^3.0.4" + +react@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" + integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + +read-cmd-shim@~1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz#87e43eba50098ba5a32d0ceb583ab8e43b961c16" + integrity sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA== + dependencies: + graceful-fs "^4.1.2" + +read-installed@~4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc= + dependencies: + debuglog "^1.0.1" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + semver "2 || 3 || 4 || 5" + slide "~1.1.3" + util-extend "^1.0.1" + optionalDependencies: + graceful-fs "^4.1.2" + +"read-package-json@1 || 2", read-package-json@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.1.tgz#16aa66c59e7d4dad6288f179dd9295fd59bb98f1" + integrity sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A== + dependencies: + glob "^7.1.1" + json-parse-better-errors "^1.0.1" + normalize-package-data "^2.0.0" + npm-normalize-package-bin "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-json@~2.0.9: + version "2.0.13" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a" + integrity sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg== + dependencies: + glob "^7.1.1" + json-parse-better-errors "^1.0.1" + normalize-package-data "^2.0.0" + slash "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-tree@~5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.1.6.tgz#4f03e83d0486856fb60d97c94882841c2a7b1b7a" + integrity sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg== + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + once "^1.3.0" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg-up@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" + integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== + dependencies: + find-up "^3.0.0" + read-pkg "^3.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +read@1, read@~1.0.1, read@~1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= + dependencies: + mute-stream "~0.0.4" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.2, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~1.1.10: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdir-scoped-modules@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" + integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + graceful-fs "^4.1.2" + once "^1.3.0" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" + integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== + dependencies: + picomatch "^2.0.7" + +realpath-native@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" + integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== + dependencies: + util.promisify "^1.0.0" + +recharts-scale@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.3.tgz#040b4f638ed687a530357292ecac880578384b59" + integrity sha512-t8p5sccG9Blm7c1JQK/ak9O8o95WGhNXD7TXg/BW5bYbVlr6eCeRBNpgyigD4p6pSSMehC5nSvBUPj6F68rbFA== + dependencies: + decimal.js-light "^2.4.1" + +recharts@^1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-1.8.5.tgz#ca94a3395550946334a802e35004ceb2583fdb12" + integrity sha512-tM9mprJbXVEBxjM7zHsIy6Cc41oO/pVYqyAsOHLxlJrbNBuLs0PHB3iys2M+RqCF0//k8nJtZF6X6swSkWY3tg== + dependencies: + classnames "^2.2.5" + core-js "^2.6.10" + d3-interpolate "^1.3.0" + d3-scale "^2.1.0" + d3-shape "^1.2.0" + lodash "^4.17.5" + prop-types "^15.6.0" + react-resize-detector "^2.3.0" + react-smooth "^1.0.5" + recharts-scale "^0.4.2" + reduce-css-calc "^1.3.0" + +recursive-readdir@2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" + integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== + dependencies: + minimatch "3.0.4" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +reduce-css-calc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY= + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.3.tgz#60350f7fb252c0a67eb10fd4694d16909971300f" + integrity sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ== + dependencies: + balanced-match "^1.0.0" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3: + version "0.13.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" + integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== + +regenerator-runtime@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz#e96bf612a3362d12bb69f7e8f74ffeab25c7ac91" + integrity sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g== + +regenerator-transform@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.2.tgz#949d9d87468ff88d5a7e4734ebb994a892de1ff2" + integrity sha512-V4+lGplCM/ikqi5/mkkpJ06e9Bujq1NFmNLvsCs56zg3ZbzrnUzAtizZ24TXxtRX/W2jcdScwQCnbL0CICTFkQ== + dependencies: + "@babel/runtime" "^7.8.4" + private "^0.1.8" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regex-parser@2.2.10: + version "2.2.10" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.10.tgz#9e66a8f73d89a107616e63b39d4deddfee912b37" + integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA== + +regexp.prototype.flags@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" + integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpp@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" + integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== + +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== + dependencies: + 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" + +registry-auth-token@^3.0.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" + integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A== + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= + dependencies: + rc "^1.0.1" + +regjsgen@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== + +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +renderkid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.3.tgz#380179c2ff5ae1365c522bf2fcfcff01c5b74149" + integrity sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA== + dependencies: + css-select "^1.1.0" + dom-converter "^0.2" + htmlparser2 "^3.3.0" + strip-ansi "^3.0.0" + utila "^0.4.0" + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request-promise-core@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" + integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== + dependencies: + lodash "^4.17.15" + +request-promise-native@^1.0.5: + version "1.0.8" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" + integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== + dependencies: + request-promise-core "1.1.3" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +"request@>=2.9.0 <2.82.0", request@~2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + integrity sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA= + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +request@^2.74.0, request@^2.87.0, request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resize-observer-polyfill@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-url-loader@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz#28931895fa1eab9be0647d3b2958c100ae3c0bf0" + integrity sha512-K1N5xUjj7v0l2j/3Sgs5b8CjrrgtC70SmdCuZiJ8tSyb5J+uk3FoeZ4b7yTnH6j7ngI+Bc5bldHJIa8hYdu2gQ== + dependencies: + adjust-sourcemap-loader "2.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" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + +resolve@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5" + integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== + dependencies: + path-parse "^1.0.6" + +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.3.2, resolve@^1.8.1: + version "1.15.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" + integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.10.0, retry@~0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +rework-visit@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a" + integrity sha1-mUWygD8hni96ygCtuLyfZA+ELJo= + +rework@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7" + integrity sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc= + dependencies: + convert-source-map "^0.3.3" + css "^2.0.0" + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@2.6.3, rimraf@~2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +run-async@^2.2.0, run-async@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8" + integrity sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg== + dependencies: + is-promise "^2.1.0" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" + integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@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@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/sanitize.css/-/sanitize.css-10.0.0.tgz#b5cb2547e96d8629a60947544665243b1dc3657a" + integrity sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg== + +sass-loader@8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.2.tgz#debecd8c3ce243c76454f2e8290482150380090d" + integrity sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ== + dependencies: + clone-deep "^4.0.1" + loader-utils "^1.2.3" + neo-async "^2.6.1" + schema-utils "^2.6.1" + semver "^6.3.0" + +sax@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= + +sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^3.1.9: + version "3.1.11" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" + integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== + dependencies: + xmlchars "^2.1.1" + +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6.4: + version "2.6.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.5.tgz#c758f0a7e624263073d396e29cd40aa101152d8a" + integrity sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ== + dependencies: + ajv "^6.12.0" + ajv-keywords "^3.4.1" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.7: + version "1.10.7" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b" + integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA== + dependencies: + node-forge "0.9.0" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= + dependencies: + semver "^5.0.3" + +"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + 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" + +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + 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" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + integrity sha1-YDCCL70smCOUn49y7WQR7lzyWq4= + dependencies: + graceful-fs "^4.1.2" + readable-stream "^2.0.2" + +shallow-clone@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060" + integrity sha1-WQnodLp3EG1zrEFM/sH/yofZcGA= + dependencies: + is-extendable "^0.1.1" + kind-of "^2.0.1" + lazy-cache "^0.2.3" + mixin-object "^2.0.1" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.4.tgz#386713f1ef688c7c0304dc4c0632898941cad2e3" + integrity sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig== + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= + +smart-buffer@^1.0.13: + version "1.1.15" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" + integrity sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= + dependencies: + hoek "2.x.x" + +sockjs-client@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" + integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== + dependencies: + 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" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +socks-proxy-agent@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz#2eae7cf8e2a82d34565761539a7f9718c5617659" + integrity sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA== + dependencies: + agent-base "^4.1.0" + socks "^1.1.10" + +socks@^1.1.10: + version "1.1.10" + resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.10.tgz#5b8b7fc7c8f341c53ed056e929b7bf4de8ba7b5a" + integrity sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o= + dependencies: + ip "^1.1.4" + smart-buffer "^1.0.13" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +sorted-object@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" + integrity sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw= + +sorted-union-stream@~2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz#c7794c7e077880052ff71a8d4a2dbb4a9a638ac7" + integrity sha1-x3lMfgd4gAUv9xqNSi27Sppjisc= + dependencies: + from2 "^1.3.0" + stream-iterate "^1.1.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.6, source-map-support@~0.5.12: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + 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" + +spdy@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2" + integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^4.1.2, ssri@^4.1.6, ssri@~4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-4.1.6.tgz#0cb49b6ac84457e7bdd466cb730c3cb623e9a25b" + integrity sha512-WUbCdgSAMQjTFZRWvSPpauryvREEA+Krn19rx67UlJEJx/M192ZHxMmJXjZ4tkdFm+Sb0SXGlENeQVlA5wY7kA== + dependencies: + safe-buffer "^5.1.0" + +ssri@^5.0.0, ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== + dependencies: + safe-buffer "^5.1.1" + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +ssri@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-7.1.0.tgz#92c241bf6de82365b5c7fb4bd76e975522e1294d" + integrity sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g== + dependencies: + figgy-pudding "^3.5.1" + minipass "^3.1.1" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stack-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" + integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-iterate@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/stream-iterate/-/stream-iterate-1.2.0.tgz#2bd7c77296c1702a46488b8ad41f79865eecd4e1" + integrity sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE= + dependencies: + readable-stream "^2.1.5" + stream-shift "^1.0.0" + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + +string-length@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" + integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== + dependencies: + astral-regex "^1.0.0" + strip-ansi "^5.2.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimleft@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" + integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" + integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-object@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +stringstream@~0.0.4: + version "0.0.6" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" + integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA== + +strip-ansi@6.0.0, strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0, strip-ansi@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-comments@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-1.0.2.tgz#82b9c45e7f05873bee53f37168af930aa368679d" + integrity sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw== + dependencies: + babel-extract-comments "^1.0.0" + babel-plugin-transform-object-rest-spread "^6.26.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + +svg-parser@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^1.0.0, svgo@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +symbol-tree@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tapable@^1.0.0, tapable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar-fs@^1.15.3: + version "1.16.3" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2, tar-stream@^1.5.4: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar@^2.0.0, tar@~2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== + dependencies: + block-stream "*" + fstream "^1.0.12" + inherits "2" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= + dependencies: + execa "^0.7.0" + +terser-webpack-plugin@2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.4.tgz#ac045703bd8da0936ce910d8fb6350d0e1dee5fe" + integrity sha512-Nv96Nws2R2nrFOpbzF6IxRDpIkkIfmhvOws+IqMvYdFLO7o6wAILWFKONFgaYy8+T4LVz77DQW0f7wOeDEAjrg== + dependencies: + cacache "^13.0.1" + find-cache-dir "^3.2.0" + jest-worker "^25.1.0" + p-limit "^2.2.2" + schema-utils "^2.6.4" + serialize-javascript "^2.1.2" + source-map "^0.6.1" + terser "^4.4.3" + webpack-sources "^1.4.3" + +terser-webpack-plugin@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== + dependencies: + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^2.1.2" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" + +terser@^4.1.2, terser@^4.4.3, terser@^4.6.3: + version "4.6.6" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.6.tgz#da2382e6cafbdf86205e82fb9a115bd664d54863" + integrity sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +test-exclude@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" + integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== + dependencies: + glob "^7.1.3" + minimatch "^3.0.4" + read-pkg-up "^4.0.0" + require-main-filename "^2.0.0" + +text-table@0.2.0, text-table@^0.2.0, text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +"through@>=2.2.7 <3", through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + +timers-browserify@^2.0.4: + version "2.0.11" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" + integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tough-cookie@~2.3.0: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA== + dependencies: + punycode "^1.4.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + +ts-pnp@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.5.tgz#840e0739c89fce5f3abd9037bb091dbff16d9dec" + integrity sha512-ti7OGMOUOzo66wLF3liskw6YQIaSsBgc4GOAlWRnIEj8htCxJUxskanMUoJOD6MDCRAXo36goXJZch+nOS0VMA== + +ts-pnp@^1.1.2: + version "1.1.6" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.6.tgz#389a24396d425a0d3162e96d2b4638900fdc289a" + integrity sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ== + +tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: + version "1.11.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" + integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== + +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" + integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +uid-number@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= + +umask@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +unique-filename@^1.1.0, unique-filename@^1.1.1, unique-filename@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= + dependencies: + crypto-random-string "^1.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +update-notifier@^2.3.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +update-notifier@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.2.0.tgz#1b5837cf90c0736d88627732b661c138f86de72f" + integrity sha1-G1g3z5DAc22IYncytmHBOPht5y8= + dependencies: + boxen "^1.0.0" + chalk "^1.0.0" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-loader@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b" + integrity sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog== + dependencies: + loader-utils "^1.2.3" + mime "^2.4.4" + schema-utils "^2.5.0" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-parse@^1.4.3: + version "1.4.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8= + +util.promisify@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util.promisify@^1.0.0, util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utila@^0.4.0, utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +uuid@^3.0.0, uuid@^3.0.1, uuid@^3.2.1, uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g== + +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + dependencies: + builtins "^1.0.3" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +w3c-hr-time@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" + integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== + dependencies: + domexception "^1.0.1" + webidl-conversions "^4.0.2" + xml-name-validator "^3.0.0" + +wait-for-expect@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-3.0.2.tgz#d2f14b2f7b778c9b82144109c8fa89ceaadaa463" + integrity sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag== + +walker@^1.0.7, walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +watchpack@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +wcwidth@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +webpack-dev-middleware@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" + integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@3.10.2: + version "3.10.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.10.2.tgz#3403287d674c7407aab6d9b3f72259ecd0aa0874" + integrity sha512-pxZKPYb+n77UN8u9YxXT4IaIrGcNtijh/mi8TXbErHmczw0DtPnMTTjHj+eNjkqLOaAZM/qD7V59j/qJsEiaZA== + dependencies: + 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.2.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.6" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.25" + schema-utils "^1.0.0" + selfsigned "^1.10.7" + semver "^6.3.0" + serve-index "^1.9.1" + sockjs "0.3.19" + sockjs-client "1.4.0" + spdy "^4.0.1" + 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 "12.0.5" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-manifest-plugin@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz#19ca69b435b0baec7e29fbe90fb4015de2de4f16" + integrity sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ== + dependencies: + fs-extra "^7.0.0" + lodash ">=3.5 <5" + object.entries "^1.1.0" + tapable "^1.0.0" + +webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@4.41.5: + version "4.41.5" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c" + integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.2.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" + +websocket-driver@>=0.5.1: + version "0.7.3" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" + integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== + dependencies: + http-parser-js ">=0.4.0 <0.4.11" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" + integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== + +whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1, which@^1.2.12, which@^1.2.9, which@^1.3.0, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +which@~1.2.14: + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU= + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" + integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== + dependencies: + string-width "^2.1.1" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +workbox-background-sync@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz#26821b9bf16e9e37fd1d640289edddc08afd1950" + integrity sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg== + dependencies: + workbox-core "^4.3.1" + +workbox-broadcast-update@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz#e2c0280b149e3a504983b757606ad041f332c35b" + integrity sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA== + dependencies: + workbox-core "^4.3.1" + +workbox-build@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-4.3.1.tgz#414f70fb4d6de47f6538608b80ec52412d233e64" + integrity sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw== + dependencies: + "@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" + +workbox-cacheable-response@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz#f53e079179c095a3f19e5313b284975c91428c91" + integrity sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw== + dependencies: + workbox-core "^4.3.1" + +workbox-core@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-4.3.1.tgz#005d2c6a06a171437afd6ca2904a5727ecd73be6" + integrity sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg== + +workbox-expiration@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-4.3.1.tgz#d790433562029e56837f341d7f553c4a78ebe921" + integrity sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw== + dependencies: + workbox-core "^4.3.1" + +workbox-google-analytics@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz#9eda0183b103890b5c256e6f4ea15a1f1548519a" + integrity sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg== + dependencies: + workbox-background-sync "^4.3.1" + workbox-core "^4.3.1" + workbox-routing "^4.3.1" + workbox-strategies "^4.3.1" + +workbox-navigation-preload@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz#29c8e4db5843803b34cd96dc155f9ebd9afa453d" + integrity sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw== + dependencies: + workbox-core "^4.3.1" + +workbox-precaching@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-4.3.1.tgz#9fc45ed122d94bbe1f0ea9584ff5940960771cba" + integrity sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ== + dependencies: + workbox-core "^4.3.1" + +workbox-range-requests@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz#f8a470188922145cbf0c09a9a2d5e35645244e74" + integrity sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA== + dependencies: + workbox-core "^4.3.1" + +workbox-routing@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-4.3.1.tgz#a675841af623e0bb0c67ce4ed8e724ac0bed0cda" + integrity sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g== + dependencies: + workbox-core "^4.3.1" + +workbox-strategies@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-4.3.1.tgz#d2be03c4ef214c115e1ab29c9c759c9fe3e9e646" + integrity sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw== + dependencies: + workbox-core "^4.3.1" + +workbox-streams@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-4.3.1.tgz#0b57da70e982572de09c8742dd0cb40a6b7c2cc3" + integrity sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA== + dependencies: + workbox-core "^4.3.1" + +workbox-sw@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-4.3.1.tgz#df69e395c479ef4d14499372bcd84c0f5e246164" + integrity sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w== + +workbox-webpack-plugin@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz#47ff5ea1cc074b6c40fb5a86108863a24120d4bd" + integrity sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ== + dependencies: + "@babel/runtime" "^7.0.0" + json-stable-stringify "^1.0.1" + workbox-build "^4.3.1" + +workbox-window@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-4.3.1.tgz#ee6051bf10f06afa5483c9b8dfa0531994ede0f3" + integrity sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg== + dependencies: + workbox-core "^4.3.1" + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +worker-farm@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff" + integrity sha1-QzMRK7SbF6oFC4eJXKayys9A5f8= + dependencies: + errno ">=0.1.1 <0.2.0-0" + xtend ">=4.0.0 <4.1.0-0" + +worker-rpc@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" + integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== + dependencies: + microevent.ts "~0.1.1" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1, wrappy@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" + integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +write-file-atomic@^2.0.0: + version "2.4.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +write-file-atomic@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.1.0.tgz#1769f4b551eedce419f0505deae2e26763542d37" + integrity sha512-0TZ20a+xcIl4u0+Mj5xDH2yOWdmQiXlKf9Hm+TgDXjTMsEYb+gDrmb8e8UNAzMCitX8NBqG4Z/FUQIyzv/R1JQ== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + +ws@^6.1.2, ws@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xml2js@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + +xmlchars@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.7.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.8.2.tgz#a29c03f578faafd57dcb27055f9a5d569cb0c3d9" + integrity sha512-omakb0d7FjMo3R1D2EbTKVIk6dAVLRxFXdLZMEUToeAvuqgG/YuHMuQOZ5fgk+vQ8cx+cnGKwyg+8g8PNT0xQg== + dependencies: + "@babel/runtime" "^7.8.7" + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= + dependencies: + camelcase "^4.1.0" + +yargs@12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + +yargs@^11.0.0: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.1.tgz#5052efe3446a4df5ed669c995886cc0f13702766" + integrity sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + 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.1" + +zen-observable@^0.8.6: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== diff --git a/Website/package.json b/Website/package.json new file mode 100644 index 0000000..37f6737 --- /dev/null +++ b/Website/package.json @@ -0,0 +1,15 @@ +{ + "name": "hpiot-website", + "version": "1.0.0", + "description": "Website for Henry Pump's in-house SCADA", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "hpiot-website" + }, + "author": "", + "license": "ISC" +} diff --git a/desktop.ini b/desktop.ini new file mode 100644 index 0000000000000000000000000000000000000000..8ccf60ff2286f115e1d193b277146aafeb409ba3 GIT binary patch literal 176 zcmZXOPYVHI5Qm?$Pq9aejg+LENV$n44oi!z-FIcF_tWE9S4}hhX6BhcpZA`W9XE1H zZJ}p0+M2+Hnj;-xd83#7zHCJOsMZ${0JuREiB{F3~Pj30+?wq8f Xd3&vp3q1e2sr9J$88CK!$jDE=BCH@? literal 0 HcmV?d00001 diff --git a/example config.json b/example config.json new file mode 100644 index 0000000..a67a3b7 --- /dev/null +++ b/example config.json @@ -0,0 +1,109 @@ +{ + "certificateID": "1370cf88050a5d9bc5aeef22f2b9756224c080c89f703eefeee8c9081dc6424e", + "device1": { + "appname": "hpiot", + "certificateID": "1370cf88050a5d9bc5aeef22f2b9756224c080c89f703eefeee8c9081dc6424e", + "company": "henrypump", + "currentData": "empty", + "deviceType": "inventory", + "field": "inventory", + "locationID": 0, + "modbusData": "empty", + "PLCData": { + "tag1": { + "alert": { + "buffer": [ + 5, + 10, + 5, + 10 + ], + "condition": [ + "gte", + "gt", + "lte", + "lt" + ], + "contact": [ + [ + "HenryPumpDemo" + ], + [ + "HenryPumpDemo" + ], + [ + "HenryPumpDemo" + ], + [ + "HenryPumpDemo" + ] + ], + "name": [ + "Overflow Warning", + "High Pond Level", + "Critically Low Pond Level", + "Low Pond Level" + ], + "reminder": [ + 30, + 30, + 30, + 30 + ], + "response": [ + [ + "sms", + "voice", + "email" + ], + [ + "sms" + ], + [ + "sms", + "voice", + "email" + ], + [ + "sms" + ] + ], + "threshold": [ + [ + 17, + 16.5 + ], + [ + 15, + 14.5 + ], + [ + 2, + 2.5 + ], + [ + 3, + 3.5 + ] + ] + }, + "changeThreshold": 1, + "guaranteed": 3600, + "name": "pond 1 height", + "plcIP": "192.168.1.12", + "plcType": "Micro800", + "tag": "pond1Height" + }, + "tag2": { + "changeThreshold": 1, + "guaranteed": 3600, + "name": "pond 2 height", + "plcIP": "192.168.1.12", + "plcType": "Micro800", + "tag": "pond2Height" + } + }, + "voltageData": "empty" + }, + "version": 1 +} \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ed5a0e9514521441aa290cbcdb0496ed5e26bdcd GIT binary patch literal 3230 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 literal 0 HcmV?d00001 diff --git a/hpicon-1408x1408.xcf b/hpicon-1408x1408.xcf new file mode 100644 index 0000000000000000000000000000000000000000..b950c2d2d003b0e1954529c5ba3d782ec9764b1d GIT binary patch literal 139936 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 literal 0 HcmV?d00001 diff --git a/icon-128x128.png b/icon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..bf60b767459710a96c7cb90065abbf33a3c5c67a GIT binary patch literal 2743 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 literal 0 HcmV?d00001 diff --git a/icon-192x192.png b/icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..cb69621b56f2f3f595d8a6cc6cad30c71b0eefca GIT binary patch literal 3859 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 BJ}CeI literal 0 HcmV?d00001 diff --git a/icon-384x384.png b/icon-384x384.png new file mode 100644 index 0000000000000000000000000000000000000000..90661888523b34e31f8640bded629bd0d0e0beda GIT binary patch literal 7279 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 literal 0 HcmV?d00001 diff --git a/icon-512x512.png b/icon-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..ee16098a5a4cc218efd6f91d0b09ef439b9d2bb2 GIT binary patch literal 9498 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 W2p4sy7+*gC0000
+ + + +
+ + + + {{fields.key}} + + + + + {{location.location}} + +
+
{{keys.key}}: {{keys.value}}
+
+
+
+
+
+
+
+ + + +
+ + + + + + +
+ + + + + + + + {{title}} +
+ + +
+ + + + +
+ +
+
+
+
+ +