', methods=['GET'])
+ def send_static(path):
+ return flask.send_from_directory(os.path.join(www_path, 'static'), path)
+
+class Config(object):
+ DEBUG = False
+ TESTING = False
+ CSRF_ENABLED = True
+
+def init_flask(title='CH service API', init_app_fn=None, webapp=False, json_encoder=JSONEncoder, resolver=None, config=Config):
+ """
+
+ """
+ global app
+
+ # Some magic inspection to get the caller's absolute path
+ import inspect, os
+ frm = inspect.stack()[1]
+ mod = inspect.getmodule(frm[0])
+ caller_path = os.path.dirname(os.path.realpath(mod.__file__))
+
+ connexion_app = connexion.App(__name__)
+ app = connexion_app.app
+ obj_config = os.environ.get('APP_SETTINGS', config)
+ if obj_config:
+ app.config.from_object(obj_config)
+ app.json_encoder = json_encoder
+
+ with app.app_context():
+ # setup logging
+ gunicorn_logger = logging.getLogger("gunicorn.error")
+ app.logger.handlers = gunicorn_logger.handlers
+ app.logger.setLevel(gunicorn_logger.level)
+
+ if webapp:
+ init_webapp_routes(app, www_path=os.path.join(os.path.dirname(caller_path), 'www'))
+ connexion_app.add_api(os.path.join(caller_path, 'openapi/openapi.yaml'),
+ arguments={'title': title},
+ pythonic_params=True, resolver=resolver)
+
+ if init_app_fn:
+ init_app_fn(app)
+
+ return app
+
+def main():
+ app.run( host='0.0.0.0', port=os.getenv('PORT', 5001))
\ No newline at end of file
diff --git a/libraries/cloudharness-common/cloudharness/workflows/argo.py b/libraries/cloudharness-common/cloudharness/workflows/argo.py
index 3550c8b7..3c977cb3 100644
--- a/libraries/cloudharness-common/cloudharness/workflows/argo.py
+++ b/libraries/cloudharness-common/cloudharness/workflows/argo.py
@@ -3,25 +3,18 @@
Reference: https://argoproj.github.io/docs/argo/docs/rest-api.html
https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/CustomObjectsApi.md
"""
-import kubernetes
import yaml
-import os
-from pathlib import Path
-from cloudharness import log
-
-group = 'argoproj.io'
-version = 'v1alpha1'
-
-plural = 'workflows'
+from argo.workflows.client import ApiClient, WorkflowServiceApi, Configuration, V1alpha1WorkflowCreateRequest, \
+ V1alpha1Workflow
# determine the namespace of the current app and run the workflow in that namespace
from cloudharness.utils.config import CloudharnessConfig as conf
-ch_conf = conf.get_configuration()
-namespace = ch_conf and ch_conf.get('namespace','argo-workflows')
+from cloudharness import log, applications
-CUSTOM_OBJECT_URL = f"/apis/{group}/{version}/{plural}"
+ch_conf = conf.get_configuration()
+namespace = conf.get_namespace()
class WorkflowException(Exception):
@@ -67,11 +60,11 @@ def phases(cls):
class Workflow:
- def __init__(self, raw_dict):
- self.name = raw_dict['metadata']['name']
- self.status = raw_dict['status']['phase'] if 'status' in raw_dict else None
- self.create_time = raw_dict['metadata']['creationTimestamp']
- self.raw = raw_dict
+ def __init__(self, api_workflow: V1alpha1Workflow):
+ self.name = api_workflow.metadata.name
+ self.status = api_workflow.status.phase if api_workflow.status else None
+ self.create_time = api_workflow.metadata.creation_timestamp
+ self.raw = api_workflow
def is_finished(self):
return self.status in (Phase.NodeError, Phase.NodeSucceeded, Phase.NodeSkipped, Phase.NodeFailed)
@@ -86,12 +79,17 @@ def failed(self):
return self.status == Phase.NodeFailed
def get_status_message(self):
- return self.raw['status']['message']
+ return self.raw.status.message
+
+ @property
+ def pod_names(self):
+ return [node.id for node in self.raw.status.nodes.values() if not node.children]
+
class SearchResult:
def __init__(self, raw_dict):
- self.items = tuple(Workflow(item) for item in raw_dict['items'])
- self.continue_token = raw_dict['metadata']['continue']
+ self.items = tuple(Workflow(item) for item in raw_dict.items)
+ self.continue_token = raw_dict.metadata._continue
self.raw = raw_dict
def __str__(self):
@@ -107,56 +105,16 @@ def get_api_client():
configuration = get_configuration()
# configuration.api_key['authorization'] = 'YOUR_API_KEY' # TODO verify if we need an api key
- api_instance = kubernetes.client.CustomObjectsApi(kubernetes.client.ApiClient(configuration))
+ api_instance = ApiClient(configuration)
return api_instance
def get_configuration():
- try:
- configuration = kubernetes.config.load_incluster_config()
-
- except:
- log.warning('Kubernetes cluster configuration not found. Trying local configuration')
-
- try:
- configuration = kubernetes.config.load_kube_config(
- config_file=os.path.join(str(Path.home()), '.kube', 'config'))
- except:
- log.warning('Kubernetes local configuration not found. Using localhost proxy')
- configuration = kubernetes.client.configuration.Configuration()
- host = 'http://localhost:8001'
- configuration.host = host
- return configuration
-
-
-api_instance = get_api_client()
-
-def check_namespace():
- api_instance = kubernetes.client.CoreV1Api(kubernetes.client.ApiClient(get_configuration()))
- try:
- api_response = api_instance.read_namespace(namespace, exact=True)
- except kubernetes.client.rest.ApiException as e:
-
- raise Exception("Namespace for argo workflows does not exist:" + namespace) from e
-
-def create_namespace():
- api_instance = kubernetes.client.CoreV1Api(kubernetes.client.ApiClient(get_configuration()))
- body = kubernetes.client.V1Namespace(metadata=kubernetes.client.V1ObjectMeta(name=namespace)) # V1Namespace |
-
-
- try:
- api_response = api_instance.create_namespace(body)
- except Exception as e:
- raise Exception("Error creating namespace:" + namespace) from e
-try:
- check_namespace()
-except Exception as e:
- log.error('Namespace for argo workflows not found', exc_info=e)
- log.info("Creating namespace %s", namespace)
- try:
- create_namespace()
- except Exception as e:
- log.error('Cannot connect with argo', exc_info=e)
+ if not conf.is_test():
+ host = applications.get_configuration('argo').get_service_address()
+ else:
+ host = applications.get_configuration('argo').get_public_address()
+ return Configuration(host=host)
def get_workflows(status=None, limit=10, continue_token=None, timeout_seconds=3) -> SearchResult:
@@ -164,27 +122,24 @@ def get_workflows(status=None, limit=10, continue_token=None, timeout_seconds=3)
# Notice: field selector doesn't work though advertised, except fot metadata.name and metadata.namespace https://github.com/kubernetes/kubernetes/issues/51046
# The filtering by phase can be obtained through labels: https://github.com/argoproj/argo/issues/496
- params = dict(pretty=False, timeout_seconds=timeout_seconds)
- if status is not None:
- if (status not in Phase.phases()):
- raise BadParam(status, 'Status must be one of {}'.format(Phase.phases()))
- params['label_selector'] = f'workflows.argoproj.io/phase={status}'
- api_response = api_instance.list_namespaced_custom_object(group, version, namespace, plural, **params)
+ service = WorkflowServiceApi(api_client=get_api_client())
- # TODO implement limit and continue, see https://github.com/kubernetes-client/python/issues/965
- # api_response = api_instance.list_cluster_custom_object(group, version, plural, pretty=False, timeout_seconds=timeout_seconds, watch=watch, limit=limit, continue_token=continue_token)
+ # pprint(service.list_workflows('ch', V1alpha1WorkflowList()))
+ api_response = service.list_workflows(namespace, list_options_limit=limit, list_options_continue=continue_token,
+ list_options_timeout_seconds=timeout_seconds)
return SearchResult(api_response)
def submit_workflow(spec) -> Workflow:
- """https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/CustomObjectsApi.md#create_namespaced_custom_object"""
- log.debug(f"Submitting workflow\n{spec}")
- workflow = Workflow(
- api_instance.create_namespaced_custom_object(group, version, namespace, plural, spec, pretty=False))
- log.info(f"Submitted argo workflow {workflow.name}")
- if workflow.failed():
- raise WorkflowException("Workflow failed: " + workflow.get_status_message())
- return workflow
+ log.debug(f"Submitting workflow %s", spec)
+
+ service = WorkflowServiceApi(api_client=get_api_client())
+
+ req = V1alpha1WorkflowCreateRequest(workflow=spec, instance_id=namespace, namespace=namespace)
+
+ # pprint(service.list_workflows('ch', V1alpha1WorkflowList()))
+ wf = service.create_workflow(namespace, req)
+ return Workflow(wf)
def delete_workflow(workflow_name):
@@ -199,37 +154,32 @@ def delete_workflow(workflow_name):
def get_workflow(workflow_name) -> Workflow:
+ service = WorkflowServiceApi(api_client=get_api_client())
try:
- workflow = Workflow(api_instance.get_namespaced_custom_object(group, version, namespace, plural, workflow_name))
- except kubernetes.client.rest.ApiException as e:
+ api_response = service.get_workflow(namespace, name=workflow_name)
+ except Exception as e:
if e.status == 404:
raise WorkflowNotFound()
- raise WorkflowException(e.status) from e
+ raise WorkflowException("Workflow get error") from e
+ workflow = Workflow(api_response)
if workflow.failed():
raise WorkflowException("Workflow failed: " + workflow.get_status_message())
+
return workflow
+
def get_workflow_logs(workflow_name) -> str:
- core_api_instance = kubernetes.client.CoreV1Api(kubernetes.client.ApiClient(get_configuration()))
-
- try:
- wf = api_instance.get_namespaced_custom_object(group, version, namespace, plural, workflow_name)
- except kubernetes.client.rest.ApiException as e:
- if e.status == 404:
- raise WorkflowNotFound()
- raise WorkflowException(e.status) from e
-
- pod_names = [node['id'] for node in wf['status']['nodes'].values() if not 'children' in node]
-
+ return '\n'.join(get_workflow_logs_list(workflow_name))
+
+
+def get_workflow_logs_list(workflow_name):
+ from ..infrastructure import k8s
+
+ workflow = get_workflow(workflow_name)
+ pod_names = workflow.pod_names
if len(pod_names) == 0:
return ''
-
- try:
- return core_api_instance.read_namespaced_pod_log(name=pod_names[0], namespace=namespace, container="main")
- except kubernetes.client.rest.ApiException as e:
- if e.status == 400:
- return "This step has not emitted logs yet..."
- raise WorkflowException(e.status) from e
+ return [k8s.get_pod_logs(pod_name) for pod_name in pod_names]
if __name__ == '__main__':
diff --git a/libraries/cloudharness-common/cloudharness/workflows/operations.py b/libraries/cloudharness-common/cloudharness/workflows/operations.py
index 79760082..78260e2a 100644
--- a/libraries/cloudharness-common/cloudharness/workflows/operations.py
+++ b/libraries/cloudharness-common/cloudharness/workflows/operations.py
@@ -1,21 +1,20 @@
-from collections.abc import Iterable
import time
-import yaml, pyaml
+import pyaml
+
+from collections.abc import Iterable
-SERVICE_ACCOUNT = 'argo-workflows'
from cloudharness_cli.workflows.models.operation_status import OperationStatus
from cloudharness.events.client import EventClient
from cloudharness.utils.settings import CODEFRESH_PULL_SECRET
from cloudharness.utils import env
+from cloudharness import log
from . import argo
-
from .tasks import Task, SendResultTask, CustomTask
-from cloudharness import log
-
POLLING_WAIT_SECONDS = 1
+SERVICE_ACCOUNT = 'argo-workflows'
class BadOperationConfiguration(RuntimeError):
@@ -58,28 +57,31 @@ def templates(self):
raise NotImplemented
def to_workflow(self, **arguments):
- workflow = {
+ return {
'apiVersion': 'argoproj.io/v1alpha1',
'kind': 'Workflow',
'metadata': {'generateName': self.name},
'spec': self.spec()
-
}
- return workflow
def spec(self):
spec = {
'entrypoint': self.entrypoint,
- 'TTLSecondsAfterFinished': 24*60*60, # remove the workflow & pod after 1 day
+ 'ttlStrategy': {
+ 'secondsAfterCompletion': 60 * 60,
+ 'secondsAfterSuccess': 60 * 20,
+ 'secondsAfterFailure': 60 * 120,
+ },
'templates': [self.modify_template(template) for template in self.templates],
'serviceAccountName': SERVICE_ACCOUNT,
'imagePullSecrets': [{'name': CODEFRESH_PULL_SECRET}],
'volumes': [{
- 'name': 'cloudharness-allvalues',
+ # mount allvalues so we can use the cloudharness Python library
+ 'name': 'cloudharness-allvalues',
'configMap': {
'name': 'cloudharness-allvalues'
}
- }] # mount allvalues so we can use the cloudharness Python library
+ }]
}
if self.on_exit_notify:
spec = self.add_on_exit_notify_handler(spec)
@@ -110,11 +112,9 @@ def submit(self):
op = self.to_workflow()
log.debug("Submitting workflow\n" + pyaml.dump(op))
- log.error(pyaml.dump(op))
- print(pyaml.dump(op))
-
- self.persisted = argo.submit_workflow(op) # TODO use rest api for that? Include this into cloudharness.workflows?
+ # TODO use rest api for that? Include this into cloudharness.workflows?
+ self.persisted = argo.submit_workflow(op)
return self.persisted
def is_running(self):
@@ -258,8 +258,10 @@ def templates(self):
def spec(self):
spec = super().spec()
if self.volumes:
- spec['volumeClaimTemplates'] = [self.spec_volumeclaim(volume) for volume in self.volumes if ':' not in volume] # without PVC prefix (e.g. /location)
- spec['volumes'] += [self.spec_volume(volume) for volume in self.volumes if ':' in volume] # with PVC prefix (e.g. pvc-001:/location)
+ spec['volumeClaimTemplates'] = [self.spec_volumeclaim(volume) for volume in self.volumes if
+ ':' not in volume] # without PVC prefix (e.g. /location)
+ spec['volumes'] += [self.spec_volume(volume) for volume in self.volumes if
+ ':' in volume] # with PVC prefix (e.g. pvc-001:/location)
return spec
def modify_template(self, template):
@@ -272,7 +274,7 @@ def volume_template(self, volume):
path = volume
if ":" in path:
path = volume.split(':')[-1]
- return dict({'name': self.name_from_path(path), 'mountPath': path })
+ return dict({'name': self.name_from_path(path), 'mountPath': path})
def spec_volumeclaim(self, volume):
# when the volume is NOT prefixed by a PVC (e.g. /location) then create a temporary PVC for the workflow
@@ -305,6 +307,7 @@ def spec_volume(self, volume):
}
return {}
+
class PipelineOperation(CompositeOperation):
def steps_spec(self):
@@ -334,12 +337,12 @@ def execute(self, timeout=None):
result = self.client.consume_all()
if result is None:
- raise RuntimeError("Operation `" + op.name + "` did not put results in the queue. Check your workflow configuration")
+ raise RuntimeError(
+ "Operation `" + op.name + "` did not put results in the queue. Check your workflow configuration")
self.client.delete_topic()
return result
-
class ParallelOperation(CompositeOperation):
def steps_spec(self):
diff --git a/libraries/cloudharness-common/cloudharness/workflows/tasks.py b/libraries/cloudharness-common/cloudharness/workflows/tasks.py
index 6c11a220..db7a9d6c 100644
--- a/libraries/cloudharness-common/cloudharness/workflows/tasks.py
+++ b/libraries/cloudharness-common/cloudharness/workflows/tasks.py
@@ -1,13 +1,11 @@
from . import argo
-import time
-SERVICE_ACCOUNT = 'argo-workflows'
-
-from cloudharness import log
from cloudharness.utils.env import get_cloudharness_variables, get_image_full_tag
-
from .utils import WORKFLOW_NAME_VARIABLE_NAME
+SERVICE_ACCOUNT = 'argo-workflows'
+
+
class Task(argo.ArgoObject):
"""
Abstract interface for a task.
@@ -64,10 +62,10 @@ def spec(self):
'resources': self.resources,
'imagePullPolicy': self.image_pull_policy,
'volumeMounts': [{
- 'name': 'cloudharness-allvalues',
- 'mountPath': '/opt/cloudharness/resources/allvalues.yaml',
- 'subPath': 'allvalues.yaml'
- }],
+ 'name': 'cloudharness-allvalues',
+ 'mountPath': '/opt/cloudharness/resources/allvalues.yaml',
+ 'subPath': 'allvalues.yaml'
+ }],
},
'inputs': {},
'metadata': {},
diff --git a/libraries/cloudharness-common/cloudharness/workflows/utils.py b/libraries/cloudharness-common/cloudharness/workflows/utils.py
index fcea0ba8..ac2ea3ec 100644
--- a/libraries/cloudharness-common/cloudharness/workflows/utils.py
+++ b/libraries/cloudharness-common/cloudharness/workflows/utils.py
@@ -5,18 +5,20 @@
WORKFLOW_NAME_VARIABLE_NAME = "CH_WORKFLOW_NAME"
-
SHARED_DIRECTORY_VARIABLE_NAME = "shared_directory"
+
def get_workflow_name():
"""Get the workflow name from inside a workflow"""
name = get_variable(WORKFLOW_NAME_VARIABLE_NAME)
remove = name.split("-")[-1]
- return name[0:-len(remove)-1]
+ return name[0:-len(remove) - 1]
+
def get_shared_directory():
return os.getenv(SHARED_DIRECTORY_VARIABLE_NAME)
+
def notify_queue(queue, message):
client = EventClient(queue)
client.produce(message)
diff --git a/libraries/cloudharness-common/requirements.txt b/libraries/cloudharness-common/requirements.txt
index d50d5d79..b92de7bd 100644
--- a/libraries/cloudharness-common/requirements.txt
+++ b/libraries/cloudharness-common/requirements.txt
@@ -2,11 +2,8 @@ asn1crypto==0.24.0
certifi==2019.3.9
cffi==1.12.2
chardet==3.0.4
-cryptography==3.2
idna==2.8
-jwt==1.0.0
-pycosat==0.6.3
-pycparser==2.19
+pyjwt>=1.7.1,<2
pyOpenSSL==19.0.0
PySocks==1.6.8
requests==2.21.0
@@ -19,3 +16,4 @@ kafka-python
kubernetes
sentry-sdk[flask]==0.14.4
python-keycloak==0.23.0
+argo-workflows==5.0.0
diff --git a/libraries/cloudharness-common/setup.py b/libraries/cloudharness-common/setup.py
index 931fcde9..c8b94a7b 100644
--- a/libraries/cloudharness-common/setup.py
+++ b/libraries/cloudharness-common/setup.py
@@ -3,7 +3,7 @@
NAME = "cloudharness"
-VERSION = "0.2.0"
+VERSION = "0.3.0"
# To install the library, run the following
#
# python setup.py install
@@ -15,10 +15,12 @@
'kubernetes',
'kafka-python',
'pyaml',
- 'jwt',
+ 'pyjwt>=1.7.1,<2',
+ 'cryptography',
'requests>=2.21.0',
'sentry-sdk[flask]>=0.14.4',
- 'python-keycloak==0.23.0'
+ 'python-keycloak==0.23.0',
+ 'argo-workflows'
]
diff --git a/libraries/cloudharness-common/test-requirements.txt b/libraries/cloudharness-common/test-requirements.txt
index 1ec5c478..435a3ac4 100644
--- a/libraries/cloudharness-common/test-requirements.txt
+++ b/libraries/cloudharness-common/test-requirements.txt
@@ -5,3 +5,5 @@ py>=1.4.31
randomize>=0.13
pytest>=5.0.0
pytest-cov
+-e .
+-e ../client/cloudharness_cli
\ No newline at end of file
diff --git a/libraries/cloudharness-common/tests/test_applications.py b/libraries/cloudharness-common/tests/test_applications.py
index 01f0b32b..dff50002 100644
--- a/libraries/cloudharness-common/tests/test_applications.py
+++ b/libraries/cloudharness-common/tests/test_applications.py
@@ -1,8 +1,9 @@
from cloudharness.applications import ApplicationConfiguration, get_configuration
conf_1 = {
- 'name': 'app1',
+
'harness': {
+ 'name': 'app1',
'service': {
'auto': False
},
@@ -14,8 +15,9 @@
}
conf_2 = {
- 'name': 'app2',
+
'harness': {
+ 'name': 'app2',
'service': {
'auto': False
},
@@ -27,8 +29,9 @@
}
conf_2sub = {
- 'name': 'app2sub',
+
'harness': {
+ 'name': 'app2sub',
'service': {
'auto': True
},
@@ -70,7 +73,6 @@ def test_get_configuration():
assert not uut.is_auto_deployment()
assert uut.is_sentry_enabled()
-
# uut = get_configuration('app2sub') # FIXME this should work
uut = uut.subapp
diff --git a/libraries/cloudharness-common/tests/test_env.py b/libraries/cloudharness-common/tests/test_env.py
index adcd7dc7..77bd2768 100644
--- a/libraries/cloudharness-common/tests/test_env.py
+++ b/libraries/cloudharness-common/tests/test_env.py
@@ -1,31 +1,14 @@
import pytest
+import os
import yaml
from cloudharness.utils.env import *
+from cloudharness.utils.config import CloudharnessConfig as conf
+HERE = os.path.dirname(os.path.realpath(__file__)).replace(os.path.sep, '/')
+def set_test_environment():
+ with open(os.path.join(HERE, 'values.yaml')) as f:
+ values = yaml.safe_load(f)
+ conf.get_configuration().update(values)
+ set_default_environment()
-
-
-
-def test_variables():
- os.environ['CH_USE_PUBLIC'] = "False"
- assert 'CH_DOMAIN' in os.environ
-
- assert get_variable('CH_DOMAIN') == 'cloudharness.metacell.us'
- assert get_sub_variable('CH_DOCS', 'NAME') == 'ch-docs'
- assert get_sub_variable('CH-docs', 'NAME') == 'ch-docs'
- assert get_sub_variable('CH_DOCS', 'IMAGE_NAME') == 'ch-docs'
-
- assert get_sub_variable('CH_DOCS', 'PORT') == '8080'
-
- assert get_image_registry() == 'localhost:5000'
- assert get_auth_service_url() == 'accounts.cloudharness.metacell.us'
- assert get_auth_service_cluster_address() == 'keycloak:8080'
- assert get_cloudharness_events_client_id() == 'web-client'
- assert get_cloudharness_workflows_service_url() == 'workflows.cloudharness.metacell.us'
- assert get_image_full_tag('workflows-extract-download') == 'localhost:5000/workflows-extract-download:latest'
-
- with pytest.raises(VariableNotFound) as raised:
- get_variable('CH_FAKE')
-
- assert raised.value.variable_name == 'CH_FAKE'
diff --git a/libraries/cloudharness-common/tests/test_infrastructure.py b/libraries/cloudharness-common/tests/test_infrastructure.py
new file mode 100644
index 00000000..c9395467
--- /dev/null
+++ b/libraries/cloudharness-common/tests/test_infrastructure.py
@@ -0,0 +1,13 @@
+from .test_env import set_test_environment
+
+set_test_environment()
+
+from cloudharness.infrastructure import k8s
+
+kubectl_enabled = False
+
+
+def test_get_pods():
+ if not kubectl_enabled:
+ return
+ return k8s.get_pods(namespace='kube_system')
diff --git a/libraries/cloudharness-common/tests/test_integration.py b/libraries/cloudharness-common/tests/test_integration.py
index 5139c625..9da8a087 100644
--- a/libraries/cloudharness-common/tests/test_integration.py
+++ b/libraries/cloudharness-common/tests/test_integration.py
@@ -1,2 +1,2 @@
def test_something():
- assert True
\ No newline at end of file
+ assert True
diff --git a/libraries/cloudharness-common/tests/test_workflow.py b/libraries/cloudharness-common/tests/test_workflow.py
index 8a8e09ca..3cb15144 100644
--- a/libraries/cloudharness-common/tests/test_workflow.py
+++ b/libraries/cloudharness-common/tests/test_workflow.py
@@ -1,15 +1,18 @@
"""Notice, this test needs a fully operating kubernetes with argo environment in the container running the test"""
-import time
+import requests
+import yaml
+
+from .test_env import set_test_environment
+
+set_test_environment()
-from cloudharness.workflows import operations
+from cloudharness.workflows import operations, tasks
from cloudharness import set_debug
+from cloudharness.workflows import argo
set_debug()
-import yaml
-from .test_env import set_default_environment
-
-set_default_environment()
+execute = False
def test_sync_workflow():
@@ -18,11 +21,12 @@ def f():
time.sleep(2)
print('whatever')
- task = operations.PythonTask('my-task', f)
+ task = tasks.PythonTask('my-task', f)
op = operations.DistributedSyncOperation('test-sync-op-', task)
print('\n', yaml.dump(op.to_workflow()))
- print(op.execute())
+ if execute:
+ print(op.execute())
def test_pipeline_workflow():
@@ -31,9 +35,10 @@ def f():
time.sleep(2)
print('whatever')
- op = operations.PipelineOperation('test-pipeline-op-', (operations.PythonTask('step1', f), operations.PythonTask('step2', f)))
+ op = operations.PipelineOperation('test-pipeline-op-', (tasks.PythonTask('step1', f), tasks.PythonTask('step2', f)))
print('\n', yaml.dump(op.to_workflow()))
- print(op.execute())
+ if execute:
+ print(op.execute())
def test_parallel_workflow():
@@ -42,9 +47,10 @@ def f():
time.sleep(2)
print('whatever')
- op = operations.ParallelOperation('test-parallel-op-', (operations.PythonTask('p1', f), operations.PythonTask('p2', f)))
+ op = operations.ParallelOperation('test-parallel-op-', (tasks.PythonTask('p1', f), tasks.PythonTask('p2', f)))
print('\n', yaml.dump(op.to_workflow()))
- print(op.execute())
+ if execute:
+ print(op.execute())
def test_simpledag_workflow():
@@ -54,38 +60,89 @@ def f():
print('whatever')
# p3 runs after p1 and p2 finish
- op = operations.SimpleDagOperation('test-dag-op-', (operations.PythonTask('p1', f), operations.PythonTask('p2', f)),
- operations.PythonTask('p3', f))
+ op = operations.SimpleDagOperation('test-dag-op-', (tasks.PythonTask('p1', f), tasks.PythonTask('p2', f)),
+ tasks.PythonTask('p3', f))
print('\n', yaml.dump(op.to_workflow()))
- print(op.execute())
+ if execute:
+ print(op.execute())
+
def test_custom_task_workflow():
- task = operations.CustomTask('download-file', 'cloudharness-workflows-extract-download', url='https://www.bing.com')
- op = operations.PipelineOperation('test-custom-op-', (task, ))
+ task = operations.CustomTask('download-file', 'workflows-extract-download', url='https://www.bing.com')
+ op = operations.PipelineOperation('test-custom-op-', (task,))
print('\n', yaml.dump(op.to_workflow()))
- print(op.execute())
+ if execute:
+ print(op.execute())
def test_custom_connected_task_workflow():
shared_directory = '/mnt/shared'
- task_write = operations.CustomTask('download-file', 'cloudharness-workflows-extract-download', url='https://raw.githubusercontent.com/openworm/org.geppetto/master/README.md')
- task_print = operations.CustomTask('print-file', 'cloudharness-workflows-print-file', file_path=shared_directory + '/README.md')
- op = operations.PipelineOperation('test-custom-connected-op-', (task_write, task_print), shared_directory=shared_directory)
+ task_write = operations.CustomTask('download-file', 'workflows-extract-download',
+ shared_directory=shared_directory,
+ url='https://raw.githubusercontent.com/openworm/org.geppetto/master/README.md')
+ task_print = operations.CustomTask('print-file', 'workflows-print-file', shared_directory=shared_directory,
+ file_path=shared_directory + '/README.md')
+ op = operations.PipelineOperation('test-custom-connected-op-', (task_write, task_print),
+ shared_directory=shared_directory, shared_volume_size=100)
# op.execute()
print('\n', yaml.dump(op.to_workflow()))
- print(op.execute())
+ if execute:
+ print(op.execute())
def test_result_task_workflow():
- task_write = operations.CustomTask('download-file', 'cloudharness-workflows-extract-download', url='https://raw.githubusercontent.com/openworm/org.geppetto/master/README.md')
+ task_write = operations.CustomTask('download-file', 'workflows-extract-download',
+ url='https://raw.githubusercontent.com/openworm/org.geppetto/master/README.md')
op = operations.DistributedSyncOperationWithResults('test-sync-results-', task_write)
-
# op.execute()
print('\n', yaml.dump(op.to_workflow()))
- print(op.execute())
-
-
-
-# op = operations.ParallelOperation('my_op', [task, operations.CustomTask('my-coreg', 'coregistration-init')])
+ if execute:
+ print(op.execute())
+
+
+def test_get_workflows():
+ if execute:
+ assert len(argo.get_workflows())
+
+
+def test_submit_workflow():
+ WORKFLOW = 'https://raw.githubusercontent.com/argoproj/argo/v2.12.2/examples/dag-diamond-steps.yaml'
+
+ resp = requests.get(WORKFLOW)
+ manifest: dict = yaml.safe_load(resp.text)
+ if execute:
+ wf = argo.submit_workflow(manifest)
+ assert wf
+ assert wf.name
+
+
+def test_get_workflow():
+ if not execute:
+ return
+ WORKFLOW = 'https://raw.githubusercontent.com/argoproj/argo/v2.12.2/examples/dag-diamond-steps.yaml'
+
+ resp = requests.get(WORKFLOW)
+ manifest: dict = yaml.safe_load(resp.text)
+ wf = argo.submit_workflow(manifest)
+ wf = argo.get_workflow(wf.name)
+ assert wf
+ assert wf.name
+ try:
+ argo.get_workflow('riuhfsdhsdfsfisdf')
+ assert 1 == 0 # not found raises exception
+ except:
+ pass
+
+
+def test_get_workflow_logs():
+ if not execute:
+ return
+ WORKFLOW = 'https://raw.githubusercontent.com/argoproj/argo/v2.12.2/examples/dag-diamond-steps.yaml'
+
+ resp = requests.get(WORKFLOW)
+ manifest: dict = yaml.safe_load(resp.text)
+ wf = argo.submit_workflow(manifest)
+ logs = argo.get_workflow_logs(wf.name)
+ assert all(log for log in logs)
diff --git a/libraries/cloudharness-common/tests/values.yaml b/libraries/cloudharness-common/tests/values.yaml
new file mode 100644
index 00000000..655fd4e7
--- /dev/null
+++ b/libraries/cloudharness-common/tests/values.yaml
@@ -0,0 +1,1113 @@
+local: true
+secured_gatekeepers: false
+nameOverride: ''
+fullnameOverride: ''
+domain: cloudharness.metacell.us
+namespace: ch
+registry:
+ name: localhost:5000/
+ secret: ''
+tag: latest
+apps:
+ volumemanager:
+ harness:
+ name: volumemanager
+ subdomain: volumemanager
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: true
+ replicas: 1
+ image: localhost:5000/volumemanager:latest
+ name: volumemanager
+ port: 8080
+ resources: &id001
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: true
+ name: volumemanager
+ port: 8080
+ database:
+ auto: false
+ name: volumemanager-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ sentry: true
+ image: localhost:5000/volumemanager:latest
+ name: volumemanager
+ port: 8080
+ resources: *id001
+ accounts:
+ harness:
+ name: accounts
+ subdomain: accounts
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: false
+ replicas: 1
+ image: localhost:5000/accounts:latest
+ name: accounts
+ port: 8080
+ resources: &id002
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: true
+ name: accounts
+ port: 8080
+ database:
+ auto: false
+ name: accounts-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ admin:
+ pass: metacell
+ user: admin
+ role: administrator
+ client:
+ id: rest-client
+ secret: 5678eb6e-9e2c-4ee5-bd54-34e7411339e8
+ db:
+ image: postgres:10.4
+ initialdb: auth_db
+ name: keycloak-postgress
+ pass: password
+ user: user
+ enabled: true
+ harvest: true
+ webclient:
+ id: web-client
+ secret: 452952ae-922c-4766-b912-7b106271e34b
+ name: accounts
+ port: 8080
+ subdomain: accounts
+ gatekeeper:
+ image: accounts-keycloak-gatekeeper
+ image: localhost:5000/accounts:latest
+ resources: *id002
+ samples:
+ harness:
+ name: samples
+ subdomain: samples
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: true
+ replicas: 1
+ image: localhost:5000/samples:latest
+ name: samples
+ port: 8080
+ resources: &id003
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: true
+ name: samples
+ port: 8080
+ database:
+ auto: false
+ name: samples-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ sentry: true
+ port: 80
+ env:
+ - name: WORKERS
+ value: '3'
+ image: localhost:5000/samples:latest
+ name: samples
+ port: 8080
+ resources: *id003
+ events:
+ harness:
+ name: events
+ subdomain: events
+ domain: null
+ secured: true
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: false
+ replicas: 1
+ image: localhost:5000/events:latest
+ name: events
+ port: 8081
+ resources: &id004
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: true
+ name: events
+ port: 80
+ database:
+ auto: false
+ name: events-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ kafka:
+ name: bootstrap
+ port: 9092
+ image: localhost:5000/events:latest
+ name: events
+ port: 8081
+ resources: *id004
+ common:
+ harness:
+ name: common
+ subdomain: common
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: true
+ replicas: 1
+ image: localhost:5000/common:latest
+ name: common
+ port: 8080
+ resources: &id005
+ requests:
+ memory: 128Mi
+ cpu: 100m
+ limits:
+ memory: 256Mi
+ cpu: 200m
+ service:
+ auto: true
+ name: common
+ port: 8080
+ database:
+ auto: false
+ name: common-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ image: localhost:5000/common:latest
+ name: common
+ port: 8080
+ resources: *id005
+ argo:
+ harness:
+ name: argo
+ subdomain: argo
+ domain: null
+ secured: true
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: false
+ replicas: 1
+ image: localhost:5000/argo:latest
+ name: argo
+ port: 8081
+ resources: &id006
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: false
+ name: argo-server
+ port: 2746
+ database:
+ auto: false
+ name: argo-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ serviceaccount: argo-workflows
+ image: localhost:5000/argo:latest
+ name: argo-server
+ port: 8081
+ resources: *id006
+ jupyterhub:
+ harness:
+ name: jupyterhub
+ subdomain: jupyterhub
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: false
+ replicas: 1
+ image: localhost:5000/jupyterhub:latest
+ name: jupyterhub
+ port: 8081
+ resources: &id007
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: false
+ name: proxy-public
+ port: 80
+ database:
+ auto: false
+ name: jupyterhub-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ custom: {}
+ hub:
+ allowNamedServers: true
+ namedServerLimitPerUser: 10
+ service:
+ type: ClusterIP
+ annotations: {}
+ ports:
+ nodePort: null
+ loadBalancerIP: null
+ baseUrl: /
+ cookieSecret: null
+ publicURL: null
+ initContainers: []
+ uid: 1000
+ fsGid: 1000
+ nodeSelector: {}
+ concurrentSpawnLimit: 64
+ consecutiveFailureLimit: 5
+ activeServerLimit: null
+ image:
+ pullSecrets: false
+ imagePullSecret:
+ enabled: false
+ livenessProbe:
+ enabled: false
+ readinessProbe:
+ enabled: false
+ deploymentStrategy:
+ type: Recreate
+ rollingUpdate: null
+ db:
+ type: sqlite-pvc
+ upgrade: null
+ pvc:
+ annotations: {}
+ selector: {}
+ accessModes:
+ - ReadWriteOnce
+ storage: 1Gi
+ subPath: null
+ storageClassName: null
+ url: null
+ password: null
+ labels: {}
+ annotations:
+ prometheus.io/scrape: 'true'
+ prometheus.io/path: /hub/metrics
+ extraConfig:
+ timing: |
+ c.Spawner.port = 8000
+ c.Spawner.http_timeout = 300
+ c.Spawner.start_timeout = 300
+ c.JupyterHub.tornado_settings = { "headers": { }}
+ spawner: c.Spawner.args = ["--debug", "--port=8000"]
+ extraConfigMap: {}
+ extraEnv: {}
+ extraContainers: []
+ extraVolumes: []
+ extraVolumeMounts: []
+ resources:
+ requests:
+ cpu: 200m
+ memory: 512Mi
+ services: {}
+ imagePullPolicy: IfNotPresent
+ pdb:
+ enabled: true
+ minAvailable: 1
+ networkPolicy:
+ enabled: false
+ egress:
+ - to:
+ - ipBlock:
+ cidr: 0.0.0.0/0
+ rbac:
+ enabled: true
+ proxy:
+ secretToken: b3fed077c7538cfc5e2a6469ddac7d43a18fc645789407b53e580b7342b968d8
+ service:
+ type: LoadBalancer
+ labels: {}
+ annotations: {}
+ nodePorts:
+ http: null
+ https: null
+ loadBalancerIP: null
+ chp:
+ image:
+ name: jupyterhub/configurable-http-proxy
+ tag: 4.0.1
+ pullPolicy: IfNotPresent
+ livenessProbe:
+ enabled: false
+ readinessProbe:
+ enabled: false
+ resources:
+ requests:
+ cpu: 200m
+ memory: 512Mi
+ nginx:
+ image:
+ name: quay.io/kubernetes-ingress-controller/nginx-ingress-controller
+ tag: 0.15.0
+ pullPolicy: IfNotPresent
+ proxyBodySize: 64m
+ resources: {}
+ lego:
+ image:
+ name: jetstack/kube-lego
+ tag: 0.1.7
+ pullPolicy: IfNotPresent
+ resources: {}
+ labels: {}
+ nodeSelector: {}
+ pdb:
+ enabled: true
+ minAvailable: 1
+ https:
+ enabled: true
+ type: letsencrypt
+ letsencrypt:
+ contactEmail: ''
+ manual:
+ key: null
+ cert: null
+ secret:
+ name: ''
+ key: tls.key
+ crt: tls.crt
+ hosts: []
+ networkPolicy:
+ enabled: false
+ egress:
+ - to:
+ - ipBlock:
+ cidr: 0.0.0.0/0
+ auth:
+ type: tmp
+ whitelist:
+ users: null
+ admin:
+ access: true
+ users: null
+ dummy:
+ password: null
+ ldap:
+ dn:
+ search: {}
+ user: {}
+ user: {}
+ state:
+ enabled: false
+ cryptoKey: null
+ singleuser:
+ extraTolerations: []
+ nodeSelector: {}
+ extraNodeAffinity:
+ required: []
+ preferred: []
+ extraPodAffinity:
+ required: []
+ preferred: []
+ extraPodAntiAffinity:
+ required: []
+ preferred: []
+ networkTools:
+ image:
+ name: jupyterhub/k8s-network-tools
+ tag: 0.9-b51ffeb
+ cloudMetadata:
+ enabled: false
+ ip: 169.254.169.254
+ networkPolicy:
+ enabled: false
+ egress:
+ - to:
+ - ipBlock:
+ cidr: 0.0.0.0/0
+ except:
+ - 169.254.169.254/32
+ events: true
+ extraAnnotations: {}
+ extraLabels: {}
+ extraEnv: {}
+ lifecycleHooks: null
+ initContainers: []
+ extraContainers: []
+ uid: 1000
+ fsGid: 100
+ serviceAccountName: null
+ storage:
+ type: dynamic
+ capacity: 2Mi
+ dynamic:
+ pvcNameTemplate: jupyter-{userid}
+ volumeNameTemplate: jupyter-{userid}
+ homeMountPath: /home/workspace
+ extraLabels: {}
+ image:
+ name: jupyter/base-notebook
+ tag: hub-1.1.0
+ pullPolicy: IfNotPresent
+ imagePullSecret:
+ enabled: false
+ startTimeout: 300
+ cpu:
+ limit: null
+ guarantee: null
+ memory:
+ limit: null
+ guarantee: 0.5G
+ extraResource:
+ limits: {}
+ guarantees: {}
+ cmd: jupyterhub-singleuser
+ defaultUrl: null
+ scheduling:
+ userScheduler:
+ enabled: false
+ replicas: 1
+ logLevel: 4
+ image:
+ name: gcr.io/google_containers/kube-scheduler-amd64
+ tag: v1.11.2
+ nodeSelector: {}
+ pdb:
+ enabled: true
+ minAvailable: 1
+ resources:
+ requests:
+ cpu: 50m
+ memory: 256Mi
+ podPriority:
+ enabled: false
+ userPlaceholder:
+ enabled: true
+ replicas: 0
+ corePods:
+ nodeAffinity:
+ matchNodePurpose: prefer
+ userPods:
+ nodeAffinity:
+ matchNodePurpose: prefer
+ prePuller:
+ hook:
+ enabled: true
+ extraEnv: {}
+ image:
+ name: jupyterhub/k8s-image-awaiter
+ tag: 0.9-b51ffeb
+ continuous:
+ enabled: false
+ extraImages: {}
+ pause:
+ image:
+ name: gcr.io/google_containers/pause
+ tag: '3.0'
+ ingress:
+ enabled: false
+ annotations: {}
+ hosts: []
+ pathSuffix: ''
+ tls: null
+ cull:
+ enabled: true
+ users: false
+ timeout: 600
+ every: 60
+ concurrency: 10
+ maxAge: 0
+ debug:
+ enabled: false
+ image: localhost:5000/jupyterhub:latest
+ name: jupyterhub
+ port: 8081
+ resources: *id007
+ mywebapp:
+ harness:
+ name: mywebapp
+ subdomain: mywebapp
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: true
+ replicas: 1
+ image: localhost:5000/mywebapp:latest
+ name: mywebapp
+ port: 8080
+ resources: &id008
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: true
+ name: mywebapp
+ port: 8080
+ database:
+ auto: true
+ name: mywebapp-mongo-db
+ type: mongo
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ port: 80
+ image: localhost:5000/mywebapp:latest
+ name: mywebapp
+ port: 8080
+ resources: *id008
+ workflows:
+ harness:
+ name: workflows
+ subdomain: workflows
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: true
+ replicas: 1
+ image: localhost:5000/workflows:latest
+ name: workflows
+ port: 8080
+ resources: &id009
+ requests:
+ memory: 32Mi
+ cpu: 25m
+ limits:
+ memory: 500Mi
+ cpu: 500m
+ service:
+ auto: true
+ name: workflows
+ port: 8080
+ database:
+ auto: false
+ name: workflows-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ image: localhost:5000/workflows:latest
+ name: workflows
+ port: 8080
+ resources: *id009
+ sentry:
+ harness:
+ name: sentry
+ subdomain: errormonitor
+ domain: null
+ secured: false
+ uri_role_mapping:
+ - uri: /*
+ roles:
+ - administrator
+ deployment:
+ auto: true
+ replicas: 1
+ image: localhost:5000/sentry:latest
+ name: sentry
+ port: 9000
+ resources: &id010
+ requests:
+ memory: 256Mi
+ cpu: 300m
+ limits:
+ memory: 2048Mi
+ cpu: 2000m
+ service:
+ auto: true
+ name: sentry
+ port: 9000
+ database:
+ auto: false
+ name: sentry-db
+ type: null
+ size: 1Gi
+ user: mnp
+ pass: metacell
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: 'false'
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 200m
+ limits:
+ memory: 2Gi
+ cpu: 1000m
+ postgres:
+ name: sentry-postgres-host
+ port: 5432
+ image: postgres:latest
+ initialdb: sentry
+ user: sentry
+ password: secret
+ datavolume: /opt/data/
+ pgdata: /opt/data/pgdata
+ redis:
+ name: sentry-redis-host
+ image: redis:latest
+ port: 6379
+ postfix:
+ name: sentry-postfix-host
+ image: eeacms/postfix:latest
+ port: 25
+ hostname: mail.opensourcebrain.org
+ image: localhost:5000/sentry:latest
+ name: sentry
+ port: 9000
+ resources: *id010
+env:
+- name: CH_VERSION
+ value: 0.0.1
+- name: CH_CHART_VERSION
+ value: 0.0.1
+- name: CH_VOLUMEMANAGER_NAME
+ value: volumemanager
+- name: CH_VOLUMEMANAGER_SUBDOMAIN
+ value: volumemanager
+- name: CH_ACCOUNTS_NAME
+ value: accounts
+- name: CH_ACCOUNTS_SUBDOMAIN
+ value: accounts
+- name: CH_SAMPLES_NAME
+ value: samples
+- name: CH_SAMPLES_SUBDOMAIN
+ value: samples
+- name: CH_SAMPLES_PORT
+ value: 80
+- name: CH_EVENTS_NAME
+ value: events
+- name: CH_EVENTS_SUBDOMAIN
+ value: events
+- name: CH_COMMON_NAME
+ value: common
+- name: CH_COMMON_SUBDOMAIN
+ value: common
+- name: CH_ARGO_NAME
+ value: argo-server
+- name: CH_ARGO_SUBDOMAIN
+ value: argo
+- name: CH_JUPYTERHUB_NAME
+ value: jupyterhub
+- name: CH_JUPYTERHUB_SUBDOMAIN
+ value: jupyterhub
+- name: CH_MYWEBAPP_NAME
+ value: mywebapp
+- name: CH_MYWEBAPP_SUBDOMAIN
+ value: mywebapp
+- name: CH_MYWEBAPP_PORT
+ value: 80
+- name: CH_WORKFLOWS_NAME
+ value: workflows
+- name: CH_WORKFLOWS_SUBDOMAIN
+ value: workflows
+- name: CH_SENTRY_NAME
+ value: sentry
+- name: CH_SENTRY_SUBDOMAIN
+ value: errormonitor
+- name: CH_DOMAIN
+ value: cloudharness.metacell.us
+- name: CH_IMAGE_REGISTRY
+ value: localhost:5000/
+- name: CH_IMAGE_TAG
+ value: latest
+- name: ARGO_INSTANCEID
+ value: ch
+privenv:
+- name: CH_SECRET
+ value: "In God we trust; all others must bring data. \u2015 W. Edwards Deming"
+ingress:
+ enabled: true
+ name: cloudharness-ingress
+ ssl_redirect: false
+ letsencrypt:
+ email: filippo@metacell.us
+tls: null
+localIp: 192.168.99.104
+test: true
diff --git a/utilities/MANIFEST.in b/utilities/MANIFEST.in
index 34a27b48..f0ccd934 100644
--- a/utilities/MANIFEST.in
+++ b/utilities/MANIFEST.in
@@ -2,6 +2,6 @@ include cloudharness_utilities/deployment-configuration/*
include cloudharness_utilities/deployment-configuration/**/*
include cloudharness_utilities/deployment-configuration/**/**/*
include cloudharness_utilities/deployment-configuration/**/**/**/*
-include cloudharness_utilities/application-template/*
-include cloudharness_utilities/application-template/**/*
-include cloudharness_utilities/application-template/**/**/*
\ No newline at end of file
+include cloudharness_utilities/application-templates/*
+include cloudharness_utilities/application-templates/**/*
+include cloudharness_utilities/application-templates/**/**/*
\ No newline at end of file
diff --git a/utilities/README.md b/utilities/README.md
index a1bbc44f..68c947b5 100644
--- a/utilities/README.md
+++ b/utilities/README.md
@@ -1,4 +1,4 @@
-#CloudHarness Deploy
+# CloudHarness Deploy
CloudHarness Deploy is a collection of Python utilities to create CloudHarness deployments.
@@ -25,19 +25,19 @@ Usage:
harness-application myapp
```
-For more info, `harness-application --help`
-
-## harness-codefresh
+Other examples:
-Generates the Codefresh continuous deployment specification.
-
-Usage:
+Create a web application
+```bash
+harness-application myapp -t webapp
+```
+Create a web application with Mongo database
```bash
-harness-codefresh .
+harness-application myapp -t webapp -t db-mongo
```
-For more info, `harness-codefresh --help`
+For more info, `harness-application --help`
## harness-generate
diff --git a/utilities/cloudharness_utilities/__init__.py b/utilities/cloudharness_utilities/__init__.py
index b821e067..3ed6da4a 100644
--- a/utilities/cloudharness_utilities/__init__.py
+++ b/utilities/cloudharness_utilities/__init__.py
@@ -8,4 +8,4 @@
]
)
-HERE = os.path.dirname(os.path.realpath(__file__))
\ No newline at end of file
+HERE = os.path.dirname(os.path.realpath(__file__))
diff --git a/utilities/cloudharness_utilities/application-template/api/config.json b/utilities/cloudharness_utilities/application-template/api/config.json
deleted file mode 100644
index 0dd0c28f..00000000
--- a/utilities/cloudharness_utilities/application-template/api/config.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "packageName": "api_samples"
-}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-template/api/openapi.yaml b/utilities/cloudharness_utilities/application-template/api/openapi.yaml
deleted file mode 100644
index 691a41c9..00000000
--- a/utilities/cloudharness_utilities/application-template/api/openapi.yaml
+++ /dev/null
@@ -1,47 +0,0 @@
-openapi: 3.0.0
-info:
- description: CloudHarness Sample api
- version: 0.1.0
- title: CloudHarness Sample API
- contact:
- email: cloudharness@metacell.us
- license:
- name: UNLICENSED
-
-tags:
- - name: auth
- - name: workflows
-
-paths:
- /test:
- get:
- summary: Test
- security:
- - bearerAuth: []
- tags:
- - auth
- operationId: test
- description: |
- Check if the token is valid
- responses:
- "200":
- description: Check if the application works
- "400":
- description: bad input parameter
-
-
-servers:
- - url: https://samples.cloudharness.metacell.us/api
-components:
- securitySchemes:
- bearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
- x-bearerInfoFunc: cloudharness.auth.decode_token
- schemas:
- Valid:
- type: object
- properties:
- response:
- type: string
diff --git a/utilities/cloudharness_utilities/application-template/deploy/values.yaml b/utilities/cloudharness_utilities/application-template/deploy/values.yaml
deleted file mode 100644
index 91949d61..00000000
--- a/utilities/cloudharness_utilities/application-template/deploy/values.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-port: 8080
-subdomain: samples
-autodeploy: true
-autoservice: true
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/README.md b/utilities/cloudharness_utilities/application-templates/README.md
new file mode 100644
index 00000000..0b2923f7
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/README.md
@@ -0,0 +1,7 @@
+# Application templates
+
+Add here all templates you want to merge/override
+Follow the directory structure:
+- base - those files are always added
+- webapp - webapp scaffolding
+- server - auto-generated server overriding files
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/base/api/config.json b/utilities/cloudharness_utilities/application-templates/base/api/config.json
new file mode 100644
index 00000000..06559b9a
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/base/api/config.json
@@ -0,0 +1,3 @@
+{
+ "packageName": "__APP_NAME__"
+}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/base/api/openapi.yaml b/utilities/cloudharness_utilities/application-templates/base/api/openapi.yaml
new file mode 100644
index 00000000..b3d81aaa
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/base/api/openapi.yaml
@@ -0,0 +1,75 @@
+openapi: 3.0.0
+info:
+ description: __APP_NAME__
+ version: 0.1.0
+ title: __APP_NAME__
+ contact:
+ email: cloudharness@metacell.us
+ license:
+ name: UNLICENSED
+
+tags:
+ - name: test
+ - name: live
+ - name: ready
+paths:
+ /ping:
+ get:
+ summary: test the application is up
+ operationId: ping
+ tags:
+ - test
+ responses:
+ "500":
+ description: This shouldn't happen
+ "200":
+ description: What we want
+ content:
+ application/json:
+ schema:
+ type: string
+ /live:
+ get:
+ summary: Test if application is healthy
+ operationId: live
+ tags:
+ - live
+ responses:
+ "500":
+ description: Application is not healthy
+ "200":
+ description: Healthy
+ content:
+ application/json:
+ schema:
+ type: string
+ /ready:
+ get:
+ summary: Test if application is ready to take requests
+ operationId: ready
+ tags:
+ - ready
+ responses:
+ "500":
+ description: Application is not ready yet
+ "200":
+ description: Ready
+ content:
+ application/json:
+ schema:
+ type: string
+servers:
+ - url: /api
+components:
+ securitySchemes:
+ bearerAuth:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
+ x-bearerInfoFunc: cloudharness.auth.decode_token
+ schemas:
+ Valid:
+ type: object
+ properties:
+ response:
+ type: string
diff --git a/utilities/cloudharness_utilities/application-templates/base/deploy/values.yaml b/utilities/cloudharness_utilities/application-templates/base/deploy/values.yaml
new file mode 100644
index 00000000..95383400
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/base/deploy/values.yaml
@@ -0,0 +1,17 @@
+harness:
+ subdomain: __APP_NAME__
+ secured: false
+ service:
+ port: 8080
+ auto: true
+ deployment:
+ auto: true
+ port: 8080
+ livenessProbe:
+ path: /api/live
+ readinessProbe:
+ path: /api/ready
+ dependencies:
+ build:
+ - cloudharness-base
+ - cloudharness-flask
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/db-mongo/deploy/values.yaml b/utilities/cloudharness_utilities/application-templates/db-mongo/deploy/values.yaml
new file mode 100644
index 00000000..f3519b50
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/db-mongo/deploy/values.yaml
@@ -0,0 +1,4 @@
+harness:
+ database:
+ auto: true
+ type: mongo
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/db-neo4j/deploy/values.yaml b/utilities/cloudharness_utilities/application-templates/db-neo4j/deploy/values.yaml
new file mode 100644
index 00000000..7ec22dab
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/db-neo4j/deploy/values.yaml
@@ -0,0 +1,4 @@
+harness:
+ database:
+ auto: true
+ type: neo4j
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/db-postgres/deploy/values.yaml b/utilities/cloudharness_utilities/application-templates/db-postgres/deploy/values.yaml
new file mode 100644
index 00000000..4e3494db
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/db-postgres/deploy/values.yaml
@@ -0,0 +1,4 @@
+harness:
+ database:
+ auto: true
+ type: postgres
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/.dockerignore b/utilities/cloudharness_utilities/application-templates/server/backend/.dockerignore
new file mode 100644
index 00000000..a05d73b5
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/server/backend/.dockerignore
@@ -0,0 +1,71 @@
+.travis.yaml
+.openapi-generator-ignore
+README.md
+tox.ini
+git_push.sh
+test-requirements.txt
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+.hypothesis/
+venv/
+.python-version
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+#Ipython Notebook
+.ipynb_checkpoints
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/.openapi-generator-ignore b/utilities/cloudharness_utilities/application-templates/server/backend/.openapi-generator-ignore
new file mode 100644
index 00000000..1b4d9526
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/server/backend/.openapi-generator-ignore
@@ -0,0 +1,29 @@
+# OpenAPI Generator Ignore
+# Generated by openapi-generator https://github.com/openapitools/openapi-generator
+
+# Use this file to prevent files from being overwritten by the generator.
+# The patterns follow closely to .gitignore or .dockerignore.
+
+# As an example, the C# client generator defines ApiClient.cs.
+# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
+#ApiClient.cs
+
+# You can match any string of characters against a directory, file or extension with a single asterisk (*):
+#foo/*/qux
+# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
+
+# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
+#foo/**/qux
+# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
+
+# You can also negate patterns with an exclamation (!).
+# For example, you can ignore all files in a docs folder with the file extension .md:
+#docs/*.md
+# Then explicitly reverse the ignore rule for a single file:
+#!docs/README.md
+setup.py
+*/controllers/*
+Dockerfile
+src/__main__.py
+requirements.txt
+test-requirements.txt
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/Dockerfile b/utilities/cloudharness_utilities/application-templates/server/backend/Dockerfile
new file mode 100644
index 00000000..3e968c23
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/server/backend/Dockerfile
@@ -0,0 +1,19 @@
+ARG REGISTRY
+ARG TAG=latest
+ARG CLOUDHARNESS_FLASK=${REGISTRY}cloudharness-flask:${TAG}
+
+FROM $CLOUDHARNESS_FLASK
+
+ENV MODULE_NAME=__APP_NAME__
+ENV WORKERS=2
+ENV PORT=8080
+
+COPY requirements.txt /usr/src/app/
+
+RUN pip3 install --no-cache-dir -r requirements.txt
+
+COPY . /usr/src/app
+
+RUN pip3 install -e .
+
+ENTRYPOINT gunicorn --workers=$WORKERS --bind=0.0.0.0:$PORT $MODULE_NAME.__main__:app
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/README.md b/utilities/cloudharness_utilities/application-templates/server/backend/README.md
new file mode 100644
index 00000000..ede3b1d1
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/server/backend/README.md
@@ -0,0 +1,27 @@
+# __APP_NAME__
+
+## Run
+```bash
+pip install -r requirements.txt
+pip install -e .
+python __main__.py
+```
+
+## Develop
+The backend is a Python Flask application.
+Connexion library maps the apis from the openapi definition to the Flask routing.
+
+### Implement api functions
+Api functions are all defined inside [__APP_NAME__/controllers](__APP_NAME__/controllers).
+Function stubs are automatically generated: just replace your function body with the desired code.
+Since the stubs are automatically generated, using other modules outside the controllers as helpers and services to
+implement the code logic is recommended.
+
+### Add api functions
+
+1. Edit [../api/openapi.yaml](api/openapi.yaml) as needed
+1. Remove/comment the controllers exclusion on [.openapi-generator-ignore](.openapi-generator-ignore) file
+1. Run `harness-generate .` from your deployment root
+1. Merge the files inside [__APP_NAME__/controllers](__APP_NAME__/controllers). For instance, you can
+ use git or ide history)
+1. Restore the [.openapi-generator-ignore](.openapi-generator-ignore) file
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/__init__.py b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/__main__.py b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/__main__.py
new file mode 100644
index 00000000..1ce1af97
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/__main__.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+
+from cloudharness.utils.server import init_flask, main
+
+
+app = init_flask(title="__APP_NAME__", init_app_fn=None, webapp=False)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/helpers/README.md b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/helpers/README.md
new file mode 100644
index 00000000..416d48b2
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/helpers/README.md
@@ -0,0 +1,4 @@
+# Controller helper modules functions
+
+Helpers implement specific parts of control logic.
+Controllers delegate the business logic to helpers.
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/helpers/__init__.py b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/helpers/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/services/README.md b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/services/README.md
new file mode 100644
index 00000000..d46309dd
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/services/README.md
@@ -0,0 +1,3 @@
+# Service modules and functions
+
+Services map session-less logic around domain models.
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/services/__init__.py b/utilities/cloudharness_utilities/application-templates/server/backend/__APP_NAME__/services/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/.dockerignore b/utilities/cloudharness_utilities/application-templates/webapp/.dockerignore
new file mode 100644
index 00000000..f06235c4
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/.dockerignore
@@ -0,0 +1,2 @@
+node_modules
+dist
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/Dockerfile b/utilities/cloudharness_utilities/application-templates/webapp/Dockerfile
new file mode 100644
index 00000000..d4285439
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/Dockerfile
@@ -0,0 +1,36 @@
+ARG REGISTRY
+ARG TAG=latest
+ARG CLOUDHARNESS_FRONTEND_BUILD=${REGISTRY}cloudharness-frontend-build:${TAG}
+ARG CLOUDHARNESS_FLASK=${REGISTRY}cloudharness-flask:${TAG}
+
+FROM $CLOUDHARNESS_FRONTEND_BUILD as frontend
+
+ENV APP_DIR=/app
+
+WORKDIR ${APP_DIR}
+COPY frontend/package.json ${APP_DIR}
+COPY frontend/package-lock.json ${APP_DIR}
+RUN npm ci
+
+COPY frontend ${APP_DIR}
+RUN npm run build
+
+#####
+
+FROM $CLOUDHARNESS_FLASK
+
+ENV MODULE_NAME=__APP_NAME__
+
+ENV WORKERS=2
+ENV PORT=8080
+
+COPY backend/requirements.txt /usr/src/app/
+
+RUN pip3 install --no-cache-dir -r requirements.txt
+
+COPY backend/ /usr/src/app
+RUN pip3 install -e .
+
+COPY --from=frontend app/dist/ /usr/src/app/www
+
+ENTRYPOINT gunicorn --workers=$WORKERS --bind=0.0.0.0:$PORT $MODULE_NAME.__main__:app
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/README.md b/utilities/cloudharness_utilities/application-templates/webapp/README.md
new file mode 100644
index 00000000..15fe7369
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/README.md
@@ -0,0 +1,68 @@
+# __APP_NAME__
+
+Flask/React-based web application.
+This application is constructed to be deployed inside a cloud-harness Kubernetes.
+It can be also run locally for development and test purpose.
+
+The code is generated with the script `harness-application` and is in part automatically generated
+from [openapi definition](./api/config.json).
+
+## Run with Docker
+
+```bash
+docker build . -t __APP_NAME__
+docker run -it -p 8080:8080 __APP_NAME__
+```
+
+Prerequisite: the cloudharness-frontend-build image must be built first:
+
+```bash
+cd [CLOUDHARNESS_ROOT]
+docker build . -f infrastructure/base-images/cloudharness-frontend-build/Dockerfile -t cloudharness-frontend-build
+```
+
+## Develop
+
+This application is composed of a Flask backend and a React frontend.
+
+### Backend
+
+Backend code is inside the *backend* directory.
+See [backend/README.md#Develop]
+
+### Frontend
+
+Backend code is inside the *frontend* directory.
+
+Frontend is by default generated as a React web application, but no constraint about this specific technology.
+
+#### Build and run
+
+To run in development mode:
+```bash
+cd frontend
+npm install
+npm run start
+```
+This setup will start the application at http://localhost:9000. use the backend running at http://localhost:5000.
+The backend can be either started from code or from Docker.
+In that case the launch command needs to match the port with:
+
+```bash
+docker run -it -p 5000:8080 __APP_NAME__
+```
+
+#### Call the backend apis
+All the api stubs are automatically generated in the [frontend/rest](frontend/rest) directory by `harness-application`
+and `harness-generate`.
+
+## Local run
+
+```bash
+cd frontend
+npm install
+npm run build
+cp dist '../backend/www' -R
+cd ../backend
+python __main__.py
+```
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/backend/__APP_NAME__/__main__.py b/utilities/cloudharness_utilities/application-templates/webapp/backend/__APP_NAME__/__main__.py
new file mode 100644
index 00000000..c6becb11
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/backend/__APP_NAME__/__main__.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+
+from cloudharness.utils.server import init_flask, main
+
+
+app = init_flask(title="__APP_NAME__", init_app_fn=None, webapp=True)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/deploy/values.yaml b/utilities/cloudharness_utilities/application-templates/webapp/deploy/values.yaml
new file mode 100644
index 00000000..498371df
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/deploy/values.yaml
@@ -0,0 +1,6 @@
+harness:
+ dependencies:
+ build:
+ - cloudharness-base
+ - cloudharness-frontend-build
+ - cloudharness-flask
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/.babelrc b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.babelrc
new file mode 100644
index 00000000..2b53150f
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.babelrc
@@ -0,0 +1,20 @@
+{
+ "presets": [
+ "@babel/preset-env",
+ "@babel/preset-react"
+ ],
+ "env": {
+ "production":{
+ "presets": ["minify"]
+ }
+ },
+ "plugins": [
+ "@babel/transform-regenerator",
+ "@babel/plugin-proposal-class-properties",
+ [
+ "module-resolver", {
+ "root": ["./src"]
+ }
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/.dockerignore b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.dockerignore
new file mode 100644
index 00000000..cf709889
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.dockerignore
@@ -0,0 +1 @@
+**/node_modules
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/.eslintignore b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.eslintignore
new file mode 100644
index 00000000..763301fc
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.eslintignore
@@ -0,0 +1,2 @@
+dist/
+node_modules/
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/.eslintrc.yml b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.eslintrc.yml
new file mode 100644
index 00000000..68fb53e5
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.eslintrc.yml
@@ -0,0 +1,49 @@
+---
+root: true
+extends:
+ - eslint:recommended
+ - plugin:react/recommended
+parser: 'babel-eslint'
+parserOptions:
+ ecmaFeatures:
+ jsx: true
+plugins:
+ - jest
+ - react
+ - react-hooks
+settings:
+ react:
+ version: detect
+env:
+ jest/globals: true
+ browser: true
+ es6: true
+rules:
+ no-console: 0
+ func-style: 2
+ consistent-return: 2
+ prefer-arrow-callback:
+ - 2
+ - allowNamedFunctions: false
+ allowUnboundThis: false
+ jest/no-disabled-tests: 2
+ jest/no-focused-tests: 2
+ react/prop-types: 0
+ react/forbid-prop-types: 0
+ react/no-unused-prop-types: 0
+ react-hooks/rules-of-hooks: 2
+ react-hooks/exhaustive-deps: 1
+ curly: 2
+ no-tabs: 2
+ arrow-spacing: 2
+ no-unneeded-ternary: 2
+ object-curly-spacing:
+ - 2
+ - always
+ indent:
+ - 2
+ - 2
+ - SwitchCase: 1
+globals:
+ __dirname: writable
+ module: writable
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/.gitignore b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.gitignore
new file mode 100644
index 00000000..149b5765
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/.gitignore
@@ -0,0 +1,4 @@
+wwwroot/*.js
+node_modules
+typings
+dist
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/README.md b/utilities/cloudharness_utilities/application-templates/webapp/frontend/README.md
new file mode 100644
index 00000000..f55bdc5b
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/README.md
@@ -0,0 +1 @@
+# __APP_NAME__
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/build.yaml b/utilities/cloudharness_utilities/application-templates/webapp/frontend/build.yaml
new file mode 100644
index 00000000..cbed1458
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/build.yaml
@@ -0,0 +1,2 @@
+build_arguments:
+ - MY_ARG=${{MY_ARG}}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/package-lock.json b/utilities/cloudharness_utilities/application-templates/webapp/frontend/package-lock.json
new file mode 100644
index 00000000..9f88d053
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/package-lock.json
@@ -0,0 +1,8800 @@
+{
+ "name": "samples",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "@babel/compat-data": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz",
+ "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==",
+ "dev": true
+ },
+ "@babel/core": {
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz",
+ "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/generator": "^7.12.10",
+ "@babel/helper-module-transforms": "^7.12.1",
+ "@babel/helpers": "^7.12.5",
+ "@babel/parser": "^7.12.10",
+ "@babel/template": "^7.12.7",
+ "@babel/traverse": "^7.12.10",
+ "@babel/types": "^7.12.10",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.1",
+ "json5": "^2.1.2",
+ "lodash": "^4.17.19",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/generator": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz",
+ "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.11",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-annotate-as-pure": {
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz",
+ "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.10"
+ }
+ },
+ "@babel/helper-builder-binary-assignment-operator-visitor": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz",
+ "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-explode-assignable-expression": "^7.10.4",
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "@babel/helper-compilation-targets": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz",
+ "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==",
+ "dev": true,
+ "requires": {
+ "@babel/compat-data": "^7.12.5",
+ "@babel/helper-validator-option": "^7.12.1",
+ "browserslist": "^4.14.5",
+ "semver": "^5.5.0"
+ }
+ },
+ "@babel/helper-create-class-features-plugin": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz",
+ "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-member-expression-to-functions": "^7.12.1",
+ "@babel/helper-optimise-call-expression": "^7.10.4",
+ "@babel/helper-replace-supers": "^7.12.1",
+ "@babel/helper-split-export-declaration": "^7.10.4"
+ }
+ },
+ "@babel/helper-create-regexp-features-plugin": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz",
+ "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.10.4",
+ "regexpu-core": "^4.7.1"
+ }
+ },
+ "@babel/helper-define-map": {
+ "version": "7.10.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz",
+ "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/types": "^7.10.5",
+ "lodash": "^4.17.19"
+ }
+ },
+ "@babel/helper-explode-assignable-expression": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz",
+ "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.1"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz",
+ "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.12.10",
+ "@babel/template": "^7.12.7",
+ "@babel/types": "^7.12.11"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz",
+ "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.10"
+ }
+ },
+ "@babel/helper-hoist-variables": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz",
+ "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "@babel/helper-member-expression-to-functions": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz",
+ "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz",
+ "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.5"
+ }
+ },
+ "@babel/helper-module-transforms": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz",
+ "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.12.1",
+ "@babel/helper-replace-supers": "^7.12.1",
+ "@babel/helper-simple-access": "^7.12.1",
+ "@babel/helper-split-export-declaration": "^7.11.0",
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "@babel/template": "^7.10.4",
+ "@babel/traverse": "^7.12.1",
+ "@babel/types": "^7.12.1",
+ "lodash": "^4.17.19"
+ }
+ },
+ "@babel/helper-optimise-call-expression": {
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz",
+ "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.10"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
+ "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
+ "dev": true
+ },
+ "@babel/helper-remap-async-to-generator": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz",
+ "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.10.4",
+ "@babel/helper-wrap-function": "^7.10.4",
+ "@babel/types": "^7.12.1"
+ }
+ },
+ "@babel/helper-replace-supers": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz",
+ "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-member-expression-to-functions": "^7.12.7",
+ "@babel/helper-optimise-call-expression": "^7.12.10",
+ "@babel/traverse": "^7.12.10",
+ "@babel/types": "^7.12.11"
+ }
+ },
+ "@babel/helper-simple-access": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz",
+ "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.1"
+ }
+ },
+ "@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz",
+ "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.1"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz",
+ "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.12.11"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
+ "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
+ "dev": true
+ },
+ "@babel/helper-validator-option": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz",
+ "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==",
+ "dev": true
+ },
+ "@babel/helper-wrap-function": {
+ "version": "7.12.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz",
+ "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/template": "^7.10.4",
+ "@babel/traverse": "^7.10.4",
+ "@babel/types": "^7.10.4"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz",
+ "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.10.4",
+ "@babel/traverse": "^7.12.5",
+ "@babel/types": "^7.12.5"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+ "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz",
+ "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==",
+ "dev": true
+ },
+ "@babel/plugin-proposal-async-generator-functions": {
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.12.tgz",
+ "integrity": "sha512-nrz9y0a4xmUrRq51bYkWJIO5SBZyG2ys2qinHsN0zHDHVsUaModrkpyWWWXfGqYQmOL3x9sQIcTNN/pBGpo09A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-remap-async-to-generator": "^7.12.1",
+ "@babel/plugin-syntax-async-generators": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-class-properties": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz",
+ "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-class-features-plugin": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-proposal-dynamic-import": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz",
+ "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-export-namespace-from": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz",
+ "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
+ }
+ },
+ "@babel/plugin-proposal-json-strings": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz",
+ "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-json-strings": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-logical-assignment-operators": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz",
+ "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
+ }
+ },
+ "@babel/plugin-proposal-nullish-coalescing-operator": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz",
+ "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-numeric-separator": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz",
+ "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-numeric-separator": "^7.10.4"
+ }
+ },
+ "@babel/plugin-proposal-object-rest-spread": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz",
+ "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+ "@babel/plugin-transform-parameters": "^7.12.1"
+ }
+ },
+ "@babel/plugin-proposal-optional-catch-binding": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz",
+ "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-optional-chaining": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz",
+ "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-private-methods": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz",
+ "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-class-features-plugin": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-proposal-unicode-property-regex": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz",
+ "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-syntax-async-generators": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-class-properties": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz",
+ "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-syntax-dynamic-import": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
+ "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-export-namespace-from": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
+ "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-jsx": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz",
+ "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-syntax-logical-assignment-operators": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+ "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-syntax-nullish-coalescing-operator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-numeric-separator": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+ "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+ "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-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==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-top-level-await": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz",
+ "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-arrow-functions": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz",
+ "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-async-to-generator": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz",
+ "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-remap-async-to-generator": "^7.12.1"
+ }
+ },
+ "@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz",
+ "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-block-scoping": {
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz",
+ "integrity": "sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-classes": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz",
+ "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.10.4",
+ "@babel/helper-define-map": "^7.10.4",
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-optimise-call-expression": "^7.10.4",
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-replace-supers": "^7.12.1",
+ "@babel/helper-split-export-declaration": "^7.10.4",
+ "globals": "^11.1.0"
+ }
+ },
+ "@babel/plugin-transform-computed-properties": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz",
+ "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-destructuring": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz",
+ "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-dotall-regex": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz",
+ "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-duplicate-keys": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz",
+ "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz",
+ "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-for-of": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz",
+ "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-function-name": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz",
+ "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.10.4",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-literals": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz",
+ "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-member-expression-literals": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz",
+ "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-modules-amd": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz",
+ "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "babel-plugin-dynamic-import-node": "^2.3.3"
+ }
+ },
+ "@babel/plugin-transform-modules-commonjs": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz",
+ "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-simple-access": "^7.12.1",
+ "babel-plugin-dynamic-import-node": "^2.3.3"
+ }
+ },
+ "@babel/plugin-transform-modules-systemjs": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz",
+ "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-hoist-variables": "^7.10.4",
+ "@babel/helper-module-transforms": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "babel-plugin-dynamic-import-node": "^2.3.3"
+ }
+ },
+ "@babel/plugin-transform-modules-umd": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz",
+ "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz",
+ "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.12.1"
+ }
+ },
+ "@babel/plugin-transform-new-target": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz",
+ "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-object-super": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz",
+ "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-replace-supers": "^7.12.1"
+ }
+ },
+ "@babel/plugin-transform-parameters": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz",
+ "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-property-literals": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz",
+ "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-react-display-name": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz",
+ "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-react-jsx": {
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.12.tgz",
+ "integrity": "sha512-JDWGuzGNWscYcq8oJVCtSE61a5+XAOos+V0HrxnDieUus4UMnBEosDnY1VJqU5iZ4pA04QY7l0+JvHL1hZEfsw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.12.10",
+ "@babel/helper-module-imports": "^7.12.5",
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-syntax-jsx": "^7.12.1",
+ "@babel/types": "^7.12.12"
+ }
+ },
+ "@babel/plugin-transform-react-jsx-development": {
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.12.tgz",
+ "integrity": "sha512-i1AxnKxHeMxUaWVXQOSIco4tvVvvCxMSfeBMnMM06mpaJt3g+MpxYQQrDfojUQldP1xxraPSJYSMEljoWM/dCg==",
+ "dev": true,
+ "requires": {
+ "@babel/plugin-transform-react-jsx": "^7.12.12"
+ }
+ },
+ "@babel/plugin-transform-react-pure-annotations": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz",
+ "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.10.4",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-regenerator": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz",
+ "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==",
+ "dev": true,
+ "requires": {
+ "regenerator-transform": "^0.14.2"
+ }
+ },
+ "@babel/plugin-transform-reserved-words": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz",
+ "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-shorthand-properties": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz",
+ "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-spread": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz",
+ "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1"
+ }
+ },
+ "@babel/plugin-transform-sticky-regex": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz",
+ "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-template-literals": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz",
+ "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-typeof-symbol": {
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz",
+ "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-unicode-escapes": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz",
+ "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/plugin-transform-unicode-regex": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz",
+ "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.12.1",
+ "@babel/helper-plugin-utils": "^7.10.4"
+ }
+ },
+ "@babel/preset-env": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz",
+ "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==",
+ "dev": true,
+ "requires": {
+ "@babel/compat-data": "^7.12.7",
+ "@babel/helper-compilation-targets": "^7.12.5",
+ "@babel/helper-module-imports": "^7.12.5",
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/helper-validator-option": "^7.12.11",
+ "@babel/plugin-proposal-async-generator-functions": "^7.12.1",
+ "@babel/plugin-proposal-class-properties": "^7.12.1",
+ "@babel/plugin-proposal-dynamic-import": "^7.12.1",
+ "@babel/plugin-proposal-export-namespace-from": "^7.12.1",
+ "@babel/plugin-proposal-json-strings": "^7.12.1",
+ "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
+ "@babel/plugin-proposal-numeric-separator": "^7.12.7",
+ "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.12.1",
+ "@babel/plugin-proposal-optional-chaining": "^7.12.7",
+ "@babel/plugin-proposal-private-methods": "^7.12.1",
+ "@babel/plugin-proposal-unicode-property-regex": "^7.12.1",
+ "@babel/plugin-syntax-async-generators": "^7.8.0",
+ "@babel/plugin-syntax-class-properties": "^7.12.1",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+ "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
+ "@babel/plugin-syntax-json-strings": "^7.8.0",
+ "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0",
+ "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.0",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.0",
+ "@babel/plugin-syntax-top-level-await": "^7.12.1",
+ "@babel/plugin-transform-arrow-functions": "^7.12.1",
+ "@babel/plugin-transform-async-to-generator": "^7.12.1",
+ "@babel/plugin-transform-block-scoped-functions": "^7.12.1",
+ "@babel/plugin-transform-block-scoping": "^7.12.11",
+ "@babel/plugin-transform-classes": "^7.12.1",
+ "@babel/plugin-transform-computed-properties": "^7.12.1",
+ "@babel/plugin-transform-destructuring": "^7.12.1",
+ "@babel/plugin-transform-dotall-regex": "^7.12.1",
+ "@babel/plugin-transform-duplicate-keys": "^7.12.1",
+ "@babel/plugin-transform-exponentiation-operator": "^7.12.1",
+ "@babel/plugin-transform-for-of": "^7.12.1",
+ "@babel/plugin-transform-function-name": "^7.12.1",
+ "@babel/plugin-transform-literals": "^7.12.1",
+ "@babel/plugin-transform-member-expression-literals": "^7.12.1",
+ "@babel/plugin-transform-modules-amd": "^7.12.1",
+ "@babel/plugin-transform-modules-commonjs": "^7.12.1",
+ "@babel/plugin-transform-modules-systemjs": "^7.12.1",
+ "@babel/plugin-transform-modules-umd": "^7.12.1",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1",
+ "@babel/plugin-transform-new-target": "^7.12.1",
+ "@babel/plugin-transform-object-super": "^7.12.1",
+ "@babel/plugin-transform-parameters": "^7.12.1",
+ "@babel/plugin-transform-property-literals": "^7.12.1",
+ "@babel/plugin-transform-regenerator": "^7.12.1",
+ "@babel/plugin-transform-reserved-words": "^7.12.1",
+ "@babel/plugin-transform-shorthand-properties": "^7.12.1",
+ "@babel/plugin-transform-spread": "^7.12.1",
+ "@babel/plugin-transform-sticky-regex": "^7.12.7",
+ "@babel/plugin-transform-template-literals": "^7.12.1",
+ "@babel/plugin-transform-typeof-symbol": "^7.12.10",
+ "@babel/plugin-transform-unicode-escapes": "^7.12.1",
+ "@babel/plugin-transform-unicode-regex": "^7.12.1",
+ "@babel/preset-modules": "^0.1.3",
+ "@babel/types": "^7.12.11",
+ "core-js-compat": "^3.8.0",
+ "semver": "^5.5.0"
+ }
+ },
+ "@babel/preset-modules": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz",
+ "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
+ "@babel/plugin-transform-dotall-regex": "^7.4.4",
+ "@babel/types": "^7.4.4",
+ "esutils": "^2.0.2"
+ }
+ },
+ "@babel/preset-react": {
+ "version": "7.12.10",
+ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.10.tgz",
+ "integrity": "sha512-vtQNjaHRl4DUpp+t+g4wvTHsLQuye+n0H/wsXIZRn69oz/fvNC7gQ4IK73zGJBaxvHoxElDvnYCthMcT7uzFoQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.10.4",
+ "@babel/plugin-transform-react-display-name": "^7.12.1",
+ "@babel/plugin-transform-react-jsx": "^7.12.10",
+ "@babel/plugin-transform-react-jsx-development": "^7.12.7",
+ "@babel/plugin-transform-react-pure-annotations": "^7.12.1"
+ }
+ },
+ "@babel/runtime": {
+ "version": "7.12.5",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz",
+ "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "@babel/template": {
+ "version": "7.12.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz",
+ "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/parser": "^7.12.7",
+ "@babel/types": "^7.12.7"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz",
+ "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.12.11",
+ "@babel/generator": "^7.12.11",
+ "@babel/helper-function-name": "^7.12.11",
+ "@babel/helper-split-export-declaration": "^7.12.11",
+ "@babel/parser": "^7.12.11",
+ "@babel/types": "^7.12.12",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.19"
+ }
+ },
+ "@babel/types": {
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz",
+ "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.12.11",
+ "lodash": "^4.17.19",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "@discoveryjs/json-ext": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz",
+ "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==",
+ "dev": true
+ },
+ "@nodelib/fs.scandir": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "2.0.4",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
+ "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.4",
+ "fastq": "^1.6.0"
+ }
+ },
+ "@npmcli/move-file": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz",
+ "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^1.0.4"
+ },
+ "dependencies": {
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ }
+ }
+ },
+ "@types/anymatch": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
+ "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
+ "dev": true
+ },
+ "@types/eslint": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz",
+ "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==",
+ "dev": true,
+ "requires": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "@types/eslint-scope": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz",
+ "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==",
+ "dev": true,
+ "requires": {
+ "@types/eslint": "*",
+ "@types/estree": "*"
+ }
+ },
+ "@types/estree": {
+ "version": "0.0.45",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz",
+ "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==",
+ "dev": true
+ },
+ "@types/glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
+ "dev": true,
+ "requires": {
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/html-minifier-terser": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
+ "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==",
+ "dev": true
+ },
+ "@types/json-schema": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
+ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
+ "dev": true
+ },
+ "@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": "14.14.20",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz",
+ "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==",
+ "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/tapable": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz",
+ "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==",
+ "dev": true
+ },
+ "@types/uglify-js": {
+ "version": "3.11.1",
+ "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz",
+ "integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==",
+ "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
+ }
+ }
+ },
+ "@types/webpack": {
+ "version": "4.41.25",
+ "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.25.tgz",
+ "integrity": "sha512-cr6kZ+4m9lp86ytQc1jPOJXgINQyz3kLLunZ57jznW+WIAL0JqZbGubQk4GlD42MuQL5JGOABrxdpqqWeovlVQ==",
+ "dev": true,
+ "requires": {
+ "@types/anymatch": "*",
+ "@types/node": "*",
+ "@types/tapable": "*",
+ "@types/uglify-js": "*",
+ "@types/webpack-sources": "*",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "@types/webpack-sources": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz",
+ "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/source-list-map": "*",
+ "source-map": "^0.7.3"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true
+ }
+ }
+ },
+ "@typescript-eslint/experimental-utils": {
+ "version": "2.34.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz",
+ "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/typescript-estree": "2.34.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
+ },
+ "dependencies": {
+ "eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ }
+ }
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "2.34.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz",
+ "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "eslint-visitor-keys": "^1.1.0",
+ "glob": "^7.1.6",
+ "is-glob": "^4.0.1",
+ "lodash": "^4.17.15",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "semver": {
+ "version": "7.3.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+ "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
+ }
+ },
+ "@webassemblyjs/ast": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz",
+ "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/helper-numbers": "1.11.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.11.0"
+ }
+ },
+ "@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz",
+ "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-api-error": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz",
+ "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-buffer": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz",
+ "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-numbers": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz",
+ "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/floating-point-hex-parser": "1.11.0",
+ "@webassemblyjs/helper-api-error": "1.11.0",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz",
+ "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==",
+ "dev": true
+ },
+ "@webassemblyjs/helper-wasm-section": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz",
+ "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.11.0",
+ "@webassemblyjs/helper-buffer": "1.11.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
+ "@webassemblyjs/wasm-gen": "1.11.0"
+ }
+ },
+ "@webassemblyjs/ieee754": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz",
+ "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==",
+ "dev": true,
+ "requires": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "@webassemblyjs/leb128": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz",
+ "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==",
+ "dev": true,
+ "requires": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/utf8": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz",
+ "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==",
+ "dev": true
+ },
+ "@webassemblyjs/wasm-edit": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz",
+ "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.11.0",
+ "@webassemblyjs/helper-buffer": "1.11.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
+ "@webassemblyjs/helper-wasm-section": "1.11.0",
+ "@webassemblyjs/wasm-gen": "1.11.0",
+ "@webassemblyjs/wasm-opt": "1.11.0",
+ "@webassemblyjs/wasm-parser": "1.11.0",
+ "@webassemblyjs/wast-printer": "1.11.0"
+ }
+ },
+ "@webassemblyjs/wasm-gen": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz",
+ "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.11.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
+ "@webassemblyjs/ieee754": "1.11.0",
+ "@webassemblyjs/leb128": "1.11.0",
+ "@webassemblyjs/utf8": "1.11.0"
+ }
+ },
+ "@webassemblyjs/wasm-opt": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz",
+ "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.11.0",
+ "@webassemblyjs/helper-buffer": "1.11.0",
+ "@webassemblyjs/wasm-gen": "1.11.0",
+ "@webassemblyjs/wasm-parser": "1.11.0"
+ }
+ },
+ "@webassemblyjs/wasm-parser": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz",
+ "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.11.0",
+ "@webassemblyjs/helper-api-error": "1.11.0",
+ "@webassemblyjs/helper-wasm-bytecode": "1.11.0",
+ "@webassemblyjs/ieee754": "1.11.0",
+ "@webassemblyjs/leb128": "1.11.0",
+ "@webassemblyjs/utf8": "1.11.0"
+ }
+ },
+ "@webassemblyjs/wast-printer": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz",
+ "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==",
+ "dev": true,
+ "requires": {
+ "@webassemblyjs/ast": "1.11.0",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webpack-cli/info": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz",
+ "integrity": "sha512-fLnDML5HZ5AEKzHul8xLAksoKN2cibu6MgonkUj8R9V7bbeVRkd1XbGEGWrAUNYHbX1jcqCsDEpBviE5StPMzQ==",
+ "dev": true,
+ "requires": {
+ "envinfo": "^7.7.3"
+ }
+ },
+ "@webpack-cli/serve": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz",
+ "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==",
+ "dev": true
+ },
+ "@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
+ },
+ "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": "6.4.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+ "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
+ "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
+ "dev": true
+ },
+ "aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "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==",
+ "dev": true
+ },
+ "ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true
+ },
+ "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": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true
+ },
+ "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": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "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": "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "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-includes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz",
+ "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "get-intrinsic": "^1.0.1",
+ "is-string": "^1.0.5"
+ }
+ },
+ "array-union": {
+ "version": "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
+ },
+ "array.prototype.flatmap": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz",
+ "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "function-bind": "^1.1.1"
+ }
+ },
+ "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": {
+ "version": "0.9.6",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz",
+ "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=",
+ "dev": true
+ },
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "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
+ },
+ "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
+ },
+ "awesome-typescript-loader": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-5.2.1.tgz",
+ "integrity": "sha512-slv66OAJB8orL+UUaTI3pKlLorwIvS4ARZzYR9iJJyGsEgOqueMfOMdKySWzZ73vIkEe3fcwFgsKMg4d8zyb1g==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "enhanced-resolve": "^4.0.0",
+ "loader-utils": "^1.1.0",
+ "lodash": "^4.17.5",
+ "micromatch": "^3.1.9",
+ "mkdirp": "^0.5.1",
+ "source-map-support": "^0.5.3",
+ "webpack-log": "^1.2.0"
+ }
+ },
+ "axios": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+ "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+ "requires": {
+ "follow-redirects": "^1.10.0"
+ }
+ },
+ "babel-eslint": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
+ "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.7.0",
+ "@babel/traverse": "^7.7.0",
+ "@babel/types": "^7.7.0",
+ "eslint-visitor-keys": "^1.0.0",
+ "resolve": "^1.12.0"
+ }
+ },
+ "babel-helper-evaluate-path": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz",
+ "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==",
+ "dev": true
+ },
+ "babel-helper-flip-expressions": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz",
+ "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=",
+ "dev": true
+ },
+ "babel-helper-is-nodes-equiv": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz",
+ "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=",
+ "dev": true
+ },
+ "babel-helper-is-void-0": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz",
+ "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=",
+ "dev": true
+ },
+ "babel-helper-mark-eval-scopes": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz",
+ "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=",
+ "dev": true
+ },
+ "babel-helper-remove-or-void": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz",
+ "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=",
+ "dev": true
+ },
+ "babel-helper-to-multiple-sequence-expressions": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz",
+ "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==",
+ "dev": true
+ },
+ "babel-loader": {
+ "version": "8.2.2",
+ "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz",
+ "integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==",
+ "dev": true,
+ "requires": {
+ "find-cache-dir": "^3.3.1",
+ "loader-utils": "^1.4.0",
+ "make-dir": "^3.1.0",
+ "schema-utils": "^2.6.5"
+ }
+ },
+ "babel-plugin-dynamic-import-node": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
+ "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==",
+ "dev": true,
+ "requires": {
+ "object.assign": "^4.1.0"
+ }
+ },
+ "babel-plugin-minify-builtins": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz",
+ "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==",
+ "dev": true
+ },
+ "babel-plugin-minify-constant-folding": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz",
+ "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==",
+ "dev": true,
+ "requires": {
+ "babel-helper-evaluate-path": "^0.5.0"
+ }
+ },
+ "babel-plugin-minify-dead-code-elimination": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz",
+ "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==",
+ "dev": true,
+ "requires": {
+ "babel-helper-evaluate-path": "^0.5.0",
+ "babel-helper-mark-eval-scopes": "^0.4.3",
+ "babel-helper-remove-or-void": "^0.4.3",
+ "lodash": "^4.17.11"
+ }
+ },
+ "babel-plugin-minify-flip-comparisons": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz",
+ "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=",
+ "dev": true,
+ "requires": {
+ "babel-helper-is-void-0": "^0.4.3"
+ }
+ },
+ "babel-plugin-minify-guarded-expressions": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz",
+ "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==",
+ "dev": true,
+ "requires": {
+ "babel-helper-evaluate-path": "^0.5.0",
+ "babel-helper-flip-expressions": "^0.4.3"
+ }
+ },
+ "babel-plugin-minify-infinity": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz",
+ "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=",
+ "dev": true
+ },
+ "babel-plugin-minify-mangle-names": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz",
+ "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==",
+ "dev": true,
+ "requires": {
+ "babel-helper-mark-eval-scopes": "^0.4.3"
+ }
+ },
+ "babel-plugin-minify-numeric-literals": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz",
+ "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=",
+ "dev": true
+ },
+ "babel-plugin-minify-replace": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz",
+ "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==",
+ "dev": true
+ },
+ "babel-plugin-minify-simplify": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz",
+ "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==",
+ "dev": true,
+ "requires": {
+ "babel-helper-evaluate-path": "^0.5.0",
+ "babel-helper-flip-expressions": "^0.4.3",
+ "babel-helper-is-nodes-equiv": "^0.0.1",
+ "babel-helper-to-multiple-sequence-expressions": "^0.5.0"
+ }
+ },
+ "babel-plugin-minify-type-constructors": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz",
+ "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=",
+ "dev": true,
+ "requires": {
+ "babel-helper-is-void-0": "^0.4.3"
+ }
+ },
+ "babel-plugin-module-resolver": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz",
+ "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==",
+ "dev": true,
+ "requires": {
+ "find-babel-config": "^1.2.0",
+ "glob": "^7.1.6",
+ "pkg-up": "^3.1.0",
+ "reselect": "^4.0.0",
+ "resolve": "^1.13.1"
+ }
+ },
+ "babel-plugin-transform-inline-consecutive-adds": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz",
+ "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=",
+ "dev": true
+ },
+ "babel-plugin-transform-member-expression-literals": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz",
+ "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=",
+ "dev": true
+ },
+ "babel-plugin-transform-merge-sibling-variables": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz",
+ "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=",
+ "dev": true
+ },
+ "babel-plugin-transform-minify-booleans": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz",
+ "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=",
+ "dev": true
+ },
+ "babel-plugin-transform-property-literals": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz",
+ "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "babel-plugin-transform-regexp-constructors": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz",
+ "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=",
+ "dev": true
+ },
+ "babel-plugin-transform-remove-console": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz",
+ "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=",
+ "dev": true
+ },
+ "babel-plugin-transform-remove-debugger": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz",
+ "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=",
+ "dev": true
+ },
+ "babel-plugin-transform-remove-undefined": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz",
+ "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==",
+ "dev": true,
+ "requires": {
+ "babel-helper-evaluate-path": "^0.5.0"
+ }
+ },
+ "babel-plugin-transform-simplify-comparison-operators": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz",
+ "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=",
+ "dev": true
+ },
+ "babel-plugin-transform-undefined-to-void": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz",
+ "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=",
+ "dev": true
+ },
+ "babel-preset-minify": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz",
+ "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==",
+ "dev": true,
+ "requires": {
+ "babel-plugin-minify-builtins": "^0.5.0",
+ "babel-plugin-minify-constant-folding": "^0.5.0",
+ "babel-plugin-minify-dead-code-elimination": "^0.5.1",
+ "babel-plugin-minify-flip-comparisons": "^0.4.3",
+ "babel-plugin-minify-guarded-expressions": "^0.4.4",
+ "babel-plugin-minify-infinity": "^0.4.3",
+ "babel-plugin-minify-mangle-names": "^0.5.0",
+ "babel-plugin-minify-numeric-literals": "^0.4.3",
+ "babel-plugin-minify-replace": "^0.5.0",
+ "babel-plugin-minify-simplify": "^0.5.1",
+ "babel-plugin-minify-type-constructors": "^0.4.3",
+ "babel-plugin-transform-inline-consecutive-adds": "^0.4.3",
+ "babel-plugin-transform-member-expression-literals": "^6.9.4",
+ "babel-plugin-transform-merge-sibling-variables": "^6.9.4",
+ "babel-plugin-transform-minify-booleans": "^6.9.4",
+ "babel-plugin-transform-property-literals": "^6.9.4",
+ "babel-plugin-transform-regexp-constructors": "^0.4.3",
+ "babel-plugin-transform-remove-console": "^6.9.4",
+ "babel-plugin-transform-remove-debugger": "^6.9.4",
+ "babel-plugin-transform-remove-undefined": "^0.5.0",
+ "babel-plugin-transform-simplify-comparison-operators": "^6.9.4",
+ "babel-plugin-transform-undefined-to-void": "^6.9.4",
+ "lodash": "^4.17.11"
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
+ "dev": true
+ },
+ "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": "1.13.1",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+ "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"
+ }
+ },
+ "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
+ },
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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": "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"
+ }
+ }
+ }
+ },
+ "browserslist": {
+ "version": "4.16.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz",
+ "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001173",
+ "colorette": "^1.2.1",
+ "electron-to-chromium": "^1.3.634",
+ "escalade": "^3.1.1",
+ "node-releases": "^1.1.69"
+ }
+ },
+ "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
+ },
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "call-bind": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.1.tgz",
+ "integrity": "sha512-tvAvUwNcRikl3RVF20X9lsYmmepsovzTWeJiXjO0PkJp15uy/6xKFZOQtuiSULwYW+6ToZBprphCgWXC2dSgcQ==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
+ "camel-case": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
+ "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
+ "dev": true,
+ "requires": {
+ "no-case": "^2.2.0",
+ "upper-case": "^1.1.1"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001174",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001174.tgz",
+ "integrity": "sha512-tqClL/4ThQq6cfFXH3oJL4rifFBeM6gTkphjao5kgwMaW9yn0tKgQLAEfKzDwj6HQWCB/aWo8kTFlSvIN8geEA==",
+ "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
+ },
+ "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"
+ },
+ "dependencies": {
+ "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"
+ }
+ }
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "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-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==",
+ "dev": true,
+ "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==",
+ "dev": true
+ }
+ }
+ },
+ "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
+ },
+ "clean-webpack-plugin": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz",
+ "integrity": "sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A==",
+ "dev": true,
+ "requires": {
+ "@types/webpack": "^4.4.31",
+ "del": "^4.1.1"
+ }
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
+ "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
+ "dev": true
+ },
+ "clipboard-copy": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/clipboard-copy/-/clipboard-copy-3.2.0.tgz",
+ "integrity": "sha512-vooFaGFL6ulEP1liiaWFBmmfuPm3cY3y7T9eB83ZTnYc/oFeAKsq3NcDrOkBC8XaauEE8zHQwI7k0+JSYiVQSQ=="
+ },
+ "cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "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-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "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=",
+ "dev": true
+ },
+ "colorette": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
+ "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
+ "dev": true
+ },
+ "commander": {
+ "version": "2.17.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+ "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
+ "dev": true
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+ "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
+ },
+ "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"
+ }
+ },
+ "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"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "compression-webpack-plugin": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-7.1.2.tgz",
+ "integrity": "sha512-9DKNW6ILLjx+bNBoviHDgLx6swBhWWH9ApClC9sTH2NoFfQM47BapQfovCm9zjD9v1uZwInF5a925FB9ErGQeQ==",
+ "dev": true,
+ "requires": {
+ "schema-utils": "^3.0.0",
+ "serialize-javascript": "^5.0.1"
+ },
+ "dependencies": {
+ "schema-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
+ "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.6",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.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
+ },
+ "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
+ },
+ "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-anything": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.1.tgz",
+ "integrity": "sha512-lA57e7viQHOdPQcrytv5jFeudZZOXuyk47lZym279FiDQ8jeZomXiGuVf6ffMKkJ+3TIai3J1J3yi6M+/4U35g==",
+ "dev": true,
+ "requires": {
+ "is-what": "^3.7.1"
+ }
+ },
+ "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": "6.4.1",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz",
+ "integrity": "sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA==",
+ "dev": true,
+ "requires": {
+ "cacache": "^15.0.5",
+ "fast-glob": "^3.2.4",
+ "find-cache-dir": "^3.3.1",
+ "glob-parent": "^5.1.1",
+ "globby": "^11.0.1",
+ "loader-utils": "^2.0.0",
+ "normalize-path": "^3.0.0",
+ "p-limit": "^3.0.2",
+ "schema-utils": "^3.0.0",
+ "serialize-javascript": "^5.0.1",
+ "webpack-sources": "^1.4.3"
+ },
+ "dependencies": {
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
+ "cacache": {
+ "version": "15.0.5",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz",
+ "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==",
+ "dev": true,
+ "requires": {
+ "@npmcli/move-file": "^1.0.1",
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "glob": "^7.1.4",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.1",
+ "minipass-collect": "^1.0.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.2",
+ "mkdirp": "^1.0.3",
+ "p-map": "^4.0.0",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^3.0.2",
+ "ssri": "^8.0.0",
+ "tar": "^6.0.2",
+ "unique-filename": "^1.1.1"
+ }
+ },
+ "chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true
+ },
+ "globby": {
+ "version": "11.0.2",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
+ "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ }
+ },
+ "loader-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
+ "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ }
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "schema-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
+ "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.6",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ }
+ },
+ "serialize-javascript": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
+ "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "ssri": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz",
+ "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.1.1"
+ }
+ }
+ }
+ },
+ "core-js-compat": {
+ "version": "3.8.2",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.2.tgz",
+ "integrity": "sha512-LO8uL9lOIyRRrQmZxHZFl1RV+ZbcsAkFWTktn5SmH40WgLtSNYN4m4W2v9ONT147PxBY/XrRhrWq8TlvObyUjQ==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.16.0",
+ "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
+ },
+ "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"
+ }
+ },
+ "css-loader": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
+ "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
+ "dev": true,
+ "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.32",
+ "postcss-modules-extract-imports": "^2.0.0",
+ "postcss-modules-local-by-default": "^3.0.2",
+ "postcss-modules-scope": "^2.2.0",
+ "postcss-modules-values": "^3.0.0",
+ "postcss-value-parser": "^4.1.0",
+ "schema-utils": "^2.7.0",
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "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-what": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
+ "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==",
+ "dev": true
+ },
+ "cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true
+ },
+ "d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+ "dev": true,
+ "requires": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "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"
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "dev": true
+ },
+ "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
+ },
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ }
+ },
+ "dns-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
+ "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
+ "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"
+ }
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "dom-converter": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
+ "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==",
+ "dev": true,
+ "requires": {
+ "utila": "~0.4"
+ }
+ },
+ "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.1.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz",
+ "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==",
+ "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
+ },
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "dot-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+ "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ },
+ "dependencies": {
+ "lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+ "dev": true,
+ "requires": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "no-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+ "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+ "dev": true,
+ "requires": {
+ "lower-case": "^2.0.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "tslib": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
+ "dev": true
+ }
+ }
+ },
+ "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.635",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.635.tgz",
+ "integrity": "sha512-RRriZOLs9CpW6KTLmgBqyUdnY0QNqqWs0HOtuQGGEMizOTNNn1P7sGRBxARnUeLejOsgwjDyRqT3E/CSst02ZQ==",
+ "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
+ },
+ "emojis-list": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+ "dev": true
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "enhanced-resolve": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
+ "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "memory-fs": "^0.5.0",
+ "tapable": "^1.0.0"
+ }
+ },
+ "enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^4.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "entities": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true
+ },
+ "envinfo": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.3.tgz",
+ "integrity": "sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==",
+ "dev": true
+ },
+ "errno": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+ "dev": true,
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "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.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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=",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "d": "^1.0.1",
+ "ext": "^1.1.2"
+ }
+ },
+ "es6-templates": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz",
+ "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=",
+ "dev": true,
+ "requires": {
+ "recast": "~0.11.12",
+ "through": "~2.3.6"
+ }
+ },
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
+ "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": {
+ "version": "5.16.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz",
+ "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.9.1",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "eslint-scope": "^4.0.3",
+ "eslint-utils": "^1.3.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^5.0.1",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.7.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^6.2.2",
+ "js-yaml": "^3.13.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.11",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "semver": "^5.5.1",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "^2.0.1",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0"
+ },
+ "dependencies": {
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-plugin-jest": {
+ "version": "23.20.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.20.0.tgz",
+ "integrity": "sha512-+6BGQt85OREevBDWCvhqj1yYA4+BFK4XnRZSGJionuEYmcglMZYLNNBBemwzbqUAckURaHdJSBcjHPyrtypZOw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/experimental-utils": "^2.5.0"
+ }
+ },
+ "eslint-plugin-react": {
+ "version": "7.22.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz",
+ "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.1.1",
+ "array.prototype.flatmap": "^1.2.3",
+ "doctrine": "^2.1.0",
+ "has": "^1.0.3",
+ "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+ "object.entries": "^1.1.2",
+ "object.fromentries": "^2.0.2",
+ "object.values": "^1.1.1",
+ "prop-types": "^15.7.2",
+ "resolve": "^1.18.1",
+ "string.prototype.matchall": "^4.0.2"
+ },
+ "dependencies": {
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ }
+ }
+ },
+ "eslint-plugin-react-hooks": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-3.0.0.tgz",
+ "integrity": "sha512-EjxTHxjLKIBWFgDJdhKKzLh5q+vjTFrqNZX36uIxWS4OfyXe5DawqPj3U5qeJ1ngLwatjzQnmR0Lz0J0YH3kxw==",
+ "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"
+ }
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ },
+ "espree": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz",
+ "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==",
+ "dev": true,
+ "requires": {
+ "acorn": "^6.0.7",
+ "acorn-jsx": "^5.0.0",
+ "eslint-visitor-keys": "^1.0.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==",
+ "dev": true
+ },
+ "esquery": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
+ "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "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.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true
+ },
+ "events": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
+ "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "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": {
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "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
+ },
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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
+ }
+ }
+ },
+ "ext": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
+ "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
+ "dev": true,
+ "requires": {
+ "type": "^2.0.0"
+ },
+ "dependencies": {
+ "type": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz",
+ "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==",
+ "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"
+ }
+ }
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "fast-glob": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
+ "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "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
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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==",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "fastest-levenshtein": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
+ "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
+ "dev": true
+ },
+ "fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "fastq": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz",
+ "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "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"
+ }
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^2.0.1"
+ }
+ },
+ "file-loader": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-5.1.0.tgz",
+ "integrity": "sha512-u/VkLGskw3Ue59nyOwUwXI/6nuBCo7KBkniB/l7ICwr/7cPNGsL1WCXUp3GB0qgOOKU1TiP49bv4DZF/LJqprg==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^1.4.0",
+ "schema-utils": "^2.5.0"
+ }
+ },
+ "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
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "find-babel-config": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz",
+ "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==",
+ "dev": true,
+ "requires": {
+ "json5": "^0.5.1",
+ "path-exists": "^3.0.0"
+ },
+ "dependencies": {
+ "json5": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+ "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
+ }
+ }
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "dev": true,
+ "requires": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "flatted": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
+ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
+ "dev": true
+ },
+ "follow-redirects": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
+ "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "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
+ },
+ "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"
+ }
+ },
+ "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": "1.2.13",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1"
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "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=",
+ "dev": true
+ },
+ "gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true
+ },
+ "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
+ },
+ "get-intrinsic": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz",
+ "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "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
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "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": "5.1.1",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "dev": true
+ },
+ "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": "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
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "handle-thing": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
+ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
+ "dev": true
+ },
+ "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-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.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
+ },
+ "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": {
+ "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"
+ }
+ }
+ }
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "history": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
+ "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
+ "requires": {
+ "@babel/runtime": "^7.1.2",
+ "loose-envify": "^1.2.0",
+ "resolve-pathname": "^3.0.0",
+ "tiny-invariant": "^1.0.2",
+ "tiny-warning": "^1.0.0",
+ "value-equal": "^1.0.1"
+ }
+ },
+ "hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "requires": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "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"
+ }
+ },
+ "html-entities": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz",
+ "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==",
+ "dev": true
+ },
+ "html-loader": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-0.5.5.tgz",
+ "integrity": "sha512-7hIW7YinOYUpo//kSYcPB6dCKoceKLmOwjEMmhIobHuWGDVl0Nwe4l68mdG/Ru0wcUxQjVMEoZpkalZ/SE7zog==",
+ "dev": true,
+ "requires": {
+ "es6-templates": "^0.2.3",
+ "fastparse": "^1.1.1",
+ "html-minifier": "^3.5.8",
+ "loader-utils": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "html-minifier": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz",
+ "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==",
+ "dev": true,
+ "requires": {
+ "camel-case": "3.0.x",
+ "clean-css": "4.2.x",
+ "commander": "2.17.x",
+ "he": "1.2.x",
+ "param-case": "2.1.x",
+ "relateurl": "0.2.x",
+ "uglify-js": "3.4.x"
+ }
+ },
+ "html-minifier-terser": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
+ "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==",
+ "dev": true,
+ "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": {
+ "camel-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
+ "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
+ "dev": true,
+ "requires": {
+ "pascal-case": "^3.1.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true
+ },
+ "param-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
+ "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
+ "dev": true,
+ "requires": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "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": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
+ "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.20.0",
+ "source-map": "~0.6.1",
+ "source-map-support": "~0.5.12"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ }
+ }
+ },
+ "tslib": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
+ "dev": true
+ }
+ }
+ },
+ "html-webpack-plugin": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.1.tgz",
+ "integrity": "sha512-yzK7RQZwv9xB+pcdHNTjcqbaaDZ+5L0zJHXfi89iWIZmb/FtzxhLk0635rmJihcQbs3ZUF27Xp4oWGx6EK56zg==",
+ "dev": true,
+ "requires": {
+ "@types/html-minifier-terser": "^5.0.0",
+ "@types/tapable": "^1.0.5",
+ "@types/webpack": "^4.41.8",
+ "html-minifier-terser": "^5.0.1",
+ "loader-utils": "^1.2.3",
+ "lodash": "^4.17.20",
+ "pretty-error": "^2.1.1",
+ "tapable": "^1.1.3",
+ "util.promisify": "1.0.0"
+ }
+ },
+ "htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "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==",
+ "dev": true
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "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.5.3",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz",
+ "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==",
+ "dev": true
+ },
+ "http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "http-proxy": "^1.17.0",
+ "is-glob": "^4.0.0",
+ "lodash": "^4.17.11",
+ "micromatch": "^3.1.10"
+ }
+ },
+ "human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.14"
+ }
+ },
+ "ignore": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
+ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
+ "dev": true
+ },
+ "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
+ },
+ "import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.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"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "inquirer": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
+ "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^3.2.0",
+ "chalk": "^2.4.2",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.12",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.4.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.1.0",
+ "through": "^2.3.6"
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "internal-slot": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz",
+ "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==",
+ "dev": true,
+ "requires": {
+ "es-abstract": "^1.17.0-next.1",
+ "has": "^1.0.3",
+ "side-channel": "^1.0.2"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "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.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ }
+ }
+ },
+ "interpret": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
+ "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
+ "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.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "dev": 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-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.1.0",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz",
+ "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.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=",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^1.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.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true
+ },
+ "is-core-module": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
+ "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "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.2",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
+ "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
+ "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-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-negative-zero": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
+ "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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-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-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "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-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==",
+ "dev": true
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "is-what": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.12.0.tgz",
+ "integrity": "sha512-2ilQz5/f/o9V7WRWJQmpFYNmQFZ9iM+OXRonZKcYgTkCzjb949Vi4h282PD1UfmgHk666rcWonbRJ++KI41VGw==",
+ "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": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "jest-worker": {
+ "version": "26.6.2",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
+ "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "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-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==",
+ "dev": true
+ },
+ "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=",
+ "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": "2.1.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
+ "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "jsx-ast-utils": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
+ "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.1.2",
+ "object.assign": "^4.1.2"
+ }
+ },
+ "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.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ },
+ "less": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz",
+ "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==",
+ "dev": true,
+ "requires": {
+ "copy-anything": "^2.0.1",
+ "errno": "^0.1.1",
+ "graceful-fs": "^4.1.2",
+ "image-size": "~0.5.0",
+ "make-dir": "^2.1.0",
+ "mime": "^1.4.1",
+ "native-request": "^1.0.5",
+ "source-map": "~0.6.0",
+ "tslib": "^1.10.0"
+ },
+ "dependencies": {
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ }
+ },
+ "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"
+ }
+ },
+ "less-vars-to-js": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/less-vars-to-js/-/less-vars-to-js-1.3.0.tgz",
+ "integrity": "sha512-xeiLLn/IMCGtdyCkYQnW8UuzoW2oYMCKg9boZRaGI58fLz5r90bNJDlqGzmVt/1Uqk75/DxIVtQSNCMkE5fRZQ==",
+ "dev": true,
+ "requires": {
+ "strip-json-comments": "^2.0.1"
+ }
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "loader-runner": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
+ "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==",
+ "dev": true
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ }
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1"
+ }
+ },
+ "loglevel": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz",
+ "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==",
+ "dev": true
+ },
+ "loglevelnext": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz",
+ "integrity": "sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A==",
+ "dev": true,
+ "requires": {
+ "es6-symbol": "^3.1.1",
+ "object.assign": "^4.1.0"
+ }
+ },
+ "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": "1.1.4",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=",
+ "dev": true
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "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
+ },
+ "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-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
+ },
+ "merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "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"
+ }
+ },
+ "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.45.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
+ "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.28",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
+ "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.45.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true
+ },
+ "mini-create-react-context": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz",
+ "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==",
+ "requires": {
+ "@babel/runtime": "^7.12.1",
+ "tiny-warning": "^1.0.3"
+ }
+ },
+ "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
+ },
+ "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.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "minipass": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
+ "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minipass-pipeline": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+ "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dev": true,
+ "requires": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.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.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.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
+ },
+ "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.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "nan": {
+ "version": "2.14.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
+ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
+ "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"
+ }
+ },
+ "native-request": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.8.tgz",
+ "integrity": "sha512-vU2JojJVelUGp6jRcLwToPoWGxSx23z/0iX+I77J3Ht17rf2INGjrhOoQnjVo60nQd8wVsgzKkPfRXBiVdD2ag==",
+ "dev": true,
+ "optional": true
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "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.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true
+ },
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+ "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
+ },
+ "no-case": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
+ "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
+ "dev": true,
+ "requires": {
+ "lower-case": "^1.1.1"
+ }
+ },
+ "node-forge": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
+ "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
+ "dev": true
+ },
+ "node-releases": {
+ "version": "1.1.69",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz",
+ "integrity": "sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA==",
+ "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
+ },
+ "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"
+ }
+ },
+ "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=",
+ "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.9.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
+ "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==",
+ "dev": true
+ },
+ "object-is": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz",
+ "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "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.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ }
+ },
+ "object.entries": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz",
+ "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "has": "^1.0.3"
+ }
+ },
+ "object.fromentries": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.3.tgz",
+ "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "has": "^1.0.3"
+ }
+ },
+ "object.getownpropertydescriptors": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz",
+ "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "object.values": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz",
+ "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "has": "^1.0.3"
+ }
+ },
+ "obuf": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
+ "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": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "opn": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
+ "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
+ "dev": true,
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "url-parse": "^1.4.3"
+ }
+ },
+ "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
+ },
+ "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-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "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
+ },
+ "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
+ },
+ "param-case": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
+ "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
+ "dev": true,
+ "requires": {
+ "no-case": "^2.2.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==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.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
+ },
+ "pascal-case": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
+ "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
+ "dev": true,
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ },
+ "dependencies": {
+ "lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+ "dev": true,
+ "requires": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "no-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+ "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+ "dev": true,
+ "requires": {
+ "lower-case": "^2.0.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "tslib": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
+ "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-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": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "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": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+ "requires": {
+ "isarray": "0.0.1"
+ }
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "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": "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"
+ }
+ },
+ "pkg-up": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
+ "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
+ "dev": true,
+ "requires": {
+ "find-up": "^3.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ }
+ }
+ },
+ "portfinder": {
+ "version": "1.0.28",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
+ "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.2",
+ "debug": "^3.1.1",
+ "mkdirp": "^0.5.5"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "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=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "7.0.35",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+ "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+ "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-modules-extract-imports": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
+ "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.5"
+ }
+ },
+ "postcss-modules-local-by-default": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz",
+ "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==",
+ "dev": true,
+ "requires": {
+ "icss-utils": "^4.1.1",
+ "postcss": "^7.0.32",
+ "postcss-selector-parser": "^6.0.2",
+ "postcss-value-parser": "^4.1.0"
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz",
+ "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "requires": {
+ "icss-utils": "^4.0.0",
+ "postcss": "^7.0.6"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
+ "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
+ "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
+ "pretty-error": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz",
+ "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.20",
+ "renderkid": "^2.0.4"
+ }
+ },
+ "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-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
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true
+ },
+ "promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
+ "dev": true
+ },
+ "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==",
+ "dev": true,
+ "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=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "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
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "dev": true
+ },
+ "querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "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"
+ }
+ },
+ "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": "4.0.2",
+ "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
+ "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^2.0.0",
+ "schema-utils": "^3.0.0"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
+ "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ }
+ },
+ "schema-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
+ "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.6",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ }
+ }
+ }
+ },
+ "react": {
+ "version": "16.14.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
+ "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.2"
+ }
+ },
+ "react-dom": {
+ "version": "16.14.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
+ "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.2",
+ "scheduler": "^0.19.1"
+ }
+ },
+ "react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
+ "react-router": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
+ "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==",
+ "requires": {
+ "@babel/runtime": "^7.1.2",
+ "history": "^4.9.0",
+ "hoist-non-react-statics": "^3.1.0",
+ "loose-envify": "^1.3.1",
+ "mini-create-react-context": "^0.4.0",
+ "path-to-regexp": "^1.7.0",
+ "prop-types": "^15.6.2",
+ "react-is": "^16.6.0",
+ "tiny-invariant": "^1.0.2",
+ "tiny-warning": "^1.0.0"
+ }
+ },
+ "react-router-dom": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz",
+ "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==",
+ "requires": {
+ "@babel/runtime": "^7.1.2",
+ "history": "^4.9.0",
+ "loose-envify": "^1.3.1",
+ "prop-types": "^15.6.2",
+ "react-router": "5.2.0",
+ "tiny-invariant": "^1.0.2",
+ "tiny-warning": "^1.0.0"
+ }
+ },
+ "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==",
+ "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"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "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"
+ }
+ },
+ "recast": {
+ "version": "0.11.23",
+ "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz",
+ "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=",
+ "dev": true,
+ "requires": {
+ "ast-types": "0.9.6",
+ "esprima": "~3.1.0",
+ "private": "~0.1.5",
+ "source-map": "~0.5.0"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+ "dev": true
+ }
+ }
+ },
+ "rechoir": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz",
+ "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==",
+ "dev": true,
+ "requires": {
+ "resolve": "^1.9.0"
+ }
+ },
+ "regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "dev": true
+ },
+ "regenerate-unicode-properties": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz",
+ "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==",
+ "dev": true,
+ "requires": {
+ "regenerate": "^1.4.0"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.7",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
+ "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
+ },
+ "regenerator-transform": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz",
+ "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.8.4"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "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"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "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.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ }
+ }
+ },
+ "regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+ "dev": true
+ },
+ "regexpu-core": {
+ "version": "4.7.1",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz",
+ "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==",
+ "dev": true,
+ "requires": {
+ "regenerate": "^1.4.0",
+ "regenerate-unicode-properties": "^8.2.0",
+ "regjsgen": "^0.5.1",
+ "regjsparser": "^0.6.4",
+ "unicode-match-property-ecmascript": "^1.0.4",
+ "unicode-match-property-value-ecmascript": "^1.2.0"
+ }
+ },
+ "regjsgen": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz",
+ "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==",
+ "dev": true
+ },
+ "regjsparser": {
+ "version": "0.6.6",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.6.tgz",
+ "integrity": "sha512-jjyuCp+IEMIm3N1H1LLTJW1EISEJV9+5oHdEyrt43Pg9cDSb6rrLZei2cVWpl0xTjmmlpec/lEQGYgM7xfpGCQ==",
+ "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
+ }
+ }
+ },
+ "relateurl": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+ "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
+ "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
+ },
+ "renderkid": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz",
+ "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==",
+ "dev": true,
+ "requires": {
+ "css-select": "^2.0.2",
+ "dom-converter": "^0.2",
+ "htmlparser2": "^3.10.1",
+ "lodash": "^4.17.20",
+ "strip-ansi": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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
+ },
+ "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": "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
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "reselect": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
+ "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+ "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.1.0",
+ "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"
+ },
+ "dependencies": {
+ "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-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "resolve-pathname": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
+ "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "requires": {
+ "onetime": "^2.0.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
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "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"
+ }
+ },
+ "run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "dev": true
+ },
+ "run-parallel": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz",
+ "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==",
+ "dev": true
+ },
+ "rxjs": {
+ "version": "6.6.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+ "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+ "dev": true,
+ "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==",
+ "dev": true
+ },
+ "scheduler": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
+ "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "schema-utils": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
+ "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.5",
+ "ajv": "^6.12.4",
+ "ajv-keywords": "^3.5.2"
+ }
+ },
+ "select-hose": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
+ "dev": true
+ },
+ "selfsigned": {
+ "version": "1.10.8",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
+ "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
+ "dev": true,
+ "requires": {
+ "node-forge": "^0.10.0"
+ }
+ },
+ "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": {
+ "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"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "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": "5.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
+ "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+ "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": {
+ "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"
+ }
+ },
+ "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
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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-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"
+ }
+ }
+ }
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+ "dev": true
+ },
+ "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
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "signal-exit": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+ "dev": true
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "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": {
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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"
+ }
+ }
+ }
+ },
+ "sockjs": {
+ "version": "0.3.21",
+ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz",
+ "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==",
+ "dev": true,
+ "requires": {
+ "faye-websocket": "^0.11.3",
+ "uuid": "^3.4.0",
+ "websocket-driver": "^0.7.4"
+ }
+ },
+ "sockjs-client": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.0.tgz",
+ "integrity": "sha512-8Dt3BDi4FYNrCFGTL/HtwVzkARrENdwOUf1ZoW/9p3M8lZdFT35jVdrHza+qgxuG9H3/shR4cuX/X9umUrjP8Q==",
+ "dev": true,
+ "requires": {
+ "debug": "^3.2.6",
+ "eventsource": "^1.0.7",
+ "faye-websocket": "^0.11.3",
+ "inherits": "^2.0.4",
+ "json3": "^3.3.3",
+ "url-parse": "^1.4.7"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
+ "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.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-support": {
+ "version": "0.5.19",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+ "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+ "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
+ },
+ "spdy": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
+ "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
+ "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"
+ }
+ },
+ "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": {
+ "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==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.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
+ },
+ "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
+ },
+ "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"
+ }
+ },
+ "string.prototype.matchall": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz",
+ "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "has-symbols": "^1.0.1",
+ "internal-slot": "^1.0.2",
+ "regexp.prototype.flags": "^1.3.0",
+ "side-channel": "^1.0.3"
+ }
+ },
+ "string.prototype.trimend": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
+ "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "string.prototype.trimstart": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz",
+ "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "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": "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"
+ }
+ },
+ "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
+ },
+ "strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true
+ },
+ "style-loader": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
+ "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "^2.0.0",
+ "schema-utils": "^2.7.0"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
+ "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+ "dev": true,
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "table": {
+ "version": "5.4.6",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+ "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.10.2",
+ "lodash": "^4.17.14",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "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"
+ }
+ }
+ }
+ },
+ "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": "6.1.0",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
+ "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
+ "dev": true,
+ "requires": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^3.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "dependencies": {
+ "chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ }
+ }
+ },
+ "terser": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz",
+ "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.20.0",
+ "source-map": "~0.7.2",
+ "source-map-support": "~0.5.19"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "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==",
+ "dev": true
+ }
+ }
+ },
+ "terser-webpack-plugin": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz",
+ "integrity": "sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==",
+ "dev": true,
+ "requires": {
+ "jest-worker": "^26.6.2",
+ "p-limit": "^3.1.0",
+ "schema-utils": "^3.0.0",
+ "serialize-javascript": "^5.0.1",
+ "source-map": "^0.6.1",
+ "terser": "^5.5.1"
+ },
+ "dependencies": {
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "schema-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
+ "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.6",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ }
+ },
+ "serialize-javascript": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
+ "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "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
+ },
+ "thunky": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
+ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
+ "dev": true
+ },
+ "tiny-invariant": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
+ "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
+ },
+ "tiny-warning": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "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": "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"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "dev": true
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "tsutils": {
+ "version": "3.19.1",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.19.1.tgz",
+ "integrity": "sha512-GEdoBf5XI324lu7ycad7s6laADfnAqCw6wLGI+knxvw9vsIYBaJfYdmeCEG3FMMUiSm3OGgNb+m6utsWf5h9Vw==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "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"
+ }
+ },
+ "typescript": {
+ "version": "3.9.7",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
+ "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
+ "dev": true
+ },
+ "uglify-js": {
+ "version": "3.4.10",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
+ "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==",
+ "dev": true,
+ "requires": {
+ "commander": "~2.19.0",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
+ "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
+ "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
+ }
+ }
+ },
+ "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.2.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz",
+ "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==",
+ "dev": true
+ },
+ "unicode-property-aliases-ecmascript": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
+ "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
+ "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
+ },
+ "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"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "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
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "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
+ },
+ "upper-case": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
+ "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=",
+ "dev": true
+ },
+ "uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "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=",
+ "dev": true,
+ "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=",
+ "dev": true
+ }
+ }
+ },
+ "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
+ },
+ "use-clipboard-copy": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/use-clipboard-copy/-/use-clipboard-copy-0.1.2.tgz",
+ "integrity": "sha512-EkauxqyX+us4+Mfif/f61ew89EAOWIArqFpHR0jSG4SwwuDZzDAOeqO7gkK0vi+DQVADeB1RB3xqU3U0oOO3NQ==",
+ "requires": {
+ "clipboard-copy": "^3.0.0"
+ }
+ },
+ "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": "1.0.0",
+ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
+ "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "object.getownpropertydescriptors": "^2.0.3"
+ }
+ },
+ "utila": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
+ "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=",
+ "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.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "dev": true
+ },
+ "v8-compile-cache": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz",
+ "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==",
+ "dev": true
+ },
+ "value-equal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
+ "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "dev": true
+ },
+ "watchpack": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.0.tgz",
+ "integrity": "sha512-UjgD1mqjkG99+3lgG36at4wPnUXNvis2v1utwTgQ43C22c4LD71LsYMExdWXh4HZ+RmW+B0t1Vrg2GpXAkTOQw==",
+ "dev": true,
+ "requires": {
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.1.2"
+ }
+ },
+ "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"
+ }
+ },
+ "webpack": {
+ "version": "5.12.3",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.12.3.tgz",
+ "integrity": "sha512-7tiQmcTnKhZwbf7X7sEfXe0pgkGjUZjT6JfYkZHvvIb4/ZsXl1rJu5PxsJoN7W3v5sNSP/8TgBoiOdDqVdvK5w==",
+ "dev": true,
+ "requires": {
+ "@types/eslint-scope": "^3.7.0",
+ "@types/estree": "^0.0.45",
+ "@webassemblyjs/ast": "1.11.0",
+ "@webassemblyjs/wasm-edit": "1.11.0",
+ "@webassemblyjs/wasm-parser": "1.11.0",
+ "acorn": "^8.0.4",
+ "browserslist": "^4.14.5",
+ "chrome-trace-event": "^1.0.2",
+ "enhanced-resolve": "^5.3.1",
+ "eslint-scope": "^5.1.1",
+ "events": "^3.2.0",
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.2.4",
+ "json-parse-better-errors": "^1.0.2",
+ "loader-runner": "^4.2.0",
+ "mime-types": "^2.1.27",
+ "neo-async": "^2.6.2",
+ "pkg-dir": "^5.0.0",
+ "schema-utils": "^3.0.0",
+ "tapable": "^2.1.1",
+ "terser-webpack-plugin": "^5.1.1",
+ "watchpack": "^2.0.0",
+ "webpack-sources": "^2.1.1"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz",
+ "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==",
+ "dev": true
+ },
+ "enhanced-resolve": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.5.0.tgz",
+ "integrity": "sha512-b4a6BasBCoLzri4MdaeOlDMpls2oioI28CF17csMiav9dq46yvQaKPFNUrCHB6VqQokBDG2VIEEL81jMiQ6Wtw==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ }
+ },
+ "eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ },
+ "pkg-dir": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz",
+ "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==",
+ "dev": true,
+ "requires": {
+ "find-up": "^5.0.0"
+ }
+ },
+ "schema-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
+ "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.6",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.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
+ },
+ "tapable": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
+ "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==",
+ "dev": true
+ },
+ "webpack-sources": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz",
+ "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==",
+ "dev": true,
+ "requires": {
+ "source-list-map": "^2.0.1",
+ "source-map": "^0.6.1"
+ }
+ }
+ }
+ },
+ "webpack-cli": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz",
+ "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==",
+ "dev": true,
+ "requires": {
+ "@discoveryjs/json-ext": "^0.5.0",
+ "@webpack-cli/info": "^1.2.1",
+ "@webpack-cli/serve": "^1.2.1",
+ "colorette": "^1.2.1",
+ "commander": "^6.2.0",
+ "enquirer": "^2.3.6",
+ "execa": "^5.0.0",
+ "fastest-levenshtein": "^1.0.12",
+ "import-local": "^3.0.2",
+ "interpret": "^2.2.0",
+ "rechoir": "^0.7.0",
+ "v8-compile-cache": "^2.2.0",
+ "webpack-merge": "^4.2.2"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "dev": true
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ }
+ },
+ "execa": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz",
+ "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ }
+ },
+ "get-stream": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz",
+ "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==",
+ "dev": true
+ },
+ "import-local": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz",
+ "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==",
+ "dev": true,
+ "requires": {
+ "pkg-dir": "^4.2.0",
+ "resolve-cwd": "^3.0.0"
+ }
+ },
+ "is-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+ "dev": true
+ },
+ "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
+ },
+ "npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.0.0"
+ }
+ },
+ "onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "resolve-cwd": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+ "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+ "dev": true,
+ "requires": {
+ "resolve-from": "^5.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "webpack-dev-middleware": {
+ "version": "3.7.3",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz",
+ "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==",
+ "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.7",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz",
+ "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==",
+ "dev": true
+ },
+ "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-dev-server": {
+ "version": "3.11.1",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.1.tgz",
+ "integrity": "sha512-u4R3mRzZkbxQVa+MBWi2uVpB5W59H3ekZAJsQlKUTdl7Elcah2EhygTPLmeFXybQkf9i2+L0kn7ik9SnXa6ihQ==",
+ "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.3.1",
+ "http-proxy-middleware": "0.19.1",
+ "import-local": "^2.0.0",
+ "internal-ip": "^4.3.0",
+ "ip": "^1.1.5",
+ "is-absolute-url": "^3.0.3",
+ "killable": "^1.0.1",
+ "loglevel": "^1.6.8",
+ "opn": "^5.5.0",
+ "p-retry": "^3.0.1",
+ "portfinder": "^1.0.26",
+ "schema-utils": "^1.0.0",
+ "selfsigned": "^1.10.8",
+ "semver": "^6.3.0",
+ "serve-index": "^1.9.1",
+ "sockjs": "^0.3.21",
+ "sockjs-client": "^1.5.0",
+ "spdy": "^4.0.2",
+ "strip-ansi": "^3.0.1",
+ "supports-color": "^6.1.0",
+ "url": "^0.11.0",
+ "webpack-dev-middleware": "^3.7.2",
+ "webpack-log": "^2.0.0",
+ "ws": "^6.2.1",
+ "yargs": "^13.3.2"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "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"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "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-log": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz",
+ "integrity": "sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.1.0",
+ "log-symbols": "^2.1.0",
+ "loglevelnext": "^1.0.1",
+ "uuid": "^3.1.0"
+ }
+ },
+ "webpack-merge": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz",
+ "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==",
+ "dev": true,
+ "requires": {
+ "clone-deep": "^4.0.1",
+ "wildcard": "^2.0.0"
+ }
+ },
+ "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
+ }
+ }
+ },
+ "websocket-driver": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+ "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+ "dev": true,
+ "requires": {
+ "http-parser-js": ">=0.5.1",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ }
+ },
+ "websocket-extensions": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+ "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
+ },
+ "wildcard": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
+ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
+ "dev": true
+ },
+ "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==",
+ "dev": true
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "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"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^0.5.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"
+ }
+ },
+ "y18n": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
+ "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "dev": true,
+ "requires": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ },
+ "dependencies": {
+ "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
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "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
+ },
+ "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-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ }
+ }
+}
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/package.json b/utilities/cloudharness_utilities/application-templates/webapp/frontend/package.json
new file mode 100644
index 00000000..58a41207
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/package.json
@@ -0,0 +1,58 @@
+{
+ "name": "__APP_NAME__",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "prebuild": "eslint . --color",
+ "build": "webpack --config webpack.config.js",
+ "build-dev": "webpack --config webpack.config.js --env mode=development",
+ "prestart": "eslint . --color --fix",
+ "start": "webpack serve --progress --env DOMAIN=http://localhost:5000 --config webpack.config.dev.js",
+ "start:dev": "webpack serve --progress --env.DOMAIN=https://__APP_NAME__.cloudharness.metacell.us --config webpack.config.dev.js",
+ "start:minikube": "webpack serve --progress --env DOMAIN=http://__APP_NAME__.cloudharness.local --config webpack.config.dev.js"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "axios": "^0.21.1",
+ "react": "^16.12.0",
+ "react-dom": "^16.12.0",
+ "react-router": "^5.0.0",
+ "react-router-dom": "^5.0.0",
+ "use-clipboard-copy": "^0.1.2"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.8.3",
+ "@babel/plugin-proposal-class-properties": "^7.8.3",
+ "@babel/preset-env": "^7.8.3",
+ "@babel/preset-react": "^7.8.3",
+ "awesome-typescript-loader": "^5.2.1",
+ "babel-eslint": "^10.1.0",
+ "babel-loader": "^8.0.6",
+ "babel-plugin-module-resolver": "^4.0.0",
+ "babel-preset-minify": "^0.5.1",
+ "clean-webpack-plugin": "^3.0.0",
+ "compression-webpack-plugin": "^7.1.2",
+ "copy-webpack-plugin": "^6.2.1",
+ "css-loader": "^3.4.2",
+ "eslint": "5.16.0",
+ "eslint-plugin-jest": "^23.8.2",
+ "eslint-plugin-react": "^7.19.0",
+ "eslint-plugin-react-hooks": "^3.0.0",
+ "file-loader": "^5.0.2",
+ "html-loader": "^0.5.5",
+ "html-webpack-plugin": "^4.5.1",
+ "less": "^3.10.3",
+ "less-loader": "^5.0.0",
+ "less-vars-to-js": "^1.3.0",
+ "raw-loader": "^4.0.2",
+ "style-loader": "^1.1.3",
+ "typescript": "^3.9.3",
+ "webpack": "^5.0.0",
+ "webpack-cli": "^4.3.1",
+ "webpack-dev-server": "^3.11.1",
+ "webpack-merge": "^5.0.0"
+ }
+}
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/App.tsx b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/App.tsx
new file mode 100644
index 00000000..931ea6a6
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/App.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import './styles/style.less';
+
+import RestTest from './components/RestTest';
+
+
+const Main = () => (
+ <>
+
+ Sample React application is working!
+
+ See api documentation here
+ >
+);
+
+export default Main;
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/assets/icon.png b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/assets/icon.png
new file mode 100644
index 00000000..1966e6dd
Binary files /dev/null and b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/assets/icon.png differ
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/components/RestTest.tsx b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/components/RestTest.tsx
new file mode 100644
index 00000000..e6efe434
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/components/RestTest.tsx
@@ -0,0 +1,17 @@
+import React, { useState, useEffect } from 'react';
+
+
+import { TestApi } from '../rest/api'
+const test = new TestApi();
+
+const RestTest = () => {
+ const [result, setResult] = useState(null);
+ useEffect(() => {
+ test.ping().then(r => setResult(r));
+ }, []);
+
+
+ return result && Backend answered: { result.data }
+}
+
+export default RestTest;
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/index.ejs b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/index.ejs
new file mode 100644
index 00000000..97d529ad
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/index.ejs
@@ -0,0 +1,10 @@
+
+
+
+
+ __APP_NAME__
+
+
+
+
+
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/index.tsx b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/index.tsx
new file mode 100644
index 00000000..ae31e413
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/index.tsx
@@ -0,0 +1,6 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+import App from './App';
+
+ReactDOM.render(, document.getElementById('root'));
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/styles/style.less b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/styles/style.less
new file mode 100644
index 00000000..b1bece6a
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/styles/style.less
@@ -0,0 +1,4 @@
+body {
+ text-align: center;
+ background-color: '#eeeeee';
+}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/utils/history.js b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/utils/history.js
new file mode 100644
index 00000000..7bef5c97
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/src/utils/history.js
@@ -0,0 +1,2 @@
+import { createBrowserHistory } from "history";
+export default createBrowserHistory();
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/tsconfig.json b/utilities/cloudharness_utilities/application-templates/webapp/frontend/tsconfig.json
new file mode 100755
index 00000000..21ec6c41
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "outDir": "./dist/",
+ "sourceMap": true,
+ "noImplicitAny": false,
+ "module": "commonjs",
+ "target": "es2017",
+ "stripInternal":true,
+ "skipLibCheck": true,
+ "alwaysStrict":false,
+ "forceConsistentCasingInFileNames": true,
+ "noImplicitReturns": false,
+ "strict": false,
+ "noUnusedLocals": false,
+ "jsx": "react",
+ "types": [],
+ "esModuleInterop": true
+ },
+ "exclude": [
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/webpack.config.dev.js b/utilities/cloudharness_utilities/application-templates/webapp/frontend/webpack.config.dev.js
new file mode 100644
index 00000000..ea3e8266
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/webpack.config.dev.js
@@ -0,0 +1,45 @@
+const { merge } = require('webpack-merge');
+const common = require('./webpack.config.js');
+
+var path = require('path');
+
+const PORT = 9000;
+
+
+module.exports = env => {
+
+ const theDomain = env && env.DOMAIN ? env.DOMAIN : 'localhost:5000';
+
+ console.log('Dev server address: ', theDomain);
+
+ const proxyTarget = theDomain;
+ const replaceHost = (uri, appName) => (uri.includes("__APP_NAME__") && uri.replace("__APP_NAME__", appName + '.' + theDomain)) || uri;
+ if (!env.port) {
+ env.devPort = PORT;
+ }
+
+
+ const devServer = {
+ contentBase: path.join(__dirname, 'dist'),
+ compress: true,
+ port: Number(env.devPort),
+ disableHostCheck: true,
+ historyApiFallback: true,
+ proxy: {
+ '/api/': {
+ target: replaceHost( proxyTarget, '__APP_NAME__'),
+ secure: false,
+ changeOrigin: true,
+ }
+ },
+ };
+
+ return merge(
+ common(env),
+ {
+ mode: 'development',
+ devtool: 'source-map',
+ devServer,
+ }
+ )
+};
diff --git a/utilities/cloudharness_utilities/application-templates/webapp/frontend/webpack.config.js b/utilities/cloudharness_utilities/application-templates/webapp/frontend/webpack.config.js
new file mode 100644
index 00000000..b2dca762
--- /dev/null
+++ b/utilities/cloudharness_utilities/application-templates/webapp/frontend/webpack.config.js
@@ -0,0 +1,110 @@
+const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const CompressionPlugin = require('compression-webpack-plugin');
+const { CleanWebpackPlugin } = require('clean-webpack-plugin');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+
+const copyPaths = [
+ { from: path.resolve(__dirname, "src/assets"), to: 'assets' },
+];
+
+module.exports = function webpacking(envVariables) {
+ let env = envVariables;
+ if (!env) {
+ env = {};
+ }
+ if (!env.mode) {
+ env.mode = 'production';
+ }
+
+
+ console.log('####################');
+ console.log('####################');
+ console.log('BUILD bundle with parameters:');
+ console.log( env);
+ console.log('####################');
+ console.log('####################');
+
+ const { mode } = env;
+ const devtool = env.mode === 'source-map';
+
+
+ const output = {
+ path: path.resolve(__dirname, 'dist'),
+ filename: '[name].[contenthash].js'
+ };
+
+ const module = {
+ rules: [
+ {
+ test: /\.(js|jsx)$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader'
+ },
+ {
+ test: /\.ts|tsx?$/,
+ loader: "awesome-typescript-loader"
+ },
+ {
+ test: /\.(css)$/,
+ use: [
+ {
+ loader: "style-loader",
+ },
+ {
+ loader: "css-loader",
+ }],
+ },
+ {
+ test: /\.less$/,
+ use: [
+ {
+ loader: "style-loader",
+ },
+ {
+ loader: "css-loader",
+ },
+ {
+ loader: "less-loader",
+ options: {
+ lessOptions: {
+ strictMath: true,
+ },
+ },
+ },
+ ],
+ },
+ {
+ test: /\.(png|jpg|gif|eot|woff|woff2|svg|ttf)$/,
+ loader: 'file-loader'
+ },
+
+ ]
+ };
+
+ const resolve = {
+ extensions: ['*', '.js', '.json', '.ts', '.tsx', '.jsx'],
+ symlinks: false
+ };
+
+
+
+ const plugins = [
+ new CleanWebpackPlugin(),
+ new CopyWebpackPlugin({ patterns: copyPaths }),
+ new CompressionPlugin(),
+ new HtmlWebpackPlugin({
+ template: 'src/index.ejs',
+ favicon: path.join(__dirname, 'src/assets/icon.png')
+ })
+ ];
+
+ return {
+ mode,
+ devtool,
+ output,
+ module,
+ resolve,
+ plugins
+ };
+};
diff --git a/utilities/cloudharness_utilities/build.py b/utilities/cloudharness_utilities/build.py
index da1fdde9..944230ae 100644
--- a/utilities/cloudharness_utilities/build.py
+++ b/utilities/cloudharness_utilities/build.py
@@ -1,15 +1,17 @@
import os
+import sys
import logging
import tempfile
from docker import from_env as DockerClient
from .utils import find_dockerfiles_paths, app_name_from_path, merge_configuration_directories
-from .constants import NODE_BUILD_IMAGE, APPS_PATH, STATIC_IMAGES_PATH, BASE_IMAGES_PATH
+from .constants import NODE_BUILD_IMAGE, APPS_PATH, STATIC_IMAGES_PATH, BASE_IMAGES_PATH, EXCLUDE_PATHS
+
class Builder:
- def __init__(self, root_paths, include, tag, namespace, domain, registry='', interactive=False,
+ def __init__(self, root_paths, include, tag, namespace, domain, registry='', interactive=False,
exclude=tuple()):
self.included = include or []
self.tag = tag
@@ -43,8 +45,8 @@ def push(self, image_repository):
# filter the images to build
- def should_build_image(self, image_path) -> bool:
- if image_path in self.exclude:
+ def should_build_image(self, image_path, ignore_include=False) -> bool:
+ if any(excluded_path in image_path for excluded_path in (EXCLUDE_PATHS + list(self.exclude))):
return False
if not self.included:
if self.interactive:
@@ -52,7 +54,7 @@ def should_build_image(self, image_path) -> bool:
return answer.upper() != 'N'
return True
- if any(inc in image_path for inc in self.included):
+ if ignore_include or any(f"/{inc}/" in image_path or image_path.endswith(f"/{inc}") for inc in self.included):
return True
logging.info("Skipping build for image %s", image_path)
return False
@@ -62,23 +64,22 @@ def run(self):
logging.info('Start building docker images')
for rpath in self.root_paths:
logging.info('Building from root directory %s', rpath)
- self.find_and_build_under_path(BASE_IMAGES_PATH, rpath, rpath)
- self.find_and_build_under_path(STATIC_IMAGES_PATH, None, rpath)
+ self.find_and_build_under_path(BASE_IMAGES_PATH, rpath, rpath, ignore_include=True)
+ self.find_and_build_under_path(STATIC_IMAGES_PATH, None, rpath, ignore_include=True)
self.find_and_build_under_path(APPS_PATH, None, rpath)
- def find_and_build_under_path(self, base_path, context_path=None, root_path=None):
+ def find_and_build_under_path(self, base_path, context_path=None, root_path=None, ignore_include=False):
abs_base_path = os.path.join(root_path, base_path)
docker_files = (path for path in find_dockerfiles_paths(abs_base_path) if
- self.should_build_image(path))
+ self.should_build_image(path, ignore_include))
for dockerfile_path in docker_files:
dockerfile_rel_path = "" if not context_path else os.path.relpath(dockerfile_path, start=context_path)
# extract image name
image_name = app_name_from_path(os.path.relpath(dockerfile_path, start=abs_base_path))
- if self.should_build_image(os.path.relpath(dockerfile_path, start=abs_base_path)):
- self.build_image(image_name, dockerfile_rel_path,
- context_path=context_path if context_path else dockerfile_path)
+ self.build_image(image_name, dockerfile_rel_path,
+ context_path=context_path if context_path else dockerfile_path)
def build_under_path(self, dpath):
""" Uses docker sdk to build a docker images from path information """
@@ -88,12 +89,12 @@ def build_under_path(self, dpath):
dockerfile_path = dpath['abs_path']
self.build_image(image_name, dockerfile_rel_path,
- context_path=context_path if context_path else dockerfile_path)
-
+ context_path=context_path if context_path else dockerfile_path)
def build_image(self, image_name, dockerfile_rel_path, context_path=None):
- registry = "" if not self.registry else self.registry.strip('/') + '/' # make sure the registry ends with only one single /
+ registry = "" if not self.registry else self.registry.strip(
+ '/') + '/' # make sure the registry ends with only one single /
# build image
image_tag = f'{registry}{image_name}:{self.tag}' if self.tag else image_name
@@ -103,13 +104,22 @@ def build_image(self, image_name, dockerfile_rel_path, context_path=None):
logging.info(f'\n{80 * "#"}\nBuilding {image_tag} \n{80 * "#"}\n')
logging.info("Build args: " + ",".join(key + ':' + value for key, value in buildargs.items()))
- image, response = self.client.images.build(path=context_path,
- tag=image_tag,
- buildargs=buildargs,
- dockerfile=os.path.join(dockerfile_rel_path,
- "Dockerfile") if dockerfile_rel_path else None
- )
+ try:
+ image, response = self.client.images.build(path=context_path,
+ tag=image_tag,
+ buildargs=buildargs,
+ dockerfile=os.path.join(dockerfile_rel_path,
+ "Dockerfile") if dockerfile_rel_path else None
+
+ )
+ except Exception as e:
+ for line in e.build_log:
+ if 'stream' in line and line['stream'] != '\n':
+ logging.info(line['stream'].replace('\n', ' ').replace('\r', ''))
+ logging.error("Build failed with message:\n%s", ",".join(e.args))
+
+ sys.exit(1)
# log stream
for line in response:
if 'stream' in line and line['stream'] != '\n':
@@ -117,8 +127,7 @@ def build_image(self, image_name, dockerfile_rel_path, context_path=None):
if self.registry:
self.push(image_tag)
-
- def log_merging_operation(self, dpaths:[dict]) -> None:
+ def log_merging_operation(self, dpaths: [dict]) -> None:
logging_message = f"\n\nFound multiple dockerfiles for the next image ({dpaths[0]['name']}):\n\n"
for dpath in dpaths:
logging_message += f"{dpath['abs_path']}\n"
diff --git a/utilities/cloudharness_utilities/codefresh.py b/utilities/cloudharness_utilities/codefresh.py
index 5d0b29eb..4111a70a 100644
--- a/utilities/cloudharness_utilities/codefresh.py
+++ b/utilities/cloudharness_utilities/codefresh.py
@@ -1,10 +1,12 @@
import os
import oyaml as yaml
+import yaml.representer
+
import logging
-from .constants import HERE, BUILD_STEP_BASE, BUILD_STEP_STATIC, BUILD_STEP_PARALLEL, BUILD_STEP_INSTALL, \
- CODEFRESH_PATH, CODEFRESH_BUILD_PATH, \
- CODEFRESH_TEMPLATE_PATH, APPS_PATH, STATIC_IMAGES_PATH, BASE_IMAGES_PATH, DEPLOYMENT_PATH
+from .constants import HERE, CF_BUILD_STEP_BASE, CF_BUILD_STEP_STATIC, CF_BUILD_STEP_PARALLEL, CF_STEP_PUBLISH, \
+ CODEFRESH_PATH, CF_BUILD_PATH, CF_TEMPLATE_PUBLISH_PATH, DEPLOYMENT_CONFIGURATION_PATH, \
+ CF_TEMPLATE_PATH, APPS_PATH, STATIC_IMAGES_PATH, BASE_IMAGES_PATH, DEPLOYMENT_PATH, EXCLUDE_PATHS
from .helm import collect_helm_values
from .utils import find_dockerfiles_paths, app_name_from_path, \
get_image_name, get_template, merge_to_yaml_file, dict_merge
@@ -14,7 +16,20 @@
CLOUD_HARNESS_PATH = "cloud-harness"
-def create_codefresh_deployment_scripts(root_paths, codefresh_path=CODEFRESH_PATH, include=()):
+# Codefresh variables may need quotes: adjust yaml dump accordingly
+def literal_presenter(dumper, data):
+ if isinstance(data, str) and "\n" in data:
+ return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
+ if isinstance(data, str) and data.startswith('${{'):
+ return dumper.represent_scalar('tag:yaml.org,2002:str', data, style="'")
+ return dumper.represent_scalar('tag:yaml.org,2002:str', data)
+
+
+yaml.add_representer(str, literal_presenter)
+
+
+def create_codefresh_deployment_scripts(root_paths, out_filename=CODEFRESH_PATH, include=(), exclude=(),
+ template_name=CF_TEMPLATE_PATH):
"""
Entry point to create deployment scripts for codefresh: codefresh.yaml and helm chart
"""
@@ -22,46 +37,76 @@ def create_codefresh_deployment_scripts(root_paths, codefresh_path=CODEFRESH_PAT
if include:
logging.info('Including the following subpaths to the build: %s.', ', '.join(include))
- codefresh = get_template(os.path.join(HERE, CODEFRESH_TEMPLATE_PATH))
+ if exclude:
+ logging.info('Excluding the following subpaths to the build: %s.', ', '.join(exclude))
+
+ codefresh = get_template(os.path.join(HERE, template_name), True)
- codefresh['steps'][BUILD_STEP_BASE]['steps'] = {}
- codefresh['steps'][BUILD_STEP_STATIC]['steps'] = {}
- codefresh['steps'][BUILD_STEP_PARALLEL]['steps'] = {}
+ if not codefresh:
+ if template_name != CF_TEMPLATE_PATH:
+ logging.warning("Template file %s not found", template_name)
+ if os.path.exists(os.path.join(HERE, CF_TEMPLATE_PATH)):
+ logging.info("Loading legacy template %s", CF_TEMPLATE_PATH)
+ codefresh = get_template(os.path.join(HERE, CF_TEMPLATE_PATH), True)
+ return
+
+ if CF_BUILD_STEP_BASE in codefresh['steps']:
+ codefresh['steps'][CF_BUILD_STEP_BASE]['steps'] = {}
+ codefresh['steps'][CF_BUILD_STEP_STATIC]['steps'] = {}
+ codefresh['steps'][CF_BUILD_STEP_PARALLEL]['steps'] = {}
+ if CF_STEP_PUBLISH in codefresh['steps']:
+ codefresh['steps'][CF_STEP_PUBLISH]['steps'] = {}
for root_path in root_paths:
- template_path = os.path.join(root_path, CODEFRESH_TEMPLATE_PATH)
+ template_path = os.path.join(root_path, DEPLOYMENT_CONFIGURATION_PATH, template_name)
if os.path.exists(template_path):
- tpl = get_template(template_path)
- del tpl['steps'][BUILD_STEP_BASE]
- del tpl['steps'][BUILD_STEP_STATIC]
- del tpl['steps'][BUILD_STEP_PARALLEL]
+ tpl = get_template(template_path, True)
+ if CF_BUILD_STEP_BASE in codefresh['steps']:
+ del tpl['steps'][CF_BUILD_STEP_BASE]
+ if CF_BUILD_STEP_STATIC in codefresh['steps']:
+ del tpl['steps'][CF_BUILD_STEP_STATIC]
+ if CF_BUILD_STEP_PARALLEL in codefresh['steps']:
+ del tpl['steps'][CF_BUILD_STEP_PARALLEL]
+ if CF_STEP_PUBLISH in codefresh['steps']:
+ del tpl['steps'][CF_STEP_PUBLISH]
codefresh = dict_merge(codefresh, tpl)
- def codefresh_build_step_from_base_path(base_path, build_step, fixed_context=None):
+ def codefresh_build_step_from_base_path(base_path, build_step, fixed_context=None, include=include):
abs_base_path = os.path.join(os.getcwd(), base_path)
for dockerfile_path in find_dockerfiles_paths(abs_base_path):
app_relative_to_root = os.path.relpath(dockerfile_path, '.')
app_relative_to_base = os.path.relpath(dockerfile_path, abs_base_path)
app_name = app_name_from_path(app_relative_to_base)
- if include and not any(inc in dockerfile_path for inc in include):
+ if include and not any(
+ f"/{inc}/" in dockerfile_path or dockerfile_path.endswith(f"/{inc}") for inc in include):
continue
- build = codefresh_app_build_spec(
- app_name=app_name,
- app_context_path=os.path.relpath(fixed_context, '.') if fixed_context else app_relative_to_root,
- dockerfile_path=os.path.join(os.path.relpath(dockerfile_path, fixed_context) if fixed_context else '',
- "Dockerfile"))
- codefresh['steps'][build_step]['steps'][app_name] = build
-
- codefresh_build_step_from_base_path(os.path.join(root_path, BASE_IMAGES_PATH), BUILD_STEP_BASE,
- fixed_context=root_path)
- codefresh_build_step_from_base_path(os.path.join(root_path, STATIC_IMAGES_PATH), BUILD_STEP_STATIC)
- codefresh_build_step_from_base_path(os.path.join(root_path, APPS_PATH), BUILD_STEP_PARALLEL)
-
+ if any(inc in dockerfile_path for inc in (list(exclude) + EXCLUDE_PATHS)):
+ continue
+ build = None
+ if CF_BUILD_STEP_BASE in codefresh['steps']:
+ build = codefresh_app_build_spec(
+ app_name=app_name,
+ app_context_path=os.path.relpath(fixed_context, '.') if fixed_context else app_relative_to_root,
+ dockerfile_path=os.path.join(
+ os.path.relpath(dockerfile_path, fixed_context) if fixed_context else '',
+ "Dockerfile"))
+ codefresh['steps'][build_step]['steps'][app_name] = build
+ if CF_STEP_PUBLISH in codefresh['steps']:
+ codefresh['steps'][CF_STEP_PUBLISH]['steps']['publish_' + app_name] = codefresh_app_publish_spec(
+ app_name=app_name, build_tag=build and build['tag'])
+
+ codefresh_build_step_from_base_path(os.path.join(root_path, BASE_IMAGES_PATH), CF_BUILD_STEP_BASE,
+ fixed_context=root_path, include=None)
+ codefresh_build_step_from_base_path(os.path.join(root_path, STATIC_IMAGES_PATH), CF_BUILD_STEP_STATIC,
+ include=None)
+ codefresh_build_step_from_base_path(os.path.join(root_path, APPS_PATH), CF_BUILD_STEP_PARALLEL)
+
+ # Remove useless steps
codefresh['steps'] = {k: step for k, step in codefresh['steps'].items() if
'type' not in step or step['type'] != 'parallel' or (
step['steps'] if 'steps' in step else [])}
- codefresh_abs_path = os.path.join(os.getcwd(), DEPLOYMENT_PATH, codefresh_path)
+ codefresh_abs_path = os.path.join(os.getcwd(), DEPLOYMENT_PATH, out_filename)
codefresh_dir = os.path.dirname(codefresh_abs_path)
if not os.path.exists(codefresh_dir):
os.makedirs(codefresh_dir)
@@ -69,24 +114,45 @@ def codefresh_build_step_from_base_path(base_path, build_step, fixed_context=Non
yaml.dump(codefresh, f)
-def codefresh_build_spec(**kwargs):
+def codefresh_template_spec(template_path, **kwargs):
"""
Create Codefresh build specification
:return:
"""
- build = get_template(CODEFRESH_BUILD_PATH)
+ build = get_template(template_path, True)
build.update(kwargs)
return build
+def codefresh_app_publish_spec(app_name, build_tag):
+ title = app_name.capitalize().replace('-', ' ').replace('/', ' ').replace('.', ' ').strip()
+
+ step_spec = codefresh_template_spec(
+ template_path=CF_TEMPLATE_PUBLISH_PATH,
+ candidate="${{REGISTRY}}/%s:%s" % (get_image_name(app_name), build_tag or '${{DEPLOYMENT_TAG}}'),
+ title=title,
+ )
+ if not build_tag:
+ # if not build tag we are reusing old images and deploying on a production env
+ step_spec['tags'].append('latest')
+ return step_spec
+
+
+def app_specific_tag_variable(app_name):
+ return "${{ %s }}_${{DEPLOYMENT_PUBLISH_TAG}}" % app_name.replace('-', '_').upper()
+
+
def codefresh_app_build_spec(app_name, app_context_path, dockerfile_path="Dockerfile"):
logging.info('Generating build script for ' + app_name)
title = app_name.capitalize().replace('-', ' ').replace('/', ' ').replace('.', ' ').strip()
- build = codefresh_build_spec(image_name=get_image_name(app_name), title=title,
- working_directory='./' + app_context_path,
- dockerfile=dockerfile_path)
+ build = codefresh_template_spec(
+ template_path=CF_BUILD_PATH,
+ image_name=get_image_name(app_name),
+ title=title,
+ working_directory='./' + app_context_path,
+ dockerfile=dockerfile_path)
specific_build_template_path = os.path.join(app_context_path, 'build.yaml')
if os.path.exists(specific_build_template_path):
diff --git a/utilities/cloudharness_utilities/constants.py b/utilities/cloudharness_utilities/constants.py
index 7b29ba8c..cc274879 100644
--- a/utilities/cloudharness_utilities/constants.py
+++ b/utilities/cloudharness_utilities/constants.py
@@ -5,6 +5,8 @@
HERE = os.path.dirname(os.path.realpath(__file__)).replace(os.path.sep, '/')
ROOT = os.path.dirname(HERE)
+APPLICATION_TEMPLATE_PATH = 'application-templates'
+
HELM_PATH = "helm"
HELM_CHART_PATH = HELM_PATH
@@ -15,23 +17,23 @@
APPS_PATH = 'applications'
DEPLOYMENT_PATH = 'deployment'
CODEFRESH_PATH = 'codefresh/codefresh.yaml'
+EXCLUDE_PATHS = ['node_modules', '.git', '.tox']
DEPLOYMENT_CONFIGURATION_PATH = 'deployment-configuration'
-CODEFRESH_BUILD_PATH = f'{DEPLOYMENT_CONFIGURATION_PATH}/codefresh-build-template.yaml'
-CODEFRESH_TEMPLATE_PATH = f'{DEPLOYMENT_CONFIGURATION_PATH}/codefresh-template.yaml'
-CODEFRESH_REGISTRY = "r.cfcr.io/tarelli"
+CF_BUILD_PATH = f'{DEPLOYMENT_CONFIGURATION_PATH}/codefresh-build-template.yaml'
+CF_TEMPLATE_PATH = f'{DEPLOYMENT_CONFIGURATION_PATH}/codefresh-template.yaml'
+CF_TEMPLATE_PUBLISH_PATH = f'{DEPLOYMENT_CONFIGURATION_PATH}/codefresh-publish-template.yaml'
VALUES_MANUAL_PATH = 'values.yaml'
VALUE_TEMPLATE_PATH = f'{DEPLOYMENT_CONFIGURATION_PATH}/value-template.yaml'
-CH_BASE_IMAGES = {'cloudharness-base': 'python:3.7-alpine', 'cloudharness-base-debian': 'python:3'}
-
+CH_BASE_IMAGES = {'cloudharness-base': 'python:3.7-alpine', 'cloudharness-base-debian': 'python:3.7'}
-BUILD_STEP_BASE = 'build_base_images'
-BUILD_STEP_STATIC = 'build_static_images'
-BUILD_STEP_PARALLEL = 'build_application_images'
-BUILD_STEP_INSTALL = 'deployment'
+CF_BUILD_STEP_BASE = 'build_base_images'
+CF_BUILD_STEP_STATIC = 'build_static_images'
+CF_BUILD_STEP_PARALLEL = 'build_application_images'
+CF_STEP_INSTALL = 'deployment'
+CF_STEP_PUBLISH = 'publish'
BUILD_FILENAMES = ('node_modules',)
-
diff --git a/utilities/cloudharness_utilities/deployment-configuration/README.md b/utilities/cloudharness_utilities/deployment-configuration/README.md
index ff3d1c51..24fd58e8 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/README.md
+++ b/utilities/cloudharness_utilities/deployment-configuration/README.md
@@ -1,8 +1,38 @@
# Default deployment templates
+
Templates used to personalize the automatic infrastructure definition.
-Those files are used by the script `insfrastructure-generate.py`
-- `values-template.yaml`: base for `helm/values.yaml`. Modify this file to add values related to new infrastructure elements not defined as a CloudHarness application (e.g. a new database)
-- `value-template.yaml`: base for cloudharness application configuration inside `values.yaml`. Prefer adding a custom `values.yaml` to your application over changing this file.
-- `codefresh-template.yaml`: base for `codefresh/codefresh.yaml`. Modify this file if you want to change the build steps inside codefresh
+Those files are used by the script `harness-deployment` script.
+
+- `values-template.yaml`: base for `helm/values.yaml`. Modify this file to add values related to new infrastructure
+ elements not defined as a CloudHarness application (e.g. a new database)
+- `value-template.yaml`: base for cloudharness application configuration inside `values.yaml`. Prefer adding a
+ custom `values.yaml` to your application over changing this file.
+- `codefresh-template-[dev|prod].yaml`: base for `codefresh/codefresh-[dev|prod].yaml`. Modify this file if you want to
+ change the build steps inside codefresh
- `codefresh-build-template.yaml`: base for a single build entry in `codefresh.yaml`
+- `codefresh-publish-template.yaml`: base for a single publish (image tagging) entry in `codefresh.yaml`
+
+## Generating HELM Chart documentation
+
+We use [helm-docs](https://github.com/norwoodj/helm-docs) to generate a markdown file containing a table of all
+available parameters.
+
+Please follow their [installation instruction](https://github.com/norwoodj/helm-docs#installation), either use `brew` on MacOS or
+install from source. If you install from source, `go` is required.
+
+`helm-docs` is able to parse yaml comments, but only if they are prefixed with `--`:
+
+```yaml
+registry:
+ # -- The docker registry.
+ name: "localhost:5000"
+```
+
+To generate HELM chart documentation run:
+
+````bash
+helm-docs --dry-run > docs.md
+````
+
+As a final step, update the content in the respective Cloud Harness wiki page.
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/codefresh-build-template.yaml b/utilities/cloudharness_utilities/deployment-configuration/codefresh-build-template.yaml
index e0af336c..d5b04b94 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/codefresh-build-template.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/codefresh-build-template.yaml
@@ -1,9 +1,10 @@
type: build
stage: build
-tag: '${{CF_REVISION}}'
+tag: '${{CF_BUILD_ID}}'
dockerfile: Dockerfile
+registry: '${{CODEFRESH_REGISTRY}}'
build_arguments:
- - REGISTRY=${{REGISTRY}}
- - TAG=${{CF_REVISION}}
+ - REGISTRY=${{REGISTRY}}/
+ - TAG=${{CF_BUILD_ID}}
- NAMESPACE=${{NAMESPACE}}
- DOMAIN=${{DOMAIN}}
diff --git a/utilities/cloudharness_utilities/deployment-configuration/codefresh-publish-template.yaml b/utilities/cloudharness_utilities/deployment-configuration/codefresh-publish-template.yaml
new file mode 100644
index 00000000..106e7a5a
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/codefresh-publish-template.yaml
@@ -0,0 +1,7 @@
+stage: 'publish'
+type: push
+title: REPLACE_ME
+candidate: REPLACE_ME
+tags:
+ - ${{DEPLOYMENT_PUBLISH_TAG}}
+registry: ${{REGISTRY_PUBLISH_URL}}
diff --git a/utilities/cloudharness_utilities/deployment-configuration/codefresh-template.yaml b/utilities/cloudharness_utilities/deployment-configuration/codefresh-template-dev.yaml
similarity index 60%
rename from utilities/cloudharness_utilities/deployment-configuration/codefresh-template.yaml
rename to utilities/cloudharness_utilities/deployment-configuration/codefresh-template-dev.yaml
index e0b96c47..4aada583 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/codefresh-template.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/codefresh-template-dev.yaml
@@ -3,6 +3,7 @@ stages:
- prepare
- build
- deploy
+ - publish
steps:
main_clone:
title: Clone main repository
@@ -15,6 +16,14 @@ steps:
title: Post main clone
type: parallel
stage: prepare
+ steps:
+ - title: Cloning cloud-harness repository...
+ type: git-clone
+ stage: prepare
+ repo: 'https://github.com/MetaCell/cloud-harness.git'
+ revision: '${{CLOUDHARNESS_BRANCH}}'
+ working_directory: .
+ git: github
prepare_deployment:
title: "Prepare helm chart"
image: python:3.7
@@ -22,14 +31,14 @@ steps:
working_directory: .
commands:
- pip install cloud-harness/utilities
- - harness-deployment . cloud-harness -m build -t ${{CF_REVISION}} -d ${{DOMAIN}} -r ${{REGISTRY}} -rs ${{REGISTRY_SECRET}}
+ - harness-deployment cloud-harness . -m build -t ${{CF_BUILD_ID}} -d ${{DOMAIN}} -r ${{REGISTRY}} -rs ${{REGISTRY_SECRET}} -e dev
prepare_deployment_view:
commands:
- - 'helm template ./deployment/helm --debug -n ${{NAME}}'
+ - 'helm template ./deployment/helm --debug -n ${{NAMESPACE}}'
environment:
- ACTION=auth
- - KUBE_CONTEXT=${{NAME}}
- image: codefresh/cfstep-helm:2.16.1
+ - KUBE_CONTEXT=${{NAMESPACE}}
+ image: codefresh/cfstep-helm:3.4.1
stage: prepare
title: 'View helm chart'
build_base_images:
@@ -51,15 +60,20 @@ steps:
REPLACE_ME
deployment:
stage: deploy
- image: codefresh/cfstep-helm:3.0.3
+ image: codefresh/cfstep-helm:3.4.1
title: Installing chart
environment:
- CHART_REF=./deployment/helm
- RELEASE_NAME=${{NAMESPACE}}
- KUBE_CONTEXT=${{CLUSTER_NAME}}
- NAMESPACE=${{NAMESPACE}}
- - CHART_VERSION=0.0.1
+ - CHART_VERSION=${{DEPLOYMENT_PUBLISH_TAG}}
- HELM_REPO_USE_HTTP=false
- HELM_REPO_CONTEXT_PATH=
- - TIMEOUT=600
- - VALUESFILE_values=./deployment/helm/values.yaml
\ No newline at end of file
+ - TIMEOUT=600s
+ - VALUESFILE_values=./deployment/helm/values.yaml
+ publish:
+ type: parallel
+ stage: publish
+ steps:
+ REPLACE_ME
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/codefresh-template-prod.yaml b/utilities/cloudharness_utilities/deployment-configuration/codefresh-template-prod.yaml
new file mode 100644
index 00000000..175ab6ad
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/codefresh-template-prod.yaml
@@ -0,0 +1,90 @@
+version: '1.0'
+stages:
+ - prepare
+ - deploy
+ - publish
+steps:
+ main_clone:
+ title: Clone main repository
+ type: git-clone
+ stage: prepare
+ repo: '${{CF_REPO_OWNER}}/${{CF_REPO_NAME}}'
+ revision: '${{CF_BRANCH}}'
+ git: github
+ post_main_clone:
+ title: Post main clone
+ type: parallel
+ stage: prepare
+ steps:
+ - title: Cloning cloud-harness repository...
+ type: git-clone
+ stage: prepare
+ repo: 'https://github.com/MetaCell/cloud-harness.git'
+ revision: '${{CLOUDHARNESS_BRANCH}}'
+ working_directory: .
+ git: github
+ prepare_deployment:
+ title: "Prepare helm chart"
+ image: python:3.7
+ stage: prepare
+ working_directory: .
+ commands:
+ - pip install cloud-harness/utilities
+ - harness-deployment . cloud-harness -m build -t ${{DEPLOYMENT_TAG}} -d ${{DOMAIN}} -r ${{REGISTRY}} -rs ${{REGISTRY_SECRET}} -e prod
+ prepare_deployment_view:
+ commands:
+ - 'helm template ./deployment/helm --debug -n ${{NAMESPACE}}'
+ environment:
+ - ACTION=auth
+ - KUBE_CONTEXT=${{NAMESPACE}}
+ image: codefresh/cfstep-helm:3.4.1
+ stage: prepare
+ title: 'View helm chart'
+ deployment:
+ stage: deploy
+ image: codefresh/cfstep-helm:3.4.1
+ title: Installing chart
+ environment:
+ - CHART_REF=./deployment/helm
+ - RELEASE_NAME=${{NAMESPACE}}
+ - KUBE_CONTEXT=${{CLUSTER_NAME}}
+ - NAMESPACE=${{NAMESPACE}}
+ - CHART_VERSION=${{DEPLOYMENT_TAG}}
+ - HELM_REPO_USE_HTTP=false
+ - HELM_REPO_CONTEXT_PATH=
+ - TIMEOUT=600s
+ - VALUESFILE_values=./deployment/helm/values.yaml
+ approval:
+ type: pending-approval
+ stage: publish
+ title: Approve
+ description: Approve publication
+ timeout:
+ duration: 168
+ finalState: approved
+ publish:
+ type: parallel
+ stage: publish
+ steps:
+ REPLACE_ME
+ when:
+ condition:
+ all:
+ whenVarExists: 'includes("${{DEPLOYMENT_PUBLISH_TAG}}", "{{DEPLOYMENT_PUBLISH_TAG}}") == false'
+ git-tag:
+ title: Performing git tagging
+ stage: publish
+ image: alpine/git:latest
+ commands:
+ - git tag ${{DEPLOYMENT_PUBLISH_TAG}}
+ - ORIGIN=$(git remote get-url origin)
+ - PROTOCOL=https://
+ - REPLACEMENT=${PROTOCOL}${{REPO_TOKEN}}@
+ - git remote set-url origin ${ORIGIN/$PROTOCOL/$REPLACEMENT}
+ - git push origin --tags
+ when:
+ condition:
+ all:
+ whenVarExists: 'includes("${{DEPLOYMENT_PUBLISH_TAG}}", "{{DEPLOYMENT_PUBLISH_TAG}}") == false'
+ whenVarExists2: 'includes("${{REPO_TOKEN}}", "{{REPO_TOKEN}}") == false'
+
diff --git a/utilities/cloudharness_utilities/deployment-configuration/docs.md b/utilities/cloudharness_utilities/deployment-configuration/docs.md
new file mode 100644
index 00000000..493f94bc
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/docs.md
@@ -0,0 +1,49 @@
+# cloudharness
+
+![Version: 0.0.1](https://img.shields.io/badge/Version-0.0.1-informational?style=flat-square) ![AppVersion: 0.0.1](https://img.shields.io/badge/AppVersion-0.0.1-informational?style=flat-square)
+
+CloudHarness Helm Chart
+
+## Maintainers
+
+| Name | Email | Url |
+| ---- | ------ | --- |
+| Filippo Ledda | filippo@metacell.us | |
+| Zoran Sinnema | zoran@metacell.us | |
+
+## Values
+
+| Key | Type | Default | Description |
+|-----|------|---------|-------------|
+| apps | string | Will be filled automatically. | List of applications. |
+| backup.active | bool | `true` | Flag to enable/disable backups. |
+| backup.dir | string | `"/backups"` | Target directory of backups, the mount point of the persistent volume. |
+| backup.keep_days | string | `"7"` | Number of days to keep backups. |
+| backup.keep_months | string | `"6"` | Number of months to keep backups. |
+| backup.keep_weeks | string | `"4"` | Number of weeks to keep backups. |
+| backup.resources.limits.cpu | string | `"50m"` | K8s cpu resource definition. |
+| backup.resources.limits.memory | string | `"64Mi"` | K8s memory resource definition. |
+| backup.resources.requests.cpu | string | `"25m"` | K8s cpu resource definition. |
+| backup.resources.requests.memory | string | `"32Mi"` | K8s memory resource definition. |
+| backup.schedule | string | `"@daily"` | Schedule as cronjob expression. |
+| backup.suffix | string | `".gz"` | The file suffix added to backup files. |
+| domain | string | `"${{DOMAIN}}"` | The root domain. |
+| env[0] | object | `{"name":"CH_VERSION","value":"0.0.1"}` | Cloud Harness version |
+| env[1] | object | `{"name":"CH_CHART_VERSION","value":"0.0.1"}` | Cloud harness chart version |
+| fullnameOverride | string | `""` | ? |
+| ingress.enabled | bool | `true` | Flag to enable/disalbe ingress controller. |
+| ingress.letsencrypt.email | string | `"filippo@metacell.us"` | Email for letsencrypt. |
+| ingress.name | string | `"cloudharness-ingress"` | K8s Name of ingress. |
+| ingress.ssl_redirect | bool | `true` | Enables/disables SSL redirect. |
+| local | bool | `false` | If set to local, TLS won't be configured. |
+| mainapp | string | `"accounts"` | Name of mainapp, routes incoming traffic of root `domaim` to this app. |
+| nameOverride | string | `""` | ? |
+| namespace | string | `"ch"` | The K8s namespace. |
+| privenv[0] | object | `{"name":"CH_SECRET","value":"In God we trust; all others must bring data. ― W. Edwards Deming"}` | Defines a secret as private environment variable that is injected in containers. |
+| registry.name | string | `"localhost:5000"` | The docker registry. |
+| registry.secret | string | `nil` | Optional secret used for pulling from docker registry. |
+| secured_gatekeepers | bool | `true` | Enables/disables Gatekeeper. |
+| tag | string | `"latest"` | Docker tag used to pull images. |
+
+----------------------------------------------
+Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0)
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/Chart.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/Chart.yaml
index 20d334a2..f294c3e7 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/Chart.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/Chart.yaml
@@ -4,9 +4,7 @@ description: CloudHarness Helm Chart
name: cloudharness
version: 0.0.1
maintainers:
- - name: Facundo Rodriguez
- email: facundo@metacell.us
- name: Filippo Ledda
email: filippo@metacell.us
- name: Zoran Sinnema
- email: zoran@metacell.us
\ No newline at end of file
+ email: zoran@metacell.us
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/files/db-mongo-backup.sh b/utilities/cloudharness_utilities/deployment-configuration/helm/files/db-mongo-backup.sh
new file mode 100644
index 00000000..30f7067b
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/files/db-mongo-backup.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+set -e
+set -u
+
+KEEP_DAYS=${BACKUP_KEEP_DAYS}
+KEEP_WEEKS=`expr $(((${BACKUP_KEEP_WEEKS} * 7) + 1))`
+KEEP_MONTHS=`expr $(((${BACKUP_KEEP_MONTHS} * 31) + 1))`
+
+mkdir -p "${BACKUP_DIR}/daily/" "${BACKUP_DIR}/weekly/" "${BACKUP_DIR}/monthly/"
+
+# Clean old files
+echo "Cleaning backups older than ${KEEP_DAYS} ..."
+find "${BACKUP_DIR}/daily" -maxdepth 1 -mtime +${KEEP_DAYS} -name "*${BACKUP_SUFFIX}" -print -delete
+find "${BACKUP_DIR}/weekly" -maxdepth 1 -mtime +${KEEP_WEEKS} -name "*${BACKUP_SUFFIX}" -print -delete
+find "${BACKUP_DIR}/monthly" -maxdepth 1 -mtime +${KEEP_MONTHS} -name "*${BACKUP_SUFFIX}" -print -delete
+
+DFILE="${BACKUP_DIR}/daily/`date +%Y-%m-%d-%H%M%S`${BACKUP_SUFFIX}"
+WFILE="${BACKUP_DIR}/weekly/`date +%G-%V`${BACKUP_SUFFIX}"
+MFILE="${BACKUP_DIR}/monthly/`date +%Y-%m`${BACKUP_SUFFIX}"
+
+# Dump mongo database
+/usr/bin/mongodump -h $DB_HOST -u $DB_USER -p $DB_PASS --archive=$DFILE --gzip
+
+# Use hardlink instead of copy to save space
+if [ -d "${DFILE}" ]; then
+ WFILENEW="${WFILE}-new"
+ MFILENEW="${MFILE}-new"
+ rm -rf "${WFILENEW}" "${MFILENEW}"
+ mkdir "${WFILENEW}" "${MFILENEW}"
+ ln -f "${DFILE}/"* "${WFILENEW}/"
+ ln -f "${DFILE}/"* "${MFILENEW}/"
+ rm -rf "${WFILE}" "${MFILE}"
+ mv -v "${WFILENEW}" "${WFILE}"
+ mv -v "${MFILENEW}" "${MFILE}"
+else
+ ln -vf "${DFILE}" "${WFILE}"
+ ln -vf "${DFILE}" "${MFILE}"
+fi
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-mongo-backup.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-mongo-backup.yaml
new file mode 100644
index 00000000..e357c7a8
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-mongo-backup.yaml
@@ -0,0 +1,64 @@
+{{ define "deploy_utils.database.mongo.backup"}}
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+ name: "{{ .app.harness.database.name }}-backup"
+spec:
+ schedule: {{ .root.Values.backup.schedule | quote }}
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ affinity:
+ podAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchExpressions:
+ - key: service
+ operator: In
+ values:
+ - db
+ topologyKey: kubernetes.io/hostname
+ containers:
+ - name: "{{ .app.harness.database.name }}-backup"
+ image: {{ .app.harness.database.mongo.image }}
+ imagePullPolicy: IfNotPresent
+ command: ["/bin/bash"]
+ args:
+ - -c
+ - | {{ range .root.Files.Lines "files/db-mongo-backup.sh" }}
+ {{ . }}
+ {{ end }}
+ env:
+ - name: DB_USER
+ value: {{ .app.harness.database.user }}
+ - name: DB_PASS
+ value: {{ .app.harness.database.pass }}
+ - name: DB_HOST
+ value: {{ .app.harness.database.name }}
+ - name: BACKUP_KEEP_DAYS
+ value: {{ .root.Values.backup.keep_days | quote }}
+ - name: BACKUP_KEEP_WEEKS
+ value: {{ .root.Values.backup.keep_weeks | quote }}
+ - name: BACKUP_KEEP_MONTHS
+ value: {{ .root.Values.backup.keep_months | quote }}
+ - name: BACKUP_SUFFIX
+ value: {{ .root.Values.backup.suffix | quote }}
+ - name: BACKUP_DIR
+ value: {{ (printf "%s/mongo/%s" .root.Values.backup.dir .app.harness.database.name ) | quote }}
+ volumeMounts:
+ - name: "db-backup"
+ mountPath: /backups
+ resources:
+ requests:
+ memory: {{ .root.Values.backup.resources.requests.memory | default "32Mi" }}
+ cpu: {{ .root.Values.backup.resources.requests.cpu | default "25Mi" }}
+ limits:
+ memory: {{ .root.Values.backup.resources.limits.memory | default "64Mi" }}
+ cpu: {{ .root.Values.backup.resources.limits.cpu | default "50mi" }}
+ restartPolicy: OnFailure
+ volumes:
+ - name: "db-backup"
+ persistentVolumeClaim:
+ claimName: "db-backup"
+{{ end }}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-mongo.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-mongo.yaml
new file mode 100644
index 00000000..e27856c4
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-mongo.yaml
@@ -0,0 +1,26 @@
+{{- define "deploy_utils.database.mongo" }}
+ image: {{ .app.harness.database.mongo.image }}
+ env:
+ - name: MONGO_INITDB_ROOT_USERNAME
+ value: {{ .app.harness.database.user | quote }}
+ - name: MONGO_INITDB_ROOT_PASSWORD
+ value: {{ .app.harness.database.pass | quote }}
+ livenessProbe:
+ exec:
+ command:
+ - mongo
+ - --eval
+ - "db.adminCommand('ping')"
+ initialDelaySeconds: 30
+ timeoutSeconds: 5
+ failureThreshold: 6
+ readinessProbe:
+ exec:
+ command:
+ - mongo
+ - --eval
+ - "db.adminCommand('ping')"
+ initialDelaySeconds: 5
+ timeoutSeconds: 5
+ failureThreshold: 6
+{{- end }}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-neo4j-backup.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-neo4j-backup.yaml
new file mode 100644
index 00000000..f84626ac
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-neo4j-backup.yaml
@@ -0,0 +1,2 @@
+{{- define "deploy_utils.database.neo4j.backup" }}
+{{- end }}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-neo4j.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-neo4j.yaml
new file mode 100644
index 00000000..1116bbb1
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-neo4j.yaml
@@ -0,0 +1,20 @@
+{{- define "deploy_utils.database.neo4j" }}
+ image: {{ .app.harness.database.neo4j.image }}
+ env:
+ - name: NEO4J_dbms_directories_data
+ value: /data/db/data
+ - name: NEO4J_dbms_directories_logs
+ value: /data/db/logs
+ - name: NEO4J_dbms_directories_metrics
+ value: /data/db/metrics
+ - name: NEO4J_dbms_memory_size
+ value: {{ .app.harness.database.neo4j.memory.size }}
+ - name: NEO4J_dbms_memory_pagecache_size
+ value: {{ .app.harness.database.neo4j.memory.pagecache.size }}
+ - name: NEO4J_dbms_memory_heap_initial__size
+ value: {{ .app.harness.database.neo4j.memory.heap.initial }}
+ - name: NEO4J_dbms_memory_heap_max__size
+ value: {{ .app.harness.database.neo4j.memory.heap.max }}
+ - name: NEO4J_dbms_security_auth__enabled
+ value: {{ .app.harness.database.neo4j.dbms_security_auth_enabled | quote }}
+{{- end }}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-postgres-backup.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-postgres-backup.yaml
new file mode 100644
index 00000000..12cc3816
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-postgres-backup.yaml
@@ -0,0 +1,58 @@
+{{ define "deploy_utils.database.postgres.backup"}}
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+ name: "{{ .app.harness.database.name }}-backup"
+spec:
+ schedule: {{ .root.Values.backup.schedule | quote }}
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ securityContext:
+ runAsUser: 999
+ runAsGroup: 999
+ containers:
+ - name: "{{ .app.harness.database.name }}-backup"
+ imagePullPolicy: IfNotPresent
+ image: prodrigestivill/postgres-backup-local
+ command: ["/bin/bash"]
+ args: ["-c" , "./backup.sh"]
+ env:
+ - name: POSTGRES_HOST
+ value: {{ .app.harness.database.name | quote }}
+ - name: POSTGRES_DB
+ value: {{ (index .app.harness.database .app.harness.database.type).initialdb | quote }}
+ - name: POSTGRES_USER
+ value: {{ .app.harness.database.user | quote }}
+ - name: POSTGRES_PASSWORD
+ value: {{ .app.harness.database.pass | quote }}
+ - name: SCHEDULE
+ value: {{ .root.Values.backup.schedule | quote }}
+ - name: BACKUP_KEEP_DAYS
+ value: {{ .root.Values.backup.keep_days | quote }}
+ - name: BACKUP_KEEP_WEEKS
+ value: {{ .root.Values.backup.keep_weeks |quote }}
+ - name: BACKUP_KEEP_MONTHS
+ value: {{ .root.Values.backup.keep_months | quote }}
+ - name: BACKUP_SUFFIX
+ value: {{ .root.Values.backup.suffix | quote }}
+ - name: BACKUP_DIR
+ value: {{ (printf "%s/postgres/%s" .root.Values.backup.dir .app.harness.database.name) | quote }}
+ volumeMounts:
+ - name: "db-backup"
+ mountPath: /backups
+ resources:
+ requests:
+ memory: {{ .root.Values.backup.resources.requests.memory | default "32Mi" }}
+ cpu: {{ .root.Values.backup.resources.requests.cpu | default "25Mi" }}
+ limits:
+ memory: {{ .root.Values.backup.resources.limits.memory | default "64Mi" }}
+ cpu: {{ .root.Values.backup.resources.limits.cpu | default "50mi" }}
+ restartPolicy: OnFailure
+ volumes:
+ - name: "db-backup"
+ persistentVolumeClaim:
+ claimName: "db-backup"
+
+{{ end }}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-postgres.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-postgres.yaml
new file mode 100644
index 00000000..1c272997
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database-postgres.yaml
@@ -0,0 +1,12 @@
+{{- define "deploy_utils.database.postgres" }}
+ image: {{ .app.harness.database.postgres.image }}
+ env:
+ - name: POSTGRES_DB
+ value: {{ .app.harness.database.postgres.initialdb | quote }}
+ - name: POSTGRES_USER
+ value: {{ .app.harness.database.user | quote }}
+ - name: POSTGRES_PASSWORD
+ value: {{ .app.harness.database.pass | quote }}
+ - name: PGDATA
+ value: /data/db/pgdata
+{{- end }}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database.yaml
new file mode 100644
index 00000000..3d52f836
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-database.yaml
@@ -0,0 +1,124 @@
+{{- if .Values.backup.active }}
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: "db-backup"
+ namespace: {{ .Values.namespace }}
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: {{ .Values.backup.volumesize }}
+---
+{{- end }}
+{{- define "deploy_utils.database" }}
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: {{ .app.harness.database.name | quote }}
+ namespace: {{ .root.Values.namespace }}
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: {{ .app.harness.database.size }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ .app.harness.database.name | quote }}
+ namespace: {{ .root.Values.namespace }}
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: {{ .app.harness.database.name | quote }}
+ template:
+ metadata:
+ labels:
+ app: {{ .app.harness.database.name | quote }}
+ service: db
+ spec:
+ affinity:
+ podAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchExpressions:
+ - key: service
+ operator: In
+ values:
+ - db
+ topologyKey: kubernetes.io/hostname
+ containers:
+ - name: {{ .app.harness.database.name | quote }}
+ imagePullPolicy: IfNotPresent
+ {{ include (print "deploy_utils.database." .app.harness.database.type) (dict "root" .root "app" .app) }}
+ ports:
+ {{- range $port := (index .app.harness.database .app.harness.database.type).ports }}
+ - name: {{ $port.name }}
+ containerPort: {{ $port.port }}
+ {{- end }}
+ resources:
+ requests:
+ memory: {{ .app.harness.database.resources.requests.memory | default "32Mi" }}
+ cpu: {{ .app.harness.database.resources.requests.cpu | default "25m" }}
+ limits:
+ memory: {{ .app.harness.database.resources.limits.memory | default "64Mi" }}
+ cpu: {{ .app.harness.database.resources.limits.cpu | default "50m" }}
+ volumeMounts:
+ - name: {{ .app.harness.database.name | quote }}
+ mountPath: /data/db
+ {{- if .root.Values.backup.active }}
+ - name: "db-backup"
+ mountPath: /backup
+ {{- end }}
+ volumes:
+ - name: {{ .app.harness.database.name | quote }}
+ persistentVolumeClaim:
+ claimName: {{ .app.harness.database.name | quote }}
+ {{- if .root.Values.backup.active }}
+ - name: "db-backup"
+ persistentVolumeClaim:
+ claimName: "db-backup"
+ {{- end }}
+---
+{{- if .root.Values.backup.active }}
+{{- include (print "deploy_utils.database." .app.harness.database.type ".backup") . }}
+{{- end }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .app.harness.database.name | quote }}
+ namespace: {{ .root.Values.namespace }}
+ labels:
+ app: {{ .app.harness.deployment.name | quote }}
+{{ include "deploy_utils.labels" .root | indent 4 }}
+spec:
+ type: ClusterIP
+ selector:
+ app: {{ .app.harness.database.name | quote }}
+ ports:
+ {{- range $port := (index .app.harness.database .app.harness.database.type).ports }}
+ - name: {{ $port.name }}
+ port: {{ $port.port }}
+ {{- end }}
+---
+{{ end }}
+{{- range $app := .Values.apps }}
+ {{- if $app.harness.database.auto }}
+ {{ include "deploy_utils.database" (dict "root" $ "app" $app) }}
+ {{- end }}
+ {{- range $subapp := $app }}
+ {{- if contains "map" (typeOf $subapp) }}
+ {{- if hasKey $subapp "harness"}}
+ {{- if and (hasKey $subapp.harness "database") $subapp.harness.database.auto }}
+ {{ include "deploy_utils.database" (dict "root" $ "app" $subapp) }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-deployments.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-deployments.yaml
index d264f78f..abd47a99 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-deployments.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-deployments.yaml
@@ -32,9 +32,18 @@ spec:
- name: {{ .app.harness.deployment.name| default "cloudharness-docs" | quote }}
image: {{ .app.harness.deployment.image }}
imagePullPolicy: {{ include "deploy_utils.pullpolicy" .root }}
+ {{- if .app.harness.deployment.command }}
+ command: {{ .app.harness.deployment.command }}
+ {{- end }}
+ {{- if .app.harness.deployment.args }}
+ args: {{ .app.harness.deployment.args }}
+ {{- end }}
env:
{{- include "deploy_utils.env" .root | nindent 8 }}
{{- include "deploy_utils.privenv" .root | nindent 8 }}
+ {{- if .app.harness.env }}
+ {{- .app.harness.env | toYaml | nindent 8 }}
+ {{- end }}
{{- if .app.harness.secrets }}
{{- range $secret := .app.harness.secrets }}
- name: {{ print $secret.name "-" $secret.key }}
@@ -44,6 +53,22 @@ spec:
key: {{ print $secret.key }}
{{- end }}
{{- end }}
+{{ if .app.harness.livenessProbe }}
+ livenessProbe:
+ httpGet:
+ path: {{ .app.harness.livenessProbe.path }}
+ port: {{ .app.harness.deployment.port | default 8080 }}
+ periodSeconds: {{ .app.harness.livenessProbe.periodSeconds | default 10 }}
+ initialDelaySeconds: {{ .app.harness.livenessProbe.initialDelaySeconds | default 0 }}
+{{ end }}
+{{ if .app.harness.readinessProbe }}
+ readinessProbe:
+ httpGet:
+ path: {{ .app.harness.readinessProbe.path }}
+ port: {{ .app.harness.deployment.port | default 8080 }}
+ periodSeconds: {{ .app.harness.readinessProbe.periodSeconds | default 10 }}
+ initialDelaySeconds: {{ .app.harness.readinessProbe.initialDelaySeconds | default 0 }}
+{{ end }}
ports:
- containerPort: {{ .app.harness.deployment.port | default 8080 }}
resources:
@@ -61,6 +86,13 @@ spec:
- name: {{ .app.harness.deployment.volume.name }}
mountPath: {{ .app.harness.deployment.volume.mountpath }}
{{- end }}
+ {{- $app := .app}}
+ {{- range $resource := .app.harness.resources }}
+ - name: "{{ $app.harness.deployment.name }}-{{ $resource.name }}"
+ mountPath: {{ $resource.dst }}
+ subPath: {{ base $resource.dst }}
+ readOnly: true
+ {{- end}}
volumes:
- name: cloudharness-allvalues
configMap:
@@ -70,14 +102,36 @@ spec:
persistentVolumeClaim:
claimName: {{ .app.harness.deployment.volume.name }}
{{- end }}
-
+ {{ $app := .app }}
+ {{- range $resource := .app.harness.resources }}
+ - name: "{{ $app.harness.deployment.name }}-{{ $resource.name }}"
+ configMap:
+ name: "{{ $app.harness.deployment.name }}-{{ $resource.name }}"
+ {{- end }}
---
{{- end }}
+
+{{- define "deploy_utils.resource"}}
+kind: ConfigMap
+apiVersion: v1
+metadata:
+ name: "{{ .app.harness.deployment.name }}-{{ .resource.name }}"
+ labels:
+ app: {{ .app.harness.deployment.name | quote }}
+ {{ include "deploy_utils.labels" .root | indent 4 }}
+data:
+ {{ base .resource.dst }}: {{ tpl (.root.Files.Get (print "resources/" .app.harness.deployment.name "/" .resource.src)) .root | quote }}
+---
+{{- end}}
+
{{- range $app := .Values.apps }}
{{- if and (hasKey $app "port") $app.harness.deployment.auto | default false }}
---
{{- include "deploy_utils.deployment" (dict "root" $ "app" $app) }}
+ {{- range $resource := $app.harness.resources }}
+ {{- include "deploy_utils.resource" (dict "app" $app "resource" $resource "root" $) }}
{{- end }}
+ {{- end }}
{{- range $subapp := $app }}
{{- if contains "map" (typeOf $subapp) }}
{{- if hasKey $subapp "harness" }}
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-gatekeepers.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-gatekeepers.yaml
index 3c4ab65e..c57898b3 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-gatekeepers.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-gatekeepers.yaml
@@ -1,5 +1,4 @@
{{/* Secured Services/Deployments */}}
-
{{- define "deploy_utils.securedservice" }}
{{- $tls := not (not .root.Values.tls) }}
apiVersion: v1
@@ -11,7 +10,7 @@ metadata:
data:
proxy.yml: |-
verbose: true
- discovery-url: {{ ternary "https" "http" $tls}}://{{ .root.Values.apps.accounts.subdomain }}.{{ .root.Values.domain }}/auth/realms/{{ .root.Values.namespace }}
+ discovery-url: {{ ternary "https" "http" $tls}}://{{ .root.Values.apps.accounts.harness.subdomain }}.{{ .root.Values.domain }}/auth/realms/{{ .root.Values.namespace }}
client-id: {{ .root.Values.apps.accounts.webclient.id | quote }}
client-secret: {{ .root.Values.apps.accounts.webclient.secret }}
secure-cookie: {{ $tls }}
@@ -22,8 +21,6 @@ data:
redirection-url: {{ ternary "https" "http" $tls }}://{{ .app.harness.subdomain }}.{{ .root.Values.domain }}
encryption-key: AgXa7xRcoClDEU0ZDSH4X0XhL5Qy2Z2j
upstream-url: http://{{ .app.harness.service.name }}.{{ .app.namespace | default .root.Release.Namespace }}:{{ .app.harness.service.port | default 80}}
- scopes:
- - vpn-user
{{ if .app.harness.secured }}
{{ with .app.harness.uri_role_mapping }}
resources:
@@ -68,7 +65,7 @@ spec:
{{ include "deploy_utils.etcHosts" .root | indent 6 }}
containers:
- name: {{ .app.harness.service.name | quote }}
- image: "quay.io/louketo/louketo-proxy:1.0.0"
+ image: "gcr.io/metacellllc/louketo-proxy:1.0.0"
imagePullPolicy: IfNotPresent
{{ if .root.Values.local }}
securityContext:
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-services.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-services.yaml
index 1385bfed..4c58a815 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-services.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/auto-services.yaml
@@ -13,6 +13,7 @@ spec:
app: {{ .app.harness.deployment.name| quote }}
ports:
- port: {{ .app.harness.service.port }}
+ targetPort: {{ .app.harness.deployment.port }}
name: http
---
{{- end }}
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/certs/letsencrypt.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/certs/letsencrypt.yaml
index 9d00da02..67765b99 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/certs/letsencrypt.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/certs/letsencrypt.yaml
@@ -1,4 +1,4 @@
-{{ if not .Values.local }}
+{{- if and (not .Values.local) (not (not .Values.tls)) }}
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
@@ -8,7 +8,7 @@ spec:
server: https://acme-v02.api.letsencrypt.org/directory
email: {{ .Values.ingress.letsencrypt.email }}
privateKeySecretRef:
- name: {{ .Values.tls }}
+ name: tls-secret
solvers:
- http01:
ingress:
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/ingress.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/ingress.yaml
index e5e3e243..1beff6d8 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/ingress.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/ingress.yaml
@@ -1,49 +1,62 @@
+{{- define "deploy_utils.ingress.http" }}
+ {{ $domain := .root.Values.domain }}
+ {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }}
+ http:
+ paths:
+ - path: /(.*)
+ backend:
+ serviceName: {{ .app.harness.service.name }}{{- if (and .app.harness.secured $secured_gatekeepers) }}-gk{{- end }}
+ servicePort: {{- if (and .app.harness.secured $secured_gatekeepers) }} 8080 {{- else }} {{ .app.harness.service.port | default 80 }}{{- end }}
+{{- end }}
+{{- define "deploy_utils.ingress.service" }}
+ {{ $domain := .root.Values.domain }}
+ {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }}
+ {{ $app := get .root.Values.apps (print .service_name | snakecase) }}
+ - path: /proxy/{{ $app.harness.service.name }}/(.*)
+ backend:
+ serviceName: {{ $app.harness.service.name }}{{- if (and $app.harness.secured $secured_gatekeepers) }}-gk{{- end }}
+ servicePort: {{- if (and $app.harness.secured $secured_gatekeepers) }} 8080 {{- else }} {{ $app.harness.service.port | default 80 }}{{- end }}
+{{- end }}
{{- if .Values.ingress.enabled }}
{{ $domain := .Values.domain }}
{{ $tls := not (not .Values.tls) }}
- {{ $secured_gatekeepers := and .Values.secured_gatekeepers }}
+{{ $mainapp := .Values.mainapp }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ .Values.ingress.name | quote }}
annotations:
- {{- if not .Values.local }}
- kubernetes.io/tls-acme: 'true'
kubernetes.io/ingress.class: nginx
+ {{- if and (not .Values.local) $tls }}
+ kubernetes.io/tls-acme: 'true'
cert-manager.io/cluster-issuer: {{ printf "%s-%s" "letsencrypt" .Values.namespace }}
{{- end }}
nginx.ingress.kubernetes.io/ssl-redirect: {{ (and $tls .Values.ingress.ssl_redirect) | quote }}
nginx.ingress.kubernetes.io/proxy-body-size: '10m'
nginx.ingress.kubernetes.io/from-to-www-redirect: 'true'
+ nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
{{- range $app := .Values.apps }}
- {{- if $app.harness.domain }}
+ {{- if (eq $app.harness.name $mainapp) }}
- host: {{ $domain | quote }}
- http:
- paths:
- - path: /
- backend:
- serviceName: {{- if (and $app.harness.secured $secured_gatekeepers) }} "{{ $app.harness.service.name }}-gk" {{- else }} {{ $app.harness.service.name | quote }}{{- end }}
- servicePort: {{- if (and $app.harness.secured $secured_gatekeepers) }} 8080 {{- else }} {{ $app.harness.service.port | default 80 }}{{- end }}
- {{- else if $app.harness.subdomain }}
+ {{ include "deploy_utils.ingress.http" (dict "root" $ "app" $app) }}
+ {{- end }}
+ {{- if $app.harness.domain }}
+ - host: {{ $app.harness.domain | quote }}
+ {{ include "deploy_utils.ingress.http" (dict "root" $ "app" $app) }}
+ {{- end }}
+ {{- if $app.harness.subdomain }}
- host: {{ printf "%s.%s" $app.harness.subdomain $domain | quote }}
- http:
- paths:
- - path: /
- backend:
- serviceName: {{- if (and $app.harness.secured $secured_gatekeepers) }} "{{ $app.harness.service.name }}-gk" {{- else }} {{ $app.harness.service.name | quote }}{{- end }}
- servicePort: {{- if (and $app.harness.secured $secured_gatekeepers) }} 8080 {{- else }} {{ $app.harness.service.port | default 80 }}{{- end }}
+ {{ include "deploy_utils.ingress.http" (dict "root" $ "app" $app) }}
+ {{- range $service := $app.harness.use_services }}
+ {{ include "deploy_utils.ingress.service" (dict "root" $ "service_name" $service.name) }}
+ {{- end }}
{{- range $subapp := $app }}
- {{- if contains "map" (typeOf $subapp) }}
- {{- if and $subapp (hasKey $subapp "harness.subdomain") }}
+ {{- if contains "map" (typeOf $subapp) }}
+ {{- if and $subapp (hasKey $subapp "harness.subdomain") }}
- host: {{ printf "%s.%s.%s" $subapp.harness.subdomain $app.harness.subdomain $domain | quote }}
- http:
- paths:
- - path: /
- backend:
- serviceName: {{- if (and $app.harness.secured $secured_gatekeepers) }} "{{ $subapp.harness.service.name }}-gk" {{- else }} {{ $subapp.harness.service.name | quote }}{{- end }}
- servicePort: {{- if (and $app.harness.secured $secured_gatekeepers) }} 8080 {{- else }} {{ $subapp.harness.service.port | default 80 }}{{- end }}
+ {{ include "deploy_utils.ingress.http" (dict "root" $ "app" $subapp) }}
{{- end }}
{{- end }}
{{- end }}
@@ -55,10 +68,16 @@ spec:
{{- range $app := .Values.apps }}
{{- if $app.harness.subdomain }}
- {{ printf "%s.%s" $app.harness.subdomain $domain | quote }}
- {{- else if $app.domain }}
- - {{ $domain | quote }}
{{- end }}
+ {{- if $app.harness.domain }}
+ {{- if ne $app.harness.domain $domain }}
+ - {{ $app.harness.domain | quote }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- if $mainapp }}
+ - {{ $domain | quote }}
{{- end }}
- secretName: {{ $tls | quote }}
+ secretName: tls-secret
{{- end }}
{{- end }}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/tls-secret.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/tls-secret.yaml
index 9c08fb4b..ac871d2f 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/templates/tls-secret.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/templates/tls-secret.yaml
@@ -2,7 +2,7 @@
apiVersion: v1
kind: Secret
metadata:
- name: {{ .Values.tls | quote }}
+ name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: {{ .Files.Get "resources/certs/tls.crt" | b64enc | quote }}
diff --git a/utilities/cloudharness_utilities/deployment-configuration/helm/values.yaml b/utilities/cloudharness_utilities/deployment-configuration/helm/values.yaml
index e69de29b..11646d46 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/helm/values.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/helm/values.yaml
@@ -0,0 +1,73 @@
+# -- If set to local, TLS won't be configured.
+local: false
+# -- Enables/disables Gatekeeper.
+secured_gatekeepers: true
+# -- ?
+nameOverride: ""
+# -- ?
+fullnameOverride: ""
+# -- The root domain.
+domain: ${{DOMAIN}}
+# -- The K8s namespace.
+namespace: ch
+# -- Name of mainapp, routes incoming traffic of root `domaim` to this app.
+mainapp: accounts
+registry:
+ # -- The docker registry.
+ name: "localhost:5000"
+ # -- Optional secret used for pulling from docker registry.
+ secret:
+# -- Docker tag used to pull images.
+tag: latest
+# -- List of applications.
+# @default -- Will be filled automatically.
+apps: {}
+env:
+ # -- Cloud Harness version
+ - name: CH_VERSION
+ value: 0.0.1
+ # -- Cloud harness chart version
+ - name: CH_CHART_VERSION
+ value: 0.0.1
+privenv:
+ # -- Defines a secret as private environment variable that is injected in containers.
+ - name: CH_SECRET
+ value: In God we trust; all others must bring data. ― W. Edwards Deming
+ingress:
+ # -- Flag to enable/disalbe ingress controller.
+ enabled: true
+ # -- K8s Name of ingress.
+ name: cloudharness-ingress
+ # -- Enables/disables SSL redirect.
+ ssl_redirect: true
+ letsencrypt:
+ # -- Email for letsencrypt.
+ email: filippo@metacell.us
+backup:
+ # -- Flag to enable/disable backups.
+ active: true
+ # -- Number of days to keep backups.
+ keep_days: "7"
+ # -- Number of weeks to keep backups.
+ keep_weeks: "4"
+ # -- Number of months to keep backups.
+ keep_months: "6"
+ # -- Schedule as cronjob expression.
+ schedule: "*/5 * * * *"
+ # -- The file suffix added to backup files.
+ suffix: ".gz"
+ # -- The volume size for backups (all backups share the same volume)
+ volumesize: "2Gi"
+ # -- Target directory of backups, the mount point of the persistent volume.
+ dir: "/backups"
+ resources:
+ requests:
+ # -- K8s memory resource definition.
+ memory: "32Mi"
+ # -- K8s cpu resource definition.
+ cpu: "25m"
+ limits:
+ # -- K8s memory resource definition.
+ memory: "64Mi"
+ # -- K8s cpu resource definition.
+ cpu: "50m"
diff --git a/utilities/cloudharness_utilities/deployment-configuration/launch.json b/utilities/cloudharness_utilities/deployment-configuration/launch.json
new file mode 100644
index 00000000..b3e96bec
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/launch.json
@@ -0,0 +1,4 @@
+{
+ "version": "0.2.0",
+ "configurations": []
+}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/skaffold-template.yaml b/utilities/cloudharness_utilities/deployment-configuration/skaffold-template.yaml
new file mode 100644
index 00000000..91c45143
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/skaffold-template.yaml
@@ -0,0 +1,23 @@
+apiVersion: skaffold/v2beta11
+kind: Config
+build:
+ tagPolicy:
+ sha256: {}
+ artifacts: []
+deploy:
+
+ helm:
+ flags:
+ upgrade:
+ - --install
+ releases:
+ - name:
+ chartPath: deployment/helm
+ #wait: true
+ #valuesFiles:
+ #- helm-skaffold-values.yaml
+ skipBuildDependencies: true # Skip helm dep build
+ artifactOverrides:
+ apps:
+ overrides:
+ apps: {}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/value-template.yaml b/utilities/cloudharness_utilities/deployment-configuration/value-template.yaml
index 0b2934a4..fed799a7 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/value-template.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/value-template.yaml
@@ -1,26 +1,100 @@
harness:
- name:
+ # -- If specified, an ingress will be created at [subdomain].[.Values.domain]
subdomain:
+ # -- If specified, an ingress will be created at [domain]
domain:
+ # -- Application dependencies are used to define what is required in the deployment when --include (-i) is used. Specify application names in the list.
+ dependencies:
+ # -- Hard dependencies indicate that the application may not start without these other applications.
+ hard: []
+ # -- Hard dependencies indicate that the application will work partially without these other applications.
+ soft: []
+ # -- Hard dependencies indicate that the application Docker image build requires these base/common images
+ build: []
+ # -- When true, the application is shielded with a getekeeper
secured: false
+ # -- Uri/Role mapping for the gatekeeper
uri_role_mapping:
- uri: /*
roles:
- administrator
+ # -- Defines reference deployment parameters. Values maps to k8s spec
deployment:
+ # -- When true, enables automatic deployment
auto: false
+ # -- Number of pod replicas for the deployment.
replicas: 1
+ # -- Docker image url. Leave blank to leave Cloudharness automatic image name assignment.
image:
+ # -- Deployment name. Leave blank to leave Cloudharness automatic image name assignment.
name:
- port: 8081
+ # -- Deployment port.
+ port: 8080
+ # -- Deployment resources.
resources:
requests:
memory: "32Mi"
- cpu: "25m"
+ cpu: "10m"
limits:
memory: "500Mi"
cpu: "500m"
+ # -- Defines automatic service parameters.
service:
+ # -- When true, enables automatic service
auto: true
+ # -- Service name. Leave blank to leave Cloudharness automatic image name assignment.
name:
- port: 80
\ No newline at end of file
+ # -- Service port.
+ port: 80
+ # -- Specify which services this application uses in the frontend to create proxy ingresses. e.g. - name: mnp-checkout
+ use_services: []
+ # -- Reference database specs
+ database:
+ # -- When true, enables automatic database deployment
+ auto: false
+ # -- Database deployment name. Leave blank to leave Cloudharness automatic image name assignment.
+ name:
+ # -- supported db types: mongo, postgres, neo4j
+ type:
+ size: 1Gi
+ # -- database username
+ user: mnp
+ # -- database password
+ pass: metacell
+ # -- settings for mongo database (for type==mongo)
+ mongo:
+ image: mongo:latest
+ ports:
+ - name: http
+ port: 27017
+ # -- settings for postgers database (for type==postgres)
+ postgres:
+ image: postgres:latest
+ initialdb: cloudharness
+ ports:
+ - name: http
+ port: 5432
+ # -- settings for neo4j database (for type==neo4j)
+ neo4j:
+ image: neo4j:latest
+ memory:
+ size: 256M
+ pagecache:
+ size: 64M
+ heap:
+ initial: 64M
+ max: 128M
+ dbms_security_auth_enabled: "false"
+ ports:
+ - name: http
+ port: 7474
+ - name: bolt
+ port: 7687
+ # -- database deployment resources
+ resources:
+ requests:
+ memory: "512Mi"
+ cpu: "100m"
+ limits:
+ memory: "2Gi"
+ cpu: "1000m"
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/values-template.yaml b/utilities/cloudharness_utilities/deployment-configuration/values-template.yaml
index 913c9221..e69de29b 100644
--- a/utilities/cloudharness_utilities/deployment-configuration/values-template.yaml
+++ b/utilities/cloudharness_utilities/deployment-configuration/values-template.yaml
@@ -1,27 +0,0 @@
-local: false
-secured_gatekeepers: true
-nameOverride: ""
-fullnameOverride: ""
-domain: ${{DOMAIN}}
-namespace: ch
-registry:
- name: "localhost:5000"
- secret:
-tag: latest
-serviceaccount: argo-workflows
-apps:
- FILL_ME
-env:
- - name: CH_VERSION
- value: 0.0.1
- - name: CH_CHART_VERSION
- value: 0.0.1
-privenv:
- - name: CH_SECRET
- value: In God we trust; all others must bring data. ― W. Edwards Deming
-ingress:
- enabled: true
- name: cloudharness-ingress
- ssl_redirect: true
- letsencrypt:
- email: facundo@metacell.us
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/deployment-configuration/vscode-debug-template.json b/utilities/cloudharness_utilities/deployment-configuration/vscode-debug-template.json
new file mode 100644
index 00000000..8eabd715
--- /dev/null
+++ b/utilities/cloudharness_utilities/deployment-configuration/vscode-debug-template.json
@@ -0,0 +1,13 @@
+{
+ "name": "CloudHarness: Run/Debug",
+ "type": "cloudcode.kubernetes",
+ "request": "launch",
+ "skaffoldConfig": "${workspaceFolder}/skaffold.yaml",
+ "watch": true,
+ "cleanUp": false,
+ "portForward": true,
+ "imageRegistry": "localhost:5000",
+ "debug": [
+
+ ]
+}
\ No newline at end of file
diff --git a/utilities/cloudharness_utilities/dev_utils.py b/utilities/cloudharness_utilities/dev_utils.py
new file mode 100644
index 00000000..461b95d8
--- /dev/null
+++ b/utilities/cloudharness_utilities/dev_utils.py
@@ -0,0 +1,159 @@
+import os
+import logging
+import json
+
+from cloudharness_utilities.constants import HELM_CHART_PATH, DEPLOYMENT_CONFIGURATION_PATH, DEPLOYMENT_PATH, \
+ BASE_IMAGES_PATH, STATIC_IMAGES_PATH
+from cloudharness_utilities.helm import KEY_APPS, KEY_HARNESS, KEY_DEPLOYMENT
+from cloudharness_utilities.utils import get_template, dict_merge, find_dockerfiles_paths, app_name_from_path, \
+ find_file_paths, merge_to_yaml_file, get_json_template
+
+
+def create_skaffold_configuration(root_paths, helm_values, output_path='.', manage_task_images=True):
+ skaffold_conf = get_template('skaffold-template.yaml', True)
+ apps = helm_values[KEY_APPS]
+ artifacts = {}
+ overrides = {}
+ release_config = skaffold_conf['deploy']['helm']['releases'][0]
+ release_config['name'] = helm_values['namespace']
+ release_config['namespace'] = helm_values['namespace']
+
+ def build_artifact(app_name, root_path, requirements=None, dockerfile_path=''):
+ artifact_spec = {
+ 'image': app_name,
+ 'context': root_path,
+ 'docker': {
+ 'dockerfile': os.path.join(dockerfile_path, 'Dockerfile'),
+ 'buildArgs': {
+ 'REGISTRY': helm_values["registry"]["name"],
+ 'TAG': helm_values["tag"]
+ }
+ }
+ }
+ if requirements:
+ artifact_spec['requires'] = [{'image': req, 'alias': req.replace('-', '_').upper()} for req in requirements]
+ return artifact_spec
+
+ release_config['artifactOverrides'][KEY_APPS] = {}
+ for root_path in root_paths:
+ skaffold_conf = dict_merge(skaffold_conf, get_template(
+ os.path.join(root_path, DEPLOYMENT_CONFIGURATION_PATH, 'skaffold-template.yaml')))
+ apps_path = os.path.join(root_path, 'applications')
+
+ base_dockerfiles = find_dockerfiles_paths(os.path.join(root_path, BASE_IMAGES_PATH))
+
+ base_images = []
+ for dockerfile_path in base_dockerfiles:
+ context_path = os.path.relpath(root_path, output_path)
+ app_name = app_name_from_path(os.path.basename(dockerfile_path))
+ base_images.append(app_name)
+ artifacts[app_name] = build_artifact(app_name, context_path,
+ dockerfile_path=os.path.relpath(dockerfile_path, context_path))
+
+ static_dockerfiles = find_dockerfiles_paths(os.path.join(root_path, STATIC_IMAGES_PATH))
+ static_images = []
+ for dockerfile_path in static_dockerfiles:
+ context_path = os.path.relpath(dockerfile_path, output_path)
+ app_name = app_name_from_path(os.path.basename(context_path))
+ static_images.append(app_name)
+ artifacts[app_name] = build_artifact(app_name, context_path, base_images)
+
+ app_dockerfiles = find_dockerfiles_paths(apps_path)
+
+ for dockerfile_path in app_dockerfiles:
+ app_relative_to_skaffold = os.path.relpath(dockerfile_path, output_path)
+ context_path = os.path.relpath(dockerfile_path, '.')
+ app_relative_to_base = os.path.relpath(dockerfile_path, apps_path)
+ app_name = app_name_from_path(app_relative_to_base)
+ app_key = app_name.replace('-', '_')
+ if app_key not in apps:
+ if 'tasks' in app_relative_to_base and manage_task_images:
+ parent_app_name = app_name_from_path(app_relative_to_base.split('/tasks')[0])
+ parent_app_key = parent_app_name.replace('-', '_')
+
+ if parent_app_key in apps:
+ artifacts[app_key] = build_artifact(app_name, app_relative_to_skaffold,
+ base_images + static_images)
+
+ continue
+
+ build_requirements = apps[app_key][KEY_HARNESS]['dependencies'].get('build', [])
+ artifacts[app_key] = build_artifact(app_name, app_relative_to_skaffold, build_requirements)
+
+ app = apps[app_key]
+ if app[KEY_HARNESS][KEY_DEPLOYMENT]['image']:
+ release_config['artifactOverrides']['apps'][app_key] = \
+ {
+ 'harness': {
+ 'deployment': {
+ 'image': app[KEY_HARNESS]['name']
+ }
+ }
+ }
+
+ flask_main = find_file_paths(context_path, '__main__.py')
+
+ if flask_main:
+ release_config['overrides']['apps'][app_key] = \
+ {
+ 'harness': {
+ 'deployment': {
+ 'command': ['python'],
+ 'args': [f'/usr/src/app/{os.path.basename(flask_main[0])}/__main__.py']
+ }
+ }
+ }
+
+ skaffold_conf['build']['artifacts'] = [v for v in artifacts.values()]
+ merge_to_yaml_file(skaffold_conf, os.path.join(output_path, 'skaffold.yaml'))
+
+
+def create_vscode_debug_configuration(root_paths, values_manual_deploy):
+ logging.info("Creating VS code cloud build configuration.\nCloud build extension is needed to debug.")
+
+ vscode_launch_path = '.vscode/launch.json'
+
+ vs_conf = get_json_template(vscode_launch_path, True)
+
+ debug_conf = get_json_template('vscode-debug-template.json', True)
+
+ if values_manual_deploy['registry'].get('name', None):
+ debug_conf["imageRegistry"] = values_manual_deploy['registry']['name'][:-1] # remove trailing /
+ for i in range(len(vs_conf['configurations'])):
+ conf = vs_conf['configurations'][i]
+ if conf['name'] == debug_conf['name']:
+ del vs_conf['configurations'][i]
+ break
+ vs_conf['configurations'].append(debug_conf)
+
+ apps = values_manual_deploy[KEY_APPS]
+
+ for root_path in root_paths:
+ apps_path = os.path.join(root_path, 'applications')
+
+ flask_main_paths = find_file_paths(apps_path, '__main__.py')
+
+ for path in flask_main_paths:
+ app_relative_to_base = os.path.relpath(os.path.dirname(path), apps_path)
+ app_relative_to_root = os.path.relpath(os.path.dirname(path), '.')
+ app_name = app_name_from_path(app_relative_to_base.split('/')[0])
+ app_key = app_name.replace('-', '_')
+ if app_key in apps.keys():
+ debug_conf["debug"].append({
+ "image": app_name,
+ # the double source map doesn't work at the moment. Hopefully will be fixed in future skaffold updates
+ "sourceFileMap": {
+ f"${{workspaceFolder}}/{app_relative_to_root}": "/usr/src/app",
+ }
+ })
+ debug_conf["debug"].append({
+ "image": app_name,
+ "sourceFileMap": {
+ "${workspaceFolder}/cloud-harness/libraries": "/libraries"
+ }
+ })
+
+ if not os.path.exists(os.path.dirname(vscode_launch_path)):
+ os.makedirs(os.path.dirname(vscode_launch_path))
+ with open(vscode_launch_path, 'w') as f:
+ json.dump(vs_conf, f, indent=2, sort_keys=True)
diff --git a/utilities/cloudharness_utilities/helm.py b/utilities/cloudharness_utilities/helm.py
index b3ae2dd5..a14db89c 100644
--- a/utilities/cloudharness_utilities/helm.py
+++ b/utilities/cloudharness_utilities/helm.py
@@ -4,12 +4,10 @@
import yaml
import os
import shutil
-import sys
import logging
import subprocess
import tarfile
from docker import from_env as DockerClient
-from pathlib import Path
from .constants import VALUES_MANUAL_PATH, VALUE_TEMPLATE_PATH, HELM_CHART_PATH, APPS_PATH, HELM_PATH, HERE, \
DEPLOYMENT_CONFIGURATION_PATH
from .utils import get_cluster_ip, get_image_name, env_variable, get_sub_paths, app_name_from_path, \
@@ -17,22 +15,38 @@
KEY_HARNESS = 'harness'
KEY_SERVICE = 'service'
+KEY_DATABASE = 'database'
KEY_DEPLOYMENT = 'deployment'
KEY_APPS = 'apps'
+def deploy(namespace, output_path='./deployment'):
+ helm_path = os.path.join(output_path, HELM_CHART_PATH)
+ logging.info('Deploying helm chart %s', helm_path)
+ subprocess.run("helm dependency update".split(), cwd=helm_path)
+
+ subprocess.run(
+ f"helm upgrade {namespace} {helm_path} -n {namespace} --install --reset-values".split())
+
+
def create_helm_chart(root_paths, tag='latest', registry='', local=True, domain=None, exclude=(), secured=True,
- output_path='./deployment', include=None, registry_secret=None, tls=True):
+ output_path='./deployment', include=None, registry_secret=None, tls=True, env=None,
+ namespace=None):
"""
Creates values file for the helm chart
"""
- dest_deployment_path = os.path.join(output_path, HELM_CHART_PATH)
+ assert domain, 'A domain must be specified'
+ dest_deployment_path = os.path.join(output_path, HELM_CHART_PATH)
+ if registry and registry[-1] != '/':
+ registry = registry + '/'
if os.path.exists(dest_deployment_path):
shutil.rmtree(dest_deployment_path)
# Initialize with default
copy_merge_base_deployment(dest_deployment_path, os.path.join(HERE, DEPLOYMENT_CONFIGURATION_PATH, HELM_PATH))
- helm_values = collect_helm_values(HERE, tag=tag, registry=registry, exclude=exclude, include=include)
+ helm_values = get_template(os.path.join(HERE, DEPLOYMENT_CONFIGURATION_PATH, HELM_PATH, 'values.yaml'))
+ helm_values = dict_merge(helm_values,
+ collect_helm_values(HERE, tag=tag, registry=registry, exclude=exclude, env=env))
# Override for every cloudharness scaffolding
for root_path in root_paths:
@@ -41,18 +55,54 @@ def create_helm_chart(root_paths, tag='latest', registry='', local=True, domain=
collect_apps_helm_templates(root_path, exclude=exclude, include=include,
dest_helm_chart_path=dest_deployment_path)
helm_values = dict_merge(helm_values,
- collect_helm_values(root_path, tag=tag, registry=registry, exclude=exclude,
- include=include))
+ collect_helm_values(root_path, tag=tag, registry=registry, exclude=exclude, env=env))
+
+ # Override for every cloudharness scaffolding
+ helm_values[KEY_APPS] = {}
+
+ for root_path in root_paths:
+ app_values = init_app_values(root_path, exclude=exclude, values=helm_values[KEY_APPS])
+ helm_values[KEY_APPS] = dict_merge(helm_values[KEY_APPS],
+ app_values)
+
+ # Override for every cloudharness scaffolding
+ for root_path in root_paths:
+ app_values = collect_app_values(root_path, tag=tag, registry=registry, exclude=exclude, env=env)
+ helm_values[KEY_APPS] = dict_merge(helm_values[KEY_APPS],
+ app_values)
create_tls_certificate(local, domain, tls, output_path, helm_values)
- finish_helm_values(values=helm_values, tag=tag, registry=registry, local=local, domain=domain, secured=secured,
- registry_secret=registry_secret, tls=tls)
+ values, include = finish_helm_values(values=helm_values, namespace=namespace, tag=tag, registry=registry,
+ local=local, domain=domain,
+ secured=secured,
+ registry_secret=registry_secret, tls=tls, include=include)
+
+ for root_path in root_paths:
+ collect_apps_helm_templates(root_path, exclude=exclude, include=include,
+ dest_helm_chart_path=dest_deployment_path)
# Save values file for manual helm chart
merged_values = merge_to_yaml_file(helm_values, os.path.join(dest_deployment_path, VALUES_MANUAL_PATH))
+ if namespace:
+ merge_to_yaml_file({'metadata': {'namespace': namespace}}, os.path.join(dest_deployment_path, 'Chart.yaml'))
return merged_values
+def get_included_with_dependencies(values, include):
+ app_values = values['apps'].values()
+ directly_included = [app for app in app_values if any(inc == app['harness']['name'] for inc in include)]
+
+ dependent = set(include)
+ for app in directly_included:
+ dependent.update(set(app['harness']['dependencies']['hard']))
+ dependent.update(set(app['harness']['dependencies']['soft']))
+ if values['secured_gatekeepers'] and app['harness']['secured']:
+ dependent.add('accounts')
+ if len(dependent) == len(include):
+ return dependent
+ return get_included_with_dependencies(values, dependent)
+
+
def merge_helm_chart(source_templates_path, dest_helm_chart_path=HELM_CHART_PATH):
pass
@@ -87,9 +137,19 @@ def collect_apps_helm_templates(search_root, dest_helm_chart_path, exclude=(), i
dest_dir = os.path.join(dest_helm_chart_path, 'resources', app_name)
logging.info("Collecting resources for application %s to %s", app_name, dest_dir)
+
+ merge_configuration_directories(resources_dir, dest_dir)
+
+ subchart_dir = os.path.join(app_path, 'deploy/charts')
+ if os.path.exists(subchart_dir):
+ dest_dir = os.path.join(dest_helm_chart_path, 'charts', app_name)
+
+ logging.info("Collecting templates for application %s to %s", app_name, dest_dir)
if os.path.exists(dest_dir):
- shutil.rmtree(dest_dir)
- shutil.copytree(resources_dir, dest_dir)
+ logging.warning("Merging/overriding all files in directory %s", dest_dir)
+ merge_configuration_directories(subchart_dir, dest_dir)
+ else:
+ shutil.copytree(subchart_dir, dest_dir)
def copy_merge_base_deployment(dest_helm_chart_path, base_helm_chart):
@@ -103,35 +163,68 @@ def copy_merge_base_deployment(dest_helm_chart_path, base_helm_chart):
shutil.copytree(base_helm_chart, dest_helm_chart_path)
-def collect_helm_values(deployment_root, exclude=(), include=None, tag='latest', registry=''):
+def collect_helm_values(deployment_root, exclude=(), tag='latest', registry='', env=None):
"""
Creates helm values from a cloudharness deployment scaffolding
"""
values_template_path = os.path.join(deployment_root, DEPLOYMENT_CONFIGURATION_PATH, 'values-template.yaml')
- value_spec_template_path = os.path.join(deployment_root, DEPLOYMENT_CONFIGURATION_PATH, 'value-template.yaml')
- if not os.path.exists(values_template_path):
- values = {}
- else:
- values = get_template(values_template_path)
- values[KEY_APPS] = {}
+ values = get_template(values_template_path)
+ if env is not None:
+ specific_template_path = os.path.join(deployment_root, DEPLOYMENT_CONFIGURATION_PATH,
+ f'values-template-{env}.yaml')
+ if os.path.exists(specific_template_path):
+ logging.info("Specific environment values template found: " + specific_template_path)
+ with open(specific_template_path) as f:
+ values_env_specific = yaml.safe_load(f)
+ values = dict_merge(values, values_env_specific)
+ return values
+
+
+def init_app_values(deployment_root, exclude, values={}):
app_base_path = os.path.join(deployment_root, APPS_PATH)
+ overridden_template_path = os.path.join(deployment_root, DEPLOYMENT_CONFIGURATION_PATH, 'value-template.yaml')
+ default_values_path = os.path.join(HERE, DEPLOYMENT_CONFIGURATION_PATH, 'value-template.yaml')
+
for app_path in get_sub_paths(app_base_path):
+
app_name = app_name_from_path(os.path.relpath(app_path, app_base_path))
- if app_name in exclude or (include and not any(inc in app_name for inc in include)):
+ if app_name in exclude:
continue
+ app_key = app_name.replace('-', '_')
+ if app_key not in values:
+ default_values = get_template(default_values_path)
+ values[app_key] = default_values
+ overridden_defaults = get_template(overridden_template_path)
+ values[app_key] = dict_merge(values[app_key], overridden_defaults)
+
+ return values
- app_values = create_values_spec(app_name, app_path, tag=tag, registry=registry,
- template_path=value_spec_template_path)
- values[KEY_APPS][app_name.replace('-', '_')] = app_values
+
+def collect_app_values(deployment_root, exclude=(), tag='latest', registry='', env=None):
+ app_base_path = os.path.join(deployment_root, APPS_PATH)
+
+ values = {}
+ for app_path in get_sub_paths(app_base_path):
+ app_name = app_name_from_path(os.path.relpath(app_path, app_base_path))
+
+ if app_name in exclude:
+ continue
+ app_key = app_name.replace('-', '_')
+
+ app_values = create_values_spec(app_name, app_path, tag=tag, registry=registry, env=env)
+
+ values[app_key] = dict_merge(values[app_key], app_values) if app_key in values else app_values
return values
-def finish_helm_values(values, tag='latest', registry='', local=True, domain=None, secured=True, registry_secret=None, tls=True):
+def finish_helm_values(values, namespace, tag='latest', registry='', local=True, domain=None, secured=True,
+ registry_secret=None,
+ tls=True, include=None):
"""
Sets default overridden values
"""
@@ -144,6 +237,8 @@ def finish_helm_values(values, tag='latest', registry='', local=True, domain=Non
values['registry']['name'] = registry
values['registry']['secret'] = registry_secret
values['tag'] = tag
+ if namespace:
+ values['namespace'] = namespace
values['secured_gatekeepers'] = secured
values['ingress']['ssl_redirect'] = values['ingress']['ssl_redirect'] and tls
@@ -156,10 +251,47 @@ def finish_helm_values(values, tag='latest', registry='', local=True, domain=Non
values['localIp'] = get_cluster_ip()
except subprocess.TimeoutExpired:
logging.warning("Minikube not available")
+ except:
+ logging.warning("Kubectl not available")
+
+ apps = values[KEY_APPS]
+
+ for app_key in apps:
+ v = apps[app_key]
- # Create environment variables
+ values_from_legacy(v)
+ assert KEY_HARNESS in v, 'Default app value loading is broken'
+
+ harness = v[KEY_HARNESS]
+ if KEY_SERVICE not in harness:
+ harness[KEY_SERVICE] = {}
+ if KEY_DEPLOYMENT not in harness:
+ harness[KEY_DEPLOYMENT] = {}
+ if KEY_DATABASE not in harness:
+ harness[KEY_DATABASE] = {}
+ app_name = app_key.replace('_', '-')
+
+ harness['name'] = app_name
+ if not harness[KEY_SERVICE].get('name', None):
+ harness[KEY_SERVICE]['name'] = app_name
+ if not harness[KEY_DEPLOYMENT].get('name', None):
+ harness[KEY_DEPLOYMENT]['name'] = app_name
+ if not harness[KEY_DATABASE].get('name', None):
+ harness[KEY_DATABASE]['name'] = app_name.strip() + '-db'
+ if not harness[KEY_DEPLOYMENT].get('image', None):
+ harness[KEY_DEPLOYMENT]['image'] = registry + get_image_name(app_name) + f':{tag}' if tag else ''
+ values_set_legacy(v)
+
+ if include:
+ include = get_included_with_dependencies(values, set(include))
+ logging.info('Selecting included applications')
+
+ for v in [v for v in apps]:
+ if apps[v]['harness']['name'] not in include:
+ del apps[v]
+ # Create environment variables
create_env_variables(values)
- return values
+ return values, include
def values_from_legacy(values):
@@ -192,45 +324,32 @@ def values_set_legacy(values):
values['image'] = harness[KEY_DEPLOYMENT]['image']
values['name'] = harness['name']
- if harness[KEY_DEPLOYMENT]['port']:
+ if harness[KEY_DEPLOYMENT].get('port', None):
values['port'] = harness[KEY_DEPLOYMENT]['port']
- values['resources'] = harness[KEY_DEPLOYMENT]['resources']
+ if 'resources' in harness[KEY_DEPLOYMENT]:
+ values['resources'] = harness[KEY_DEPLOYMENT]['resources']
-def create_values_spec(app_name, app_path, tag=None, registry='', template_path=VALUE_TEMPLATE_PATH):
+def create_values_spec(app_name, app_path, tag=None, registry='', env=None):
logging.info('Generating values script for ' + app_name)
- values_default = get_template(template_path)
-
specific_template_path = os.path.join(app_path, 'deploy', 'values.yaml')
if os.path.exists(specific_template_path):
logging.info("Specific values template found: " + specific_template_path)
- with open(specific_template_path) as f:
- values_specific = yaml.safe_load(f)
- values = dict_merge(values_default, values_specific)
+ values = get_template(specific_template_path)
else:
- values = values_default
-
- values_from_legacy(values)
- harness = values[KEY_HARNESS]
-
- if not harness['name']:
- harness['name'] = app_name
- if not harness[KEY_SERVICE]['name']:
- harness[KEY_SERVICE]['name'] = app_name
- if not harness[KEY_DEPLOYMENT]['name']:
- harness[KEY_DEPLOYMENT]['name'] = app_name
- if not harness[KEY_DEPLOYMENT]['image']:
- if registry and registry[-1] != '/':
- registry = registry + '/'
- harness[KEY_DEPLOYMENT]['image'] = registry + get_image_name(app_name) + f':{tag}' if tag else ''
-
- values_set_legacy(values)
-
- for k in values:
- if isinstance(values[k], dict) and KEY_HARNESS in values[k]:
- values[k][KEY_HARNESS] = dict_merge(values[k][KEY_HARNESS], values_default[KEY_HARNESS])
+ values = {}
+ if env is not None:
+ specific_template_path = os.path.join(app_path, 'deploy', f'values-{env}.yaml')
+ if os.path.exists(specific_template_path):
+ logging.info("Specific environment values template found: " + specific_template_path)
+ with open(specific_template_path) as f:
+ values_env_specific = yaml.safe_load(f)
+ values = dict_merge(values, values_env_specific)
+ if KEY_HARNESS in values and 'name' in values[KEY_HARNESS] and values[KEY_HARNESS]['name']:
+ logging.warning('Name is automatically set in applications: name %s will be ignored',
+ values[KEY_HARNESS]['name'])
return values
@@ -266,29 +385,28 @@ def hosts_info(values):
logging.warning('Cannot get cluster ip')
return
logging.info(
- "\nTo test locally, update your hosts file" + f"\n{ip}\t{' '.join(sd + '.' + domain for sd in subdomains)}")
+ "\nTo test locally, update your hosts file" + f"\n{ip}\t{domain + ' ' + ' '.join(sd + '.' + domain for sd in subdomains)}")
deployments = (app[KEY_HARNESS][KEY_DEPLOYMENT]['name'] for app in values[KEY_APPS].values() if KEY_HARNESS in app)
logging.info("\nTo run locally some apps, also those references may be needed")
for appname in values[KEY_APPS]:
- app = values[KEY_APPS][appname]
- if 'name' not in app or 'port' not in app: continue
+ app = values[KEY_APPS][appname]['harness']
+ if 'deployment' not in app: continue
print(
"kubectl port-forward -n {namespace} deployment/{app} {port}:{port}".format(
- app=appname, port=app['port'], namespace=namespace))
+ app=app['deployment']['name'], port=app['deployment']['port'], namespace=namespace))
print(f"127.0.0.1\t{' '.join(s + '.cloudharness' for s in deployments)}")
def create_tls_certificate(local, domain, tls, output_path, helm_values):
-
if not tls:
helm_values['tls'] = None
return
- helm_values['tls'] = domain.replace(".", "-") + "-tls"
if not local:
return
+ helm_values['tls'] = domain.replace(".", "-") + "-tls"
HERE = os.path.dirname(os.path.realpath(__file__)).replace(os.path.sep, '/')
ROOT = os.path.dirname(os.path.dirname(HERE)).replace(os.path.sep, '/')
diff --git a/utilities/cloudharness_utilities/openapi.py b/utilities/cloudharness_utilities/openapi.py
index 276e7841..a0720dbf 100644
--- a/utilities/cloudharness_utilities/openapi.py
+++ b/utilities/cloudharness_utilities/openapi.py
@@ -7,26 +7,31 @@
import glob
import urllib.request
from cloudharness_utilities import HERE
+from cloudharness_utilities.utils import copymergedir, replaceindir, movedircontent, replace_in_file, to_python_module
import logging
CODEGEN = os.path.join(HERE, 'bin', 'openapi-generator-cli.jar')
APPLICATIONS_SRC_PATH = os.path.join('applications')
LIB_NAME = 'cloudharness_cli'
-OPENAPI_GEN_URL = 'https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/4.3.0/openapi-generator-cli-4.3.0.jar'
+OPENAPI_GEN_URL = 'https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/5.0.0/openapi-generator-cli-5.0.0.jar'
def generate_server(app_path):
+ get_dependencies()
openapi_dir = os.path.join(app_path, 'api')
openapi_file = glob.glob(os.path.join(openapi_dir, '*.yaml'))[0]
- command = f"java -jar {CODEGEN} generate -i {openapi_file} -g python-flask -o {app_path}/server -c {openapi_dir}/config.json"
+ out_name = f"backend" if not os.path.exists(f"{app_path}/server") else f"server"
+ out_path = f"{app_path}/{out_name}"
+ command = f"java -jar {CODEGEN} generate -i {openapi_file} -g python-flask -o {out_path} -c {openapi_dir}/config.json"
os.system(command)
def generate_python_client(module, openapi_file, client_src_path, lib_name=LIB_NAME):
+ get_dependencies()
config_path = os.path.join(os.path.dirname(openapi_file), 'config.json')
- module = module.replace('-', '_')
+ module = to_python_module(module)
with open(config_path, 'w') as f:
f.write(json.dumps(dict(packageName=f"{lib_name}.{module}")))
command = f"java -jar {CODEGEN} generate " \
@@ -37,6 +42,18 @@ def generate_python_client(module, openapi_file, client_src_path, lib_name=LIB_N
os.system(command)
+def generate_ts_client(openapi_file):
+ config_path = os.path.join(os.path.dirname(openapi_file), 'config.json')
+ out_dir = f"{os.path.dirname(os.path.dirname(openapi_file))}/frontend/src/rest"
+ command = f"java -jar {CODEGEN} generate " \
+ f"-i {openapi_file} " \
+ f"-g typescript-axios " \
+ f"-o {out_dir}"
+ os.system(command)
+
+ replaceindir(out_dir, "http://localhost", '')
+
+
def get_dependencies():
"""
Checks if java is installed
@@ -50,7 +67,7 @@ def get_dependencies():
sys.exit('java not found')
if not os.path.exists(CODEGEN):
- logging.warning("Code generator client not found \n")
+ logging.warning("Code generator client not found: downloading \n")
cdir = os.path.dirname(CODEGEN)
if not os.path.exists(cdir):
os.makedirs(cdir)
diff --git a/utilities/cloudharness_utilities/utils.py b/utilities/cloudharness_utilities/utils.py
index 0afb13ba..566bc6e7 100644
--- a/utilities/cloudharness_utilities/utils.py
+++ b/utilities/cloudharness_utilities/utils.py
@@ -1,13 +1,19 @@
import glob
import subprocess
import os
+import json
import collections
import oyaml as yaml
import shutil
import logging
+import fileinput
from .constants import HERE, NEUTRAL_PATHS, DEPLOYMENT_CONFIGURATION_PATH, BASE_IMAGES_PATH, STATIC_IMAGES_PATH, \
- APPS_PATH, BUILD_FILENAMES
+ APPS_PATH, BUILD_FILENAMES, EXCLUDE_PATHS
+
+REPLACE_TEXT_FILES_EXTENSIONS = (
+ '.js', '.md', '.py', '.js', '.ts', '.tsx', '.txt', 'Dockerfile', 'yaml', 'json', '.ejs'
+)
def app_name_from_path(dockerfile_path):
@@ -18,9 +24,13 @@ def get_sub_paths(base_path):
return tuple(path for path in glob.glob(base_path + "/*") if os.path.isdir(path))
-def find_dockerfiles_paths(base_directory):
+def find_file_paths(base_directory, file_name):
return tuple(os.path.dirname(path).replace(os.path.sep, "/") for path in
- glob.glob(f"{base_directory}/**/Dockerfile", recursive=True))
+ glob.glob(f"{base_directory}/**/{file_name}", recursive=True))
+
+
+def find_dockerfiles_paths(base_directory):
+ return find_file_paths(base_directory, 'Dockerfile')
def get_parent_app_name(app_relative_path):
@@ -28,11 +38,7 @@ def get_parent_app_name(app_relative_path):
def get_image_name(app_name, base_name=None):
- return base_name + '-' + app_name if base_name else app_name
-
-
-def get_image_name_from_dockerfile_path(self, dockerfile_path, base_name):
- return get_image_name(os.path.basename(os.path.dirname(dockerfile_path)), base_name)
+ return base_name + '/' + app_name if base_name else app_name
def env_variable(name, value):
@@ -41,57 +47,168 @@ def env_variable(name, value):
def get_cluster_ip():
out = subprocess.check_output(['kubectl', 'cluster-info'], timeout=10).decode("utf-8")
- print(type(out))
ip = out.split('\n')[0].split('://')[1].split(':')[0]
return ip
-def get_template(yaml_path):
- with open(os.path.join(HERE, DEPLOYMENT_CONFIGURATION_PATH, os.path.basename(yaml_path))) as f:
- dict_template = yaml.safe_load(f)
+def robust_load_json(json_path):
+ """
+ Supports json with // comments
+ """
+ try:
+ with open(json_path) as f:
+ return json.load(f)
+ except:
+ with open(json_path) as f:
+ return json.loads("".join(line for line in f if "//" not in line))
+
+
+def get_json_template(json_path, base_default=False):
+ default_template_path = os.path.join(HERE, DEPLOYMENT_CONFIGURATION_PATH, os.path.basename(json_path))
+ dict_template = {}
+ if base_default and os.path.exists(default_template_path):
+ dict_template = robust_load_json(default_template_path)
+ if os.path.exists(json_path):
+ override_tpl = robust_load_json(json_path)
+ if override_tpl:
+ dict_template = dict_merge(dict_template or {}, override_tpl)
+ return dict_template or {}
+
+
+def get_template(yaml_path, base_default=False):
+ default_template_path = os.path.join(HERE, DEPLOYMENT_CONFIGURATION_PATH, os.path.basename(yaml_path))
+ dict_template = {}
+ if base_default and os.path.exists(default_template_path):
+ with open(default_template_path) as f:
+ dict_template = yaml.safe_load(f)
if os.path.exists(yaml_path):
with open(yaml_path) as f:
override_tpl = yaml.safe_load(f)
if override_tpl:
- dict_template = dict_merge(dict_template, override_tpl)
- return dict_template
+ dict_template = dict_merge(dict_template or {}, override_tpl)
+ return dict_template or {}
def file_is_yaml(fname):
return fname[-4:] == 'yaml' or fname[-3:] == 'yml'
+def replaceindir(root_src_dir, source, replace):
+ """
+ Does copy and merge (shutil.copytree requires that the destination does not exist)
+ :param root_src_dir:
+ :param root_dst_dir:
+ :return:
+ """
+ logging.info('Replacing in directory %s to %s', source, replace)
+ for src_dir, dirs, files in os.walk(root_src_dir):
+ if any(path in src_dir for path in EXCLUDE_PATHS):
+ continue
+
+ for dirname in dirs:
+ if source in dirname:
+ dirpath = os.path.join(src_dir, dirname)
+ movedircontent(dirpath, dirpath.replace(source, to_python_module(replace)))
+
+ for src_dir, dirs, files in os.walk(root_src_dir):
+ for file_ in files:
+ if not any(file_.endswith(ext) for ext in REPLACE_TEXT_FILES_EXTENSIONS):
+ continue
+
+ src_file = os.path.join(src_dir, file_)
+ replace_in_file(src_file, source, replace)
+
+
+def replace_in_file(src_file, source, replace):
+ if src_file.endswith('.py') or os.path.basename(src_file) == 'Dockerfile':
+ replace = to_python_module(replace)
+ with fileinput.FileInput(src_file, inplace=True) as file:
+ try:
+ for line in file:
+ print(line.replace(source, replace), end='')
+ except UnicodeDecodeError:
+ pass
+
+
+def copymergedir(root_src_dir, root_dst_dir):
+ """
+ Does copy and merge (shutil.copytree requires that the destination does not exist)
+ :param root_src_dir:
+ :param root_dst_dir:
+ :return:
+ """
+ logging.info('Copying directory %s to %s', root_src_dir, root_dst_dir)
+ for src_dir, dirs, files in os.walk(root_src_dir):
+
+ dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
+ if not os.path.exists(dst_dir):
+ os.makedirs(dst_dir)
+ for file_ in files:
+ src_file = os.path.join(src_dir, file_)
+ dst_file = os.path.join(dst_dir, file_)
+ if os.path.exists(dst_file):
+ os.remove(dst_file)
+ try:
+ shutil.copy(src_file, dst_dir)
+ except:
+ logging.warning("Error copying file %s to %s.", src_file, dst_dir)
+
+
+def movedircontent(root_src_dir, root_dst_dir):
+ """
+ Does copy and merge (shutil.copytree requires that the destination does not exist)
+ :param root_src_dir:
+ :param root_dst_dir:
+ :return:
+ """
+ logging.info('Moving directory content from %s to %s', root_src_dir, root_dst_dir)
+ for src_dir, dirs, files in os.walk(root_src_dir):
+ dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
+ if not os.path.exists(dst_dir):
+ os.makedirs(dst_dir)
+ for file_ in files:
+ src_file = os.path.join(src_dir, file_)
+ dst_file = os.path.join(dst_dir, file_)
+
+ try:
+ shutil.move(src_file, os.path.join(dst_dir, os.path.basename(src_file)))
+ except:
+ logging.warning("Error moving file %s to %s.", src_file, dst_dir, exc_info=True)
+ shutil.rmtree(root_src_dir)
+
+
def merge_configuration_directories(source, dest):
if not os.path.exists(source):
return
if not os.path.exists(dest):
- shutil.copytree(source, dest)
+ shutil.copytree(source, dest, ignore=shutil.ignore_patterns(*EXCLUDE_PATHS))
return
- for fname in glob.glob(source + "/*"):
- frel = os.path.relpath(fname, start=source)
- fdest = os.path.join(dest, frel)
-
- if os.path.basename(fname) in BUILD_FILENAMES:
- continue
-
- if os.path.isdir(fname):
- merge_configuration_directories(fname, fdest)
+ for src_dir, dirs, files in os.walk(source):
+ if any(path in src_dir for path in EXCLUDE_PATHS):
continue
-
- if not os.path.exists(fdest):
- shutil.copy2(fname, fdest)
- elif file_is_yaml(fname):
-
- try:
- merge_yaml_files(fname, fdest)
- logging.info(f"Merged/overridden file content of {fdest} with {fname}")
- except yaml.YAMLError as e:
- logging.warning(f"Overwriting file {fdest} with {fname}")
- shutil.copy2(fname, fdest)
- else:
- logging.warning(f"Overwriting file {fdest} with {fname}")
- shutil.copy2(fname, fdest)
+ dst_dir = src_dir.replace(source, dest, 1)
+ if not os.path.exists(dst_dir):
+ os.makedirs(dst_dir)
+ for fname in files:
+ if fname in BUILD_FILENAMES:
+ continue
+ fpath = os.path.join(src_dir, fname)
+ frel = os.path.relpath(fpath, start=source)
+ fdest = os.path.join(dest, frel)
+ if not os.path.exists(fdest):
+ shutil.copy2(fpath, fdest)
+ elif file_is_yaml(fpath):
+
+ try:
+ merge_yaml_files(fpath, fdest)
+ logging.info(f"Merged/overridden file content of {fdest} with {fpath}")
+ except yaml.YAMLError as e:
+ logging.warning(f"Overwriting file {fdest} with {fpath}")
+ shutil.copy2(fpath, fdest)
+ else:
+ logging.warning(f"Overwriting file {fdest} with {fpath}")
+ shutil.copy2(fpath, fdest)
def merge_yaml_files(fname, fdest):
@@ -179,4 +296,8 @@ def merge_app_directories(root_paths, destination) -> None:
merge_configuration_directories(os.path.join(rpath, 'client'),
os.path.join(destination, 'client'))
merge_configuration_directories(os.path.join(rpath, 'deployment-configuration'),
- os.path.join(destination, 'deployment-configuration'))
\ No newline at end of file
+ os.path.join(destination, 'deployment-configuration'))
+
+
+def to_python_module(name):
+ return name.replace('-', '_')
diff --git a/utilities/harness-application b/utilities/harness-application
index b5daec5e..68e34962 100644
--- a/utilities/harness-application
+++ b/utilities/harness-application
@@ -3,12 +3,19 @@
import sys
import os
import shutil
+import re
from cloudharness_utilities import HERE
+from cloudharness_utilities.constants import APPLICATION_TEMPLATE_PATH
import cloudharness_utilities.openapi
-from cloudharness_utilities.openapi import generate_server, APPLICATIONS_SRC_PATH
+from cloudharness_utilities.openapi import generate_server, APPLICATIONS_SRC_PATH, generate_ts_client
+from cloudharness_utilities.utils import merge_configuration_directories, replaceindir, replace_in_file, \
+ to_python_module
-APPLICATION_TEMPLATE = os.path.join(HERE, 'application-template')
+# Only allow lowercased alphabetical characters separated by "-".
+name_pattern = re.compile("[a-z]+((-)?[a-z])?")
+
+PLACEHOLDER = '__APP_NAME__'
if __name__ == "__main__":
import argparse
@@ -17,15 +24,46 @@ if __name__ == "__main__":
description='Creates a new Application.')
parser.add_argument('name', metavar='name', type=str,
help='Application name')
+ parser.add_argument('-t', '--template', dest='templates', action="append", default=['base', 'server'],
+ help="""Add a template name.
+
+ Available templates:
+ - base (backend flask app based on openapi, always included)
+ - webapp (webapp including backend and frontend)
+ - db-postgres
+ - db-neo4j
+ - db-mongo
+ """)
args, unknown = parser.parse_known_args(sys.argv[1:])
if unknown:
print('There are unknown args. Make sure to call the script with the accepted args. Try --help')
print(f'unknown: {unknown}')
- else:
- app_path = os.path.join(APPLICATIONS_SRC_PATH, args.name)
- shutil.copytree(APPLICATION_TEMPLATE, app_path) # TODO replace the name inside the template
- generate_server(app_path)
+ exit(1)
+
+ try:
+ match = name_pattern.match(args.name)
+ if not match:
+ print("Invalid application name")
+ print(
+ f"Application name must start and end with lowercased alphabetical characters and may contain '-' as separator. Used expression: '{name_pattern.pattern}'")
+ exit(1)
+ except re.error:
+ print("Invalid regex")
+ exit(1)
+ app_path = os.path.join(APPLICATIONS_SRC_PATH, args.name)
+ for template_name in args.templates:
+ if template_name == 'server':
+ generate_server(app_path)
+ for base_path in (HERE, os.getcwd()):
+ template_path = os.path.join(base_path, APPLICATION_TEMPLATE_PATH, template_name)
+ if os.path.exists(template_path):
+ merge_configuration_directories(template_path, app_path)
+ replace_in_file(os.path.join(app_path, 'api/config.json'), PLACEHOLDER, to_python_module(args.name))
+ replaceindir(app_path, PLACEHOLDER, args.name)
+ if 'webapp' in args.templates:
+ os.remove(os.path.join(app_path, 'backend', 'Dockerfile'))
+ generate_ts_client(openapi_file=os.path.join(app_path, 'api/openapi.yaml'))
diff --git a/utilities/harness-codefresh b/utilities/harness-codefresh
deleted file mode 100644
index a58fb841..00000000
--- a/utilities/harness-codefresh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import os
-
-from cloudharness_utilities.codefresh import create_codefresh_deployment_scripts
-from cloudharness_utilities.helm import create_helm_chart
-
-
-HERE = os.path.dirname(os.path.realpath(__file__)).replace(os.path.sep, '/')
-ROOT = os.path.dirname(HERE).replace(os.path.sep, '/')
-
-if __name__ == "__main__":
- import argparse
-
- parser = argparse.ArgumentParser(
- description='Walk filesystem inside ./applications and define build and deploy scripts.')
- parser.add_argument('paths', metavar='paths', default=[ROOT], type=str, nargs='*',
- help='Base paths to start looking for applications. The paths will be processed '
- 'in the given order so determining the build and overriding precedence.')
- parser.add_argument('-i', '--include', dest='include', action="append", default=[],
- help='Specify the applications to include and exclude the rest. '
- 'Omit to build images for all Docker files.')
-
- args, unknown = parser.parse_known_args(sys.argv[1:])
-
- if unknown:
- print('There are unknown args. Make sure to call the script with the accepted args. Try --help')
- print(f'unknown: {unknown}')
- else:
- create_codefresh_deployment_scripts(args.paths, include=args.include)
-
diff --git a/utilities/harness-deployment b/utilities/harness-deployment
index b20ef64b..9acd9fa2 100644
--- a/utilities/harness-deployment
+++ b/utilities/harness-deployment
@@ -5,7 +5,8 @@ import os
from cloudharness_utilities.build import Builder
from cloudharness_utilities.utils import merge_app_directories
-from cloudharness_utilities.helm import create_helm_chart, hosts_info
+from cloudharness_utilities.helm import create_helm_chart, hosts_info, deploy
+from cloudharness_utilities.dev_utils import create_skaffold_configuration, create_vscode_debug_configuration
from cloudharness_utilities.codefresh import create_codefresh_deployment_scripts
HERE = os.path.dirname(os.path.realpath(__file__)).replace(os.path.sep, '/')
@@ -28,8 +29,8 @@ if __name__ == "__main__":
parser.add_argument('-t', '--tag', dest='tag', action="store", default='latest',
help='Add a tag with the current version (default `latest`)')
- parser.add_argument('-n', '--namespace', dest='namespace', action="store", default='default',
- help='Specify the namespace of the deployment (default `default`)')
+ parser.add_argument('-n', '--namespace', dest='namespace', action="store", default=None,
+ help='Specify the namespace of the deployment (default taken from values.yaml)')
parser.add_argument('-r', '--registry', dest='registry', action="store", default='',
help='Specify image registry prefix')
@@ -48,14 +49,17 @@ if __name__ == "__main__":
help='Specify for local deployments info and setup')
parser.add_argument('-u', '--disable-security', dest='unsecured', action="store_true",
help='Disable secured gatekeepers access')
- parser.add_argument('-e', '--exclude', dest='exclude', action="append", default=(),
+ parser.add_argument('-ex', '--exclude', dest='exclude', action="append", default=[],
+ help='Specify application to exclude from the deployment')
+ parser.add_argument('-e', '--env', dest='env', action="store", default=None,
help='Specify application to exclude from the deployment')
-
parser.add_argument('-m', '--merge', dest='merge', action="store", default=None,
help='Merge application folders and build in the given directory')
parser.add_argument('-dtls', '--disable-tls', dest='no_tls', action="store_true",
help='Disable tls (serve on http)')
+ parser.add_argument('--deploy', dest='deploy', action="store_true",
+ help='Deploy helm chart')
args, unknown = parser.parse_known_args(sys.argv[1:])
@@ -65,14 +69,9 @@ if __name__ == "__main__":
print(f'unknown: {unknown}')
else:
- builder = Builder(root_paths, args.include, tag=args.tag, registry=args.registry, interactive=args.build_interactive,
- exclude=args.exclude, namespace=args.namespace, domain=args.domain)
-
if args.merge:
- merge_app_directories(builder.root_paths, destination=args.merge)
- builder.root_paths = [args.merge]
- if args.build or args.build_interactive:
- builder.run()
+ merge_app_directories(root_paths, destination=args.merge)
+ root_paths = [args.merge]
values_manual_deploy = create_helm_chart(
root_paths,
@@ -85,7 +84,32 @@ if __name__ == "__main__":
exclude=args.exclude,
include=args.include,
registry_secret=args.registry_secret,
- tls=not args.no_tls
+ tls=not args.no_tls,
+ env=args.env,
+ namespace=args.namespace
)
- create_codefresh_deployment_scripts(builder.root_paths, include=args.include)
+
+ build_included = [app['harness']['name'] for app in values_manual_deploy['apps'].values() if 'harness' in app]
+
+ create_codefresh_deployment_scripts(root_paths, include=build_included) # LEGACY
+ create_codefresh_deployment_scripts(root_paths, include=build_included,
+ template_name='codefresh-template-dev.yaml',
+ out_filename="codefresh-dev.yaml")
+ create_codefresh_deployment_scripts(root_paths, include=build_included,
+ template_name='codefresh-template-prod.yaml',
+ out_filename="codefresh-prod.yaml")
+
+ create_skaffold_configuration(root_paths, values_manual_deploy)
+ create_vscode_debug_configuration([os.path.join(os.getcwd(), path) for path in args.paths],
+ values_manual_deploy)
+
+ if args.build or args.build_interactive:
+ builder = Builder(root_paths, build_included, tag=args.tag, registry=args.registry,
+ interactive=args.build_interactive,
+ exclude=args.exclude, namespace=args.namespace, domain=args.domain)
+ builder.run()
+
hosts_info(values_manual_deploy)
+
+ if args.deploy:
+ deploy(args.namespace, args.output_path)
diff --git a/utilities/harness-generate b/utilities/harness-generate
index df835871..07fe985b 100644
--- a/utilities/harness-generate
+++ b/utilities/harness-generate
@@ -6,7 +6,9 @@ import shutil
import sys
import logging
-from cloudharness_utilities.openapi import LIB_NAME, generate_python_client, generate_server, get_dependencies
+from cloudharness_utilities.openapi import LIB_NAME, generate_python_client, generate_server, get_dependencies, \
+ generate_ts_client
+from cloudharness_utilities.utils import copymergedir
HERE = os.path.dirname(os.path.realpath(__file__))
ROOT = os.path.dirname(HERE)
@@ -16,43 +18,21 @@ def get_openapi_file_paths(root_path):
return [path for path in glob.glob(root_path + '/applications/*/api/*.yaml')]
-def get_modules(openapi_files):
+def get_application_paths(openapi_files):
return [os.path.basename(os.path.dirname(os.path.dirname(path))) for path in openapi_files]
-def generate_servers(root_path):
+def generate_servers(root_path, interactive=False):
"""
Generates server stubs
"""
openapi_files = get_openapi_file_paths(root_path)
- modules = get_modules(openapi_files)
+ modules = get_application_paths(openapi_files)
for i in range(len(modules)):
- openapi_file = openapi_files[i]
- application_root = os.path.dirname(os.path.dirname(openapi_file))
- generate_server(application_root)
-
-
-def copymergedir(root_src_dir, root_dst_dir):
- """
- Does copy and merge (shutil.copytree requires that the destination does not exist)
- :param root_src_dir:
- :param root_dst_dir:
- :return:
- """
- logging.info('Copying directory %s to %s', root_src_dir, root_dst_dir)
- for src_dir, dirs, files in os.walk(root_src_dir):
- dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
- if not os.path.exists(dst_dir):
- os.makedirs(dst_dir)
- for file_ in files:
- src_file = os.path.join(src_dir, file_)
- dst_file = os.path.join(dst_dir, file_)
- if os.path.exists(dst_file):
- os.remove(dst_file)
- try:
- shutil.copy(src_file, dst_dir)
- except:
- logging.warning("Error copying file %s to %s.", src_file, dst_dir)
+ if not interactive or input("Do you want to generate " + openapi_files[i] + "? [Y/n]").upper() != 'N':
+ openapi_file = openapi_files[i]
+ application_root = os.path.dirname(os.path.dirname(openapi_file))
+ generate_server(application_root)
def aggregate_packages(client_src_path, lib_name=LIB_NAME):
@@ -131,41 +111,44 @@ def aggregate_packages(client_src_path, lib_name=LIB_NAME):
shutil.rmtree(MODULE_TMP_PATH)
-def generate_clients(root_path, client_lib_name=LIB_NAME):
+def generate_clients(root_path, client_lib_name=LIB_NAME, interactive=False):
"""
Generates client stubs
"""
+ if interactive and input("Do you want to generate client libraries? [Y/n]").upper() == 'N':
+ return
+
openapi_files = get_openapi_file_paths(root_path)
- modules = get_modules(openapi_files)
- client_src_path = os.path.join(root_path, 'client', client_lib_name)
- for i in range(len(modules)):
- module = modules[i]
+ applications = get_application_paths(openapi_files)
+
+ client_src_path = os.path.join(root_path, 'libraries/client', client_lib_name)
+ for i in range(len(applications)):
+ app_name = applications[i]
openapi_file = openapi_files[i]
- generate_python_client(module, openapi_file, client_src_path, lib_name=client_lib_name)
+ app_dir = os.path.dirname(os.path.dirname(openapi_file))
+ generate_python_client(app_name, openapi_file, client_src_path, lib_name=client_lib_name)
+ if os.path.exists(os.path.join(app_dir, 'frontend')):
+ generate_ts_client(openapi_file)
aggregate_packages(client_src_path, client_lib_name)
if __name__ == "__main__":
-
import argparse
parser = argparse.ArgumentParser(
- description='Walk filesystem inside ./applications and define build and deploy scripts.')
+ description='Walk filesystem inside ./applications create application scaffolding.')
parser.add_argument('path', metavar='path', default=ROOT, type=str,
help='Base path of the application.')
- parser.add_argument('-nc', '--no-client', dest='client', action="store_false",
- help='Specify for local deployments info and setup')
- parser.add_argument('-ns', '--no-server', dest='server', action="store_false",
- help='Specify for local deployments info and setup')
parser.add_argument('-cn', '--client-name', dest='client_name', action="store", default=LIB_NAME,
help='Specify image registry prefix')
+ parser.add_argument('-i', '--interactive', dest='interactive', action="store_true",
+ help='Asks before generate')
args, unknown = parser.parse_known_args(sys.argv[1:])
root_path = os.path.join(os.getcwd(), args.path) if not os.path.isabs(args.path) else args.path
get_dependencies()
- if args.server:
- generate_servers(root_path)
- if args.client:
- generate_clients(root_path, args.client_name)
+ generate_servers(root_path, interactive=args.interactive)
+
+ generate_clients(root_path, args.client_name, interactive=args.interactive)
diff --git a/utilities/setup.py b/utilities/setup.py
index d8d78e06..ff932741 100644
--- a/utilities/setup.py
+++ b/utilities/setup.py
@@ -12,7 +12,7 @@
NAME = "cloudharness-utilities"
-VERSION = "0.2.0"
+VERSION = "0.3.0"
# To install the library, run the following
#
# python setup.py install
@@ -37,7 +37,7 @@
install_requires=REQUIREMENTS,
packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
include_package_data=True,
- scripts=['harness-codefresh', 'harness-deployment', 'harness-generate', 'harness-application'],
+ scripts=['harness-deployment', 'harness-generate', 'harness-application'],
long_description="""\
MetaCell Neuroscience Platform - CloudHarness deploy library
"""
diff --git a/utilities/test-requirements.txt b/utilities/test-requirements.txt
new file mode 100644
index 00000000..e2fead49
--- /dev/null
+++ b/utilities/test-requirements.txt
@@ -0,0 +1,8 @@
+coverage>=4.0.3
+nose>=1.3.7
+pluggy>=0.3.1
+py>=1.4.31
+randomize>=0.13
+pytest>=5.0.0
+pytest-cov
+-e .
diff --git a/utilities/tests/resources/applications/accounts/deploy/resources/aresource.txt b/utilities/tests/resources/applications/accounts/deploy/resources/aresource.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/utilities/tests/resources/applications/accounts/deploy/values-dev.yaml b/utilities/tests/resources/applications/accounts/deploy/values-dev.yaml
new file mode 100644
index 00000000..2b9fefa6
--- /dev/null
+++ b/utilities/tests/resources/applications/accounts/deploy/values-dev.yaml
@@ -0,0 +1 @@
+a: dev
\ No newline at end of file
diff --git a/utilities/tests/resources/applications/accounts/deploy/values.yaml b/utilities/tests/resources/applications/accounts/deploy/values.yaml
new file mode 100644
index 00000000..2957614c
--- /dev/null
+++ b/utilities/tests/resources/applications/accounts/deploy/values.yaml
@@ -0,0 +1,5 @@
+a: b
+autodeploy: overridden
+harness:
+ deployment:
+ port: overridden
\ No newline at end of file
diff --git a/utilities/tests/resources/applications/legacy/deploy/values.yaml b/utilities/tests/resources/applications/legacy/deploy/values.yaml
new file mode 100644
index 00000000..2cf7ff6a
--- /dev/null
+++ b/utilities/tests/resources/applications/legacy/deploy/values.yaml
@@ -0,0 +1,3 @@
+autodeploy: legacy
+a: b
+name: "I'm useless"
\ No newline at end of file
diff --git a/utilities/tests/resources/applications/myapp/Dockerfile b/utilities/tests/resources/applications/myapp/Dockerfile
new file mode 100644
index 00000000..e69de29b
diff --git a/utilities/tests/resources/applications/myapp/deploy/resources/aresource.txt b/utilities/tests/resources/applications/myapp/deploy/resources/aresource.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/utilities/tests/resources/applications/myapp/deploy/templates/mytemplate.yaml b/utilities/tests/resources/applications/myapp/deploy/templates/mytemplate.yaml
new file mode 100644
index 00000000..e69de29b
diff --git a/utilities/tests/resources/applications/myapp/deploy/values.yaml b/utilities/tests/resources/applications/myapp/deploy/values.yaml
new file mode 100644
index 00000000..2aaee442
--- /dev/null
+++ b/utilities/tests/resources/applications/myapp/deploy/values.yaml
@@ -0,0 +1,7 @@
+harness:
+ name: "I'm useless"
+ subdomain: mysubdomain
+ dependencies:
+ soft:
+ - legacy
+a: b
diff --git a/utilities/tests/resources/deployment-configuration/value-template.yaml b/utilities/tests/resources/deployment-configuration/value-template.yaml
new file mode 100644
index 00000000..45a27d06
--- /dev/null
+++ b/utilities/tests/resources/deployment-configuration/value-template.yaml
@@ -0,0 +1 @@
+common: True
\ No newline at end of file
diff --git a/utilities/tests/resources/deployment-configuration/values-template-dev.yaml b/utilities/tests/resources/deployment-configuration/values-template-dev.yaml
new file mode 100644
index 00000000..44673bfe
--- /dev/null
+++ b/utilities/tests/resources/deployment-configuration/values-template-dev.yaml
@@ -0,0 +1,3 @@
+a: dev
+database:
+ auto: false
\ No newline at end of file
diff --git a/utilities/tests/resources/deployment-configuration/values-template.yaml b/utilities/tests/resources/deployment-configuration/values-template.yaml
new file mode 100644
index 00000000..b6888f2f
--- /dev/null
+++ b/utilities/tests/resources/deployment-configuration/values-template.yaml
@@ -0,0 +1,5 @@
+mainapp: myapp
+domain: myapp.local
+a: b
+database:
+ auto: true
\ No newline at end of file
diff --git a/utilities/tests/test_helm.py b/utilities/tests/test_helm.py
new file mode 100644
index 00000000..df3d94ae
--- /dev/null
+++ b/utilities/tests/test_helm.py
@@ -0,0 +1,72 @@
+import shutil
+import yaml
+
+from cloudharness_utilities.helm import *
+
+HERE = os.path.dirname(os.path.realpath(__file__))
+RESOURCES = os.path.join(HERE, 'resources')
+OUT = './deployment'
+CLOUDHARNESS_ROOT = os.path.dirname(os.path.dirname(HERE))
+
+
+def test_collect_helm_values():
+ values = create_helm_chart([CLOUDHARNESS_ROOT, RESOURCES], output_path=OUT, include=['samples', 'myapp'],
+ exclude=['events'], domain="my.local",
+ namespace='test', env='dev', local=False, tag=1, registry='reg')
+
+ # Auto values
+ assert values[KEY_APPS]['myapp'][KEY_HARNESS]['deployment']['image'] == 'reg/myapp:1'
+ assert values[KEY_APPS]['myapp'][KEY_HARNESS]['name'] == 'myapp'
+ assert values[KEY_APPS]['legacy'][KEY_HARNESS]['name'] == 'legacy'
+ assert values[KEY_APPS]['accounts'][KEY_HARNESS]['deployment']['image'] == 'reg/accounts:1'
+
+ # First level include apps
+ assert 'samples' in values[KEY_APPS]
+ assert 'myapp' in values[KEY_APPS]
+
+ # Not included
+ assert 'jupyterhub' not in values[KEY_APPS]
+
+ # Dependency include first level
+ assert 'accounts' in values[KEY_APPS]
+ assert 'legacy' in values[KEY_APPS]
+
+ # Dependency include second level
+ assert 'argo' in values[KEY_APPS]
+
+ # Explicit exclude overrides include
+ assert 'events' not in values[KEY_APPS]
+
+ # Base values kept
+ assert values[KEY_APPS]['accounts'][KEY_HARNESS]['subdomain'] == 'accounts'
+
+ # Defaults
+ assert 'service' in values[KEY_APPS]['legacy'][KEY_HARNESS]
+ assert 'common' in values[KEY_APPS]['legacy']
+ assert 'common' in values[KEY_APPS]['accounts']
+ # Values overriding
+ assert values[KEY_APPS]['accounts'][KEY_HARNESS]['deployment']['port'] == 'overridden'
+
+ # Environment specific overriding
+ assert values[KEY_APPS]['accounts']['a'] == 'dev'
+ assert values['a'] == 'dev'
+ assert values['database']['auto'] == False
+
+ # legacy reading
+ assert values[KEY_APPS]['accounts'][KEY_HARNESS]['deployment']['auto'] == 'overridden'
+ assert values[KEY_APPS]['legacy'][KEY_HARNESS]['deployment']['auto'] == 'legacy'
+
+ helm_path = os.path.join(OUT, HELM_CHART_PATH)
+
+ def exists(*args):
+ return os.path.exists(os.path.join(*args))
+
+ # Check files
+ assert exists(helm_path)
+ assert exists(helm_path, 'values.yaml')
+ assert exists(helm_path, 'resources/accounts/realm.json')
+ assert exists(helm_path, 'resources/accounts/aresource.txt')
+ assert exists(helm_path, 'resources/myapp/aresource.txt')
+ assert exists(helm_path, 'templates/myapp/mytemplate.yaml')
+
+ shutil.rmtree(OUT)
diff --git a/utilities/tests/test_utils.py b/utilities/tests/test_utils.py
index f9914d9c..d831eace 100644
--- a/utilities/tests/test_utils.py
+++ b/utilities/tests/test_utils.py
@@ -5,12 +5,13 @@
HERE = os.path.dirname(os.path.realpath(__file__)).replace(os.path.sep, '/')
+
def test_image_name_from_docker_path():
assert app_name_from_path("a") == 'a'
assert app_name_from_path("a/b") == 'a-b'
assert app_name_from_path("a/src/b") == 'a-b'
assert app_name_from_path("a/tasks/b") == 'a-b'
- assert app_name_from_path("cloudharness/a/b") == 'a-b'
+ assert app_name_from_path("cloudharness/a/b") == 'cloudharness-a-b'
def test_merge_configuration_directories():
@@ -26,7 +27,6 @@ def test_merge_configuration_directories():
assert os.path.exists(os.path.join(res_path, "b.yaml"))
assert os.path.exists(os.path.join(res_path, "c.yaml"))
-
assert os.path.exists(os.path.join(res_path, "sub", "a.yaml"))
assert os.path.exists(os.path.join(res_path, "sub", "b.yaml"))
assert os.path.exists(os.path.join(res_path, "sub", "c.yaml"))
@@ -38,7 +38,6 @@ def test_merge_configuration_directories():
assert a['b']['bb'] == 'bb'
assert a['b']['bc'] == 'bc'
-
with open(os.path.join(res_path, "sub", "a.yaml")) as f:
a = yaml.safe_load(f)
assert a['a'] == 'a1'
diff --git a/utilities/tox.ini b/utilities/tox.ini
new file mode 100644
index 00000000..f517c410
--- /dev/null
+++ b/utilities/tox.ini
@@ -0,0 +1,9 @@
+[tox]
+envlist = py3
+
+[testenv]
+deps=-r{toxinidir}/test-requirements.txt
+
+commands=
+ coverage run --source cloudharness_utilities -m pytest -v
+ coverage report -m
\ No newline at end of file