From 9663cf5f5d4a845a152933c33c47df393cb9b0db Mon Sep 17 00:00:00 2001 From: shaiic-pai Date: Tue, 29 Sep 2020 14:29:12 +0800 Subject: [PATCH 1/2] alert manager based gpu utilization enhancement --- README.md | 4 +- .../services-configuration.yaml.template | 52 +- .../paiService/service_management_start.py | 4 - docs/manual/cluster-admin/README.md | 8 +- .../cluster-admin/how-to-customize-alerts.md | 165 + docs/manual/cluster-admin/troubleshooting.md | 106 +- .../services-configuration.yaml | 20 +- mkdocs.yml | 3 + src/alert-manager/.gitignore | 2 + .../build/alert-handler.common.dockerfile | 31 + src/alert-manager/config/alert-manager.md | 106 +- src/alert-manager/config/alert-manager.yaml | 8 + src/alert-manager/config/alert_manager.py | 39 +- .../deploy/alert-configmap.yaml.template | 31 - .../alert-manager-configmap.yaml.template | 93 + ...=> alert-manager-deployment.yaml.template} | 40 +- .../deploy/alert-templates/pai.tmpl | 128 - src/alert-manager/deploy/refresh.sh | 4 +- src/alert-manager/deploy/service.yaml | 5 +- .../deploy/{start.sh.template => start.sh} | 10 +- src/alert-manager/deploy/stop.sh | 3 - .../src/alert-handler/.editorconfig | 9 + .../src/alert-handler/.eslintrc.js | 36 + .../src/alert-handler/common/config.js | 23 + .../src/alert-handler/common/logger.js | 43 + .../src/alert-handler/controllers/job.js | 111 + .../src/alert-handler/controllers/mail.js | 207 ++ .../emails/general-templates/html.ejs | 166 + .../emails/general-templates/subject.ejs | 7 + src/alert-manager/src/alert-handler/index.js | 38 + .../src/alert-handler/package.json | 50 + .../src/alert-handler/prettier.config.js | 8 + .../src/alert-handler/routes/actions.js | 44 + src/alert-manager/src/alert-handler/yarn.lock | 3102 +++++++++++++++++ src/job-exporter/src/collector.py | 39 +- src/job-exporter/src/docker_inspect.py | 13 +- .../test/data/docker_inspect_amd.json | 1 + .../docker_inspect_kube_launcher_task.json | 1 + .../test/data/docker_inspect_sample.json | 1 + .../test/data/inspect_result_bug_fix.json | 1 + src/job-exporter/test/test_collector.py | 4 +- src/job-exporter/test/test_docker_inspect.py | 9 +- src/prometheus/config/prometheus.md | 6 +- .../deploy/alerting/customized.rules.template | 20 + src/prometheus/deploy/alerting/jobs.rules | 25 +- .../deploy/prometheus-configmap.yaml.template | 5 +- src/prometheus/deploy/service.yaml | 1 + src/rest-server/build/build-pre.sh | 1 + src/rest-server/src/models/v2/job/k8s.js | 124 +- .../src/models/v2/job/runtime-env.js | 3 +- src/tools/tests/test_alert_operator.py | 6 +- 51 files changed, 4655 insertions(+), 311 deletions(-) create mode 100755 docs/manual/cluster-admin/how-to-customize-alerts.md create mode 100755 src/alert-manager/.gitignore create mode 100755 src/alert-manager/build/alert-handler.common.dockerfile delete mode 100644 src/alert-manager/deploy/alert-configmap.yaml.template create mode 100755 src/alert-manager/deploy/alert-manager-configmap.yaml.template rename src/alert-manager/deploy/{alert-manager.yaml.template => alert-manager-deployment.yaml.template} (57%) mode change 100644 => 100755 delete mode 100644 src/alert-manager/deploy/alert-templates/pai.tmpl rename src/alert-manager/deploy/{start.sh.template => start.sh} (79%) mode change 100644 => 100755 create mode 100755 src/alert-manager/src/alert-handler/.editorconfig create mode 100755 src/alert-manager/src/alert-handler/.eslintrc.js create mode 100755 src/alert-manager/src/alert-handler/common/config.js create mode 100755 src/alert-manager/src/alert-handler/common/logger.js create mode 100755 src/alert-manager/src/alert-handler/controllers/job.js create mode 100755 src/alert-manager/src/alert-handler/controllers/mail.js create mode 100755 src/alert-manager/src/alert-handler/emails/general-templates/html.ejs create mode 100755 src/alert-manager/src/alert-handler/emails/general-templates/subject.ejs create mode 100755 src/alert-manager/src/alert-handler/index.js create mode 100755 src/alert-manager/src/alert-handler/package.json create mode 100755 src/alert-manager/src/alert-handler/prettier.config.js create mode 100755 src/alert-manager/src/alert-handler/routes/actions.js create mode 100755 src/alert-manager/src/alert-handler/yarn.lock create mode 100755 src/prometheus/deploy/alerting/customized.rules.template diff --git a/README.md b/README.md index 6dad31fcf4..5caa417231 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Join the chat at https://gitter.im/Microsoft/pai](https://badges.gitter.im/Microsoft/pai.svg)](https://gitter.im/Microsoft/pai?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Version](https://img.shields.io/github/release/Microsoft/pai.svg)](https://github.com/Microsoft/pai/releases/latest) -**OpenPAI [v1.1.1](./RELEASE_NOTE.md#July-2020-version-111) has been released!** +**OpenPAI [v1.2.0](./RELEASE_NOTE.md#Sep-2020-version-120) has been released!** With the release of v1.0, OpenPAI is switching to a more robust, more powerful and lightweight architecture. OpenPAI is also becoming more and more modular so that the platform can be easily customized and expanded to suit new needs. OpenPAI also provides many AI user-friendly features, making it easier for end users and administrators to complete daily AI tasks. @@ -127,6 +127,8 @@ The [admin manual](https://openpai.readthedocs.io/en/latest/manual/cluster-admin - **Users and groups management**. Administrators could manage the [users and groups](https://openpai.readthedocs.io/en/latest/manual/cluster-admin/how-to-manage-users-and-groups.html) easily. +- **Alerts management**. Administrators could [customize alerts rules and actions](https://openpai.readthedocs.io/en/latest/manual/cluster-admin/how-to-customize-alerts.html). + - **Customization**. Administrators could customize the cluster by [plugins](https://openpai.readthedocs.io/en/latest/manual/cluster-admin/how-to-customize-cluster-by-plugins.html). Administrators could also upgrade (or downgrade) a single component (e.g. rest servers) to address customized application demands. ### For cluster users diff --git a/contrib/kubespray/quick-start/services-configuration.yaml.template b/contrib/kubespray/quick-start/services-configuration.yaml.template index ae6100254a..5ba81b6cde 100644 --- a/contrib/kubespray/quick-start/services-configuration.yaml.template +++ b/contrib/kubespray/quick-start/services-configuration.yaml.template @@ -164,17 +164,37 @@ authentication: # port: 80 -# if you want to enable alert manager to send alert email, uncomment following lines and fill -# the right values. +# if you want to enable alert-handler actions, uncomment following lines and fill the right values. # alert-manager: -# receiver: your_addr@example.com -# smtp_url: smtp.office365.com:587 -# smtp_from: alert_sender@example.com -# smtp_auth_username: alert_sender@example.com -# smtp_auth_password: password_for_alert_sender -# port: 9093 # this is optional, you should not write this if you do not want to change the port alert-manager is listening on - -# uncomment following if you want to change customeize grafana +# port: 9093 # do not change this if you do not want to change the port alert-manager is listening on +# alert-handler: # alert-handler will only be enabled when this field is not empty +# port: 9095 # do not change this if you do not want to change the port alert-handler is listening on +# log-level: "info" +# pai-bearer-token: 'your-application-token-for-pai-rest-server' +# email-configs: # email-notification will only be enabled when this field is not empty +# admin-receiver: addr-of-admin-receiver@example.com +# smtp-host: smtp.office365.com +# smtp-port: 587 +# smtp-from: alert-sender@example.com +# smtp-auth-username: alert-sender@example.com +# smtp-auth-password: password-for-alert-sender +# customized-routes: +# routes: +# - receiver: pai-email-admin-user-and-stop-job +# match: +# alertname: PAIJobGpuPercentLowerThan0_3For1h +# customized-receivers: +# - name: "pai-email-admin-user-and-stop-job" +# actions: +# - email-admin +# - email-user +# - stop-jobs +# - tag-jobs +# tags: +# - 'stopped-by-alert-manager' + + +# uncomment following if you want to change customize grafana # grafana: # port: 3000 @@ -191,11 +211,21 @@ authentication: # interface: eth0,eno2 -# uncomment following if you want to change customeize prometheus +# uncomment following if you want to customize prometheus # prometheus: # port: 9091 # # How frequently to scrape targets # scrape_interval: 30 +# customized-alerts: | +# groups: +# - name: customized-alerts +# rules: +# - alert: PAIJobGpuPercentLowerThan0_3For1h +# expr: avg(task_gpu_percent{virtual_cluster=~"default"}) by (job_name) < 0.3 +# for: 1h +# annotations: +# summary: "{{$labels.job_name}} has a job gpu percent lower than 30% for 1 hour" +# description: Monitor job level gpu utilization in certain virtual clusters. # uncomment following section if you want to customize the threshold of cleaner diff --git a/deployment/paiLibrary/paiService/service_management_start.py b/deployment/paiLibrary/paiService/service_management_start.py index fdb5c95e94..10016a2317 100644 --- a/deployment/paiLibrary/paiService/service_management_start.py +++ b/deployment/paiLibrary/paiService/service_management_start.py @@ -79,8 +79,6 @@ def start(self, serv): for fat_serv in dependency_list: if fat_serv not in self.service_list: continue - if fat_serv in self.done_dict and self.done_dict[fat_serv] == True: - continue self.start(fat_serv) try_counts = 0 @@ -128,6 +126,4 @@ def run(self): self.logger.warning("service.yaml can't be found on the directory of {0}".format(serv)) self.logger.warning("Please check your source code. The {0}'s service will be skipped.".format(serv)) continue - if serv in self.done_dict and self.done_dict[serv] == True: - continue self.start(serv) diff --git a/docs/manual/cluster-admin/README.md b/docs/manual/cluster-admin/README.md index 5704d774d9..11aef676b5 100644 --- a/docs/manual/cluster-admin/README.md +++ b/docs/manual/cluster-admin/README.md @@ -14,6 +14,8 @@ This manual is for cluster administrators to learn the installation and uninstal 6. [How to Set Up Virtual Clusters](./how-to-set-up-virtual-clusters.md) 7. [How to Add and Remove Nodes](./how-to-add-and-remove-nodes.md) 8. [How to Customize Cluster by Plugins](./how-to-customize-cluster-by-plugins.md) -9. [Troubleshooting](./troubleshooting.md) -10. [How to Uninstall OpenPAI](./how-to-uninstall-openpai.md) -11. [Upgrade Guide](./upgrade-guide.md) \ No newline at end of file +9. [How to Customize Alerts](./how-to-customize-alerts.md) +10. [Troubleshooting](./troubleshooting.md) +11. [Recommended Practice](./recommended-practice.md) +12. [How to Uninstall OpenPAI](./how-to-uninstall-openpai.md) +13. [Upgrade Guide](./upgrade-guide.md) diff --git a/docs/manual/cluster-admin/how-to-customize-alerts.md b/docs/manual/cluster-admin/how-to-customize-alerts.md new file mode 100755 index 0000000000..1188973b65 --- /dev/null +++ b/docs/manual/cluster-admin/how-to-customize-alerts.md @@ -0,0 +1,165 @@ +# How to Customize Alerts + +OpenPAI supports the customization of alert rules and corresponding handling actions. +The alert rules are managed by `prometheus` service and the matching rules between rules and actions are managed by `alert-manager` service. + +By default, the alerts will only be displayed on the webportal. +You can customize `prometheus` and `alert-manager` to realize complex functions. +For example, we can send emails to administrators and alert related users, tag the jobs, etc. + +In this document, we will introduce existing alerts & actions, their matching methods, and how to add new customized alerts & actions. + +## Existing Alerts/Actions & How to Match Them + +### Existing Alerts + +OpenPAI uses `Prometheus` to monitor system metrics. +We provide various alerts by defining rules on virtual_clusters, GPU utilization, etc. +If OpenPAI is deployed, you can then visit `your_master_ip/prometheus/alerts` to see the details of alerts, including their definitions and status. + +For alerting rules syntax, please refer to [link](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/). + +### Existing Actions + +OpenPAI uses the `alert-manager` service for alert handling. We have provided so far these following actions: +* webportal-notification: Show alerts on the home page of webportal (on the top-right corner). +* email-admin: Send emails to the assigned admin. +* email-user: Send emails to the owners of jobs. +* stop-jobs Stop jobs by calling OpenPAI REST API. +* tag-jobs: Add a tag to jobs by calling OpenPAI REST API. + +The action `webportal-notification` is always enabled, which means that all the alerts will be shown on the webportal. + +All the other actions are realized in `alert-handler`. +To make these actions available, administrators need to properly fill the corresponding fields of `alert-manager` in `service-configuration.yml`, +the available actions list will then be saved in `cluster_cfg["alert-manager"]["actions-available"]`, please refer to [alert-manager config](https://github.com/microsoft/pai/tree/master/src/alert-manager/config/alert-manager.md) for details of alert-manager service configuration details. + +Make sure `job_name` presents in the alert body if you want to use `email-user`, `stop-jobs`, or `tag-jobs` actions. + +### How to Match Alerts and Actions + +The matching rules are defined using `receivers` and `rules`. +A `receiver` is simply a group of actions, a `rule` matches the alerts to a specific `receiver`. + +With the default configuration, all the alerts will match the default alert receiver which triggers only `email-admin` action. +You can add new receivers with related matching rules to assign actions to alerts in the `alert-manager` field in `service-configuration.yml` + +For example : + +``` yaml +customized-routes: + routes: + - receiver: pai-email-admin-user-and-stop-job + match: + alertname: PAIJobGpuPercentLowerThan0_3For1h +customized-receivers: + - name: "pai-email-admin-user-and-stop-job" + actions: + - email-admin + - email-user + - stop-jobs + - tag-jobs + tags: + - 'stopped-by-alert-manager' +``` + +Here we define : +- a receiver `pai-email-admin-user-and-stop-job`, which contains the actions `email-admin`, `email-user`, `stop-jobs` and `tag-jobs` +- a route, which matches the alert `pai-email-admin-user-and-stop-job` to the receiver `pai-email-admin-user-and-stop-job`. + +As a consequence, when the alert `PAIJobGpuPercentLowerThan0_3For1h` is fired, all these 4 actions will be triggered. + +For `routes` definition, we adopt the syntax of [Prometheus Alertmanager](https://prometheus.io/docs/alerting/latest/configuration/). +For `receivers` definition, you can simply: +- name the receiver in `name` field; +- list the actions to use in `actions`; +- list the tags in `tags` if `tag-jobs` is one of the actions. + +Remember to push service config to the cluster and restart the `alert-manager` service after your modification with the following commands in the dev-box container: +```bash +./paictl.py service stop -n alert-manager +./paictl.py config push -p /cluster-configuration -m service +./paictl.py service start -n alert-manager +``` + +For alert & action matching rules syntax, please refer to [Prometheus Alertmanager](https://prometheus.io/docs/alerting/latest/configuration/). + +For OpenPAI service management, please refer to [Basic Management Operations](https://github.com/microsoft/pai/blob/master/docs/manual/cluster-admin/basic-management-operations.md). + + +## How to Add Customized Alerts + +You can define customized alerts in the `prometheus` field in `service-configuration.yml`. +For example, We can add a customized alert `PAIJobGpuPercentLowerThan0_3For1h` by adding : + +``` yaml +customized-alerts: | + groups: + - name: customized-alerts + rules: + - alert: PAIJobGpuPercentLowerThan0_3For1h + expr: avg(task_gpu_percent{virtual_cluster=~"default"}) by (job_name) < 0.3 + for: 1h + annotations: + summary: "{{$labels.job_name}} has a job gpu percent lower than 30% for 1 hour" + description: Monitor job level gpu utilization in certain virtual clusters. +``` + +The `PAIJobGpuPercentLowerThan0_3For1h` alert will be fired when the job on virtual cluster `default` has a task level average GPU percent lower than `30%` for more than `1 hour`. +Here the metric `task_gpu_percent` is used, which describes the GPU utilization in task level. +You can explore the system metrics at `your_master_ip/prometheus/graph`. + +Remember to push service config to the cluster and restart the `prometheus` service after your modification with the following commands in the dev-box container: +```bash +./paictl.py service stop -n prometheus +./paictl.py config push -p /cluster-configuration -m service +./paictl.py service start -n prometheus +``` + +Please refer to [Prometheus Alerting Rules](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) for alerting rules syntax. + +## How to Add Customized Actions + +If you want to add new customized actions, follow these steps: + +### Realize the action in 'alert-handler'. +We provide `alert-handler` as a lightweight `express` application, where you can add customized APIs easily. + +For example, the `stop-jobs` action is realized by calling the `localhost:9095/alert-handler/stop-jobs` API through `webhook`, +the request is then forward to the OpenPAI Rest Server to stop the job. +You can add new APIs in `alert-handler` and adapt the request to realize the required action. + +The source code of `alert-handler` is available [here](https://github.com/microsoft/pai/blob/master/src/alert-manager/src/alert-handler). + +### Check the dependencies of the action + +As stated before, to make an action available, administrators need to provide the necessary configurations. +Check this [folder](https://github.com/microsoft/pai/tree/master/src/alert-manager/config) and define the dependencies' rules for your customized actions. + + +### Render the action to webhook configurations + +When customized receivers are defined in `service-configuration.yml`, +the `actions` will then be rendered as webhook_configs [here](https://github.com/microsoft/pai/blob/master/src/alert-manager/deploy/alert-manager-configmap.yaml.template). + +The actions we provide, `email-admin`, `email-user`, `stop-jobs`, `tag-jobs`, can be called within `alert-manager` by sending POST requests to `alert-handler`: +- `localhost:{your_alert_handler_port}/alert-handler/send-email-to-admin` +- `localhost:{your_alert_handler_port}/alert-handler/send-email-to-user` +- `localhost:{your_alert_handler_port}/alert-handler/stop-jobs` +- `localhost:{your_alert_handler_port}/alert-handler/tag-jobs/:tag` + +The request body will be automatically filled by `alert-manager` with `webhook` +and `alert-handler` will adapt the requests to various actions. + +Please define how to render your customized action to the `alert-handler` API request +[here](https://github.com/microsoft/pai/blob/master/src/alert-manager/src/alert-handler) + +Remember to re-build and push the docker image, and restart the `alert-manager` service after your modification with the following commmands in the dev-box container: + +```bash +./build/pai_build.py build -c /cluster-configuration/ -s alert-manager +./build/pai_build.py push -c /cluster-configuration/ -i alert-handler +./paictl.py service stop -n alert-manager +./paictl.py config push -p /cluster-configuration -m service +./paictl.py service start -n alert-manager +``` diff --git a/docs/manual/cluster-admin/troubleshooting.md b/docs/manual/cluster-admin/troubleshooting.md index 5d70fdd8bd..55b10935da 100644 --- a/docs/manual/cluster-admin/troubleshooting.md +++ b/docs/manual/cluster-admin/troubleshooting.md @@ -1,6 +1,64 @@ # Troubleshooting -## NVIDIA GPU is Not Detected +This ducument includes some troubleshooting cases in practice. + +### PaiServicePodNotReady Alert + +This is a kind of alert from alert manager, and usually caused by container being killed by operator or OOM killer. To check if it was killed by OOM killer, you can check node's free memory via Prometheus: + + 1. visit Prometheus web page, it is usually `http://:9091`. + 2. Enter query `node_memory_MemFree_bytes`. + 3. If free memory drop to near 0, the container should be killed by OOM killer + 4. You can double check this by logging into node and run command `dmesg` and looking for phase `oom`. Or you can run `docker inspect ` to get more detailed information. + +Solutions: + + 1. Force remove unhealth containers with this command in terminal: + `kubectl delete pod pod-name --grace-period=0 --force` + 2. Recreate pod in Kubernetes, this operation may block indefinitely because dockerd may not functioning correctly after OOM. If recreate blocked too long, you can log into the node and restart dockerd via `/etc/init.d/docker restart`. + 3. If restarting doesn't solve it, you can consider increase the pod's memory limit. + +### NodeNotReady Alert + +This is a kind of alert from alert manager, and is reported by watchdog service. Watchdog gets such metrics from Kubernetes API. Example metrics is like: + +``` +pai_node_count{disk_pressure="false",instance="10.0.0.1:9101",job="pai_serivce_exporter",memory_pressure="false",name="10.0.0.2",out_of_disk="false",pai_service_name="watchdog",ready="true",scraped_from="watchdog-5ddd945975-kwhpr"} +``` + +The name label indicate what node this metric represents. + +If the node's ready label has value "unknown", this means the node may disconnect from Kubernetes master, this may due to several reasons: + + - Node is down + - Kubelet is down + - Network partition between node and Kubernetes master + +You can first try to log into the node. If you can not, and have no ping response, the node may be down, and you should boot it up. + +If you can log in to the node, you should check if the kubelet is up and running, execute `sudo systemctl status kubelet` command in the node, normally you can see the kubelet service. + +After this step, you should check the log of kubelet, to see if it can access Kubernetes API. If you see something like: + +``` + E0410 04:24:30.663050 2491 kubelet_node_status.go:386] Error updating node status, will retry: error getting node "10.0.0.1": Get http://10.0.1.2:8080/api/v1/nodes/10.0.0.1: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) +``` + +This means the node can not report its status to Kubernetes, and hence the Kubernetes will post unknown status, and this triggered the alert. + +You should check what caused this connectivity problem. + +### NodeFilesystemUsage Alert + +This is a kind of alert from alert manager, and is used to monitor disk space of each server. If usage of disk space is greater than 80%, this alert will be triggered. OpenPAI has two services may use a lot of disk space. They are storage manager and docker image cache. If there is other usage of OpenPAI servers, they should be checked to avoid the disk usage is caused by outside of OpenPAI. + +Solutions: + + 1. Check user file on the NFS storage server launched by storage manager. If you didn't set up a storage manager, ignore this step. + 2. Check the docker cache. The docker may use too many disk space for caching, it's worth to have a check. + 3. Check PAI log folder size. The path is `/var/log/pai`. + +### NVIDIA GPU is Not Detected If you cannot use GPU in your job, please check the following items on the corresponding worker node: @@ -9,18 +67,48 @@ If you cannot use GPU in your job, please check the following items on the corre If the GPU number shown in webportal is wrong, check the [hivedscheduler and VC configuration](./how-to-set-up-virtual-clusters.md). -## A Certain Node is Lost +### Cannot See Utilization Information. + +If you cannot see utilization information (e.g. GPU, CPU, and network usage) in cluster, please check if the service `prometheus`, `grafana`, `job-exporter`, and `node-exporter` are working. -If the node is lost temporarily, you can wait until it works normally. +To be detailed, you can [exec into a dev box container](./basic-management-operations.md#pai-service-management-and-paictl), then check the service status by `kubectl get pod`. You can see the pod log by `kubectl logs `. After you fix the problem, you can [restart the whole cluster using paictl](./basic-management-operations.md#pai-service-management-and-paictl). -If you want to remove the node from your cluster, refer to [How to Add and Remove Nodes](how-to-add-and-remove-nodes.md). -## A Certain PAI Service is Not Working +### Node is De-allocated and doesn't Appear in Kubernetes System when it Comes Back -You can see service log on the [Kubernetes Dashboard](./basic-management-operations.md#access-kubernetes-dashboard) for triage. After the problem is addressed, restart the service using [paictl.py](./basic-management-operations.md#pai-service-management-and-paictl): +Working nodes can be de-allocated if you are using a cloud service and set up PAI on low-priority machines. Usually, if the node is lost temporarily, you can wait until the node comes back. It doesn't need any special care. + +However, some cloud service providers not only de-allocate nodes, but also remove all disk contents on the certain nodes. Thus the node cannot connect to Kubernetes automatically when it comes back. If it is your case, we recommend you to set up a crontab job on the dev box node to bring back these nodes periodically. + +In [How to Add and Remove Nodes](how-to-add-and-remove-nodes.md), we have described how to add a node. The crontab job doesn't need to do all of these things. It only needs to add the node to the Kubernetes. It figures out which nodes have come back but are still considered `NotReady` in Kubernetes, then, run the following command to bring it back: ```bash -./paictl.py service stop -n -./paictl.py service start -n +ansible-playbook -i inventory/mycluster/hosts.yml upgrade-cluster.yml --become --become-user=root --limit=${limit_list} -e "@inventory/mycluster/openpai.yml" +``` + +`${limit_list}` stands for the names of these de-allocated nodes. For example, if the crontab job finds node `a` and node `b` are available now, but they are still in `NotReady` status in Kuberentes, then it can set `limit_list=a,b`. + +### How to Enlarge Internal Storage Size + +Currently, OpenPAI uses [internal storage](https://github.com/microsoft/pai/tree/master/src/internal-storage) to hold database. Internal storage is a limited size storage. It leverages loop device in Linux to provide a storage with strictly limited quota. The default quota is 30 GB (or 10GB for OpenPAI <= `v1.1.0`), which can hold about 1,000,000 jobs. If you want a larger space to hold more jobs, please follow these steps to enlarge the internal storage: + +Step 1. [Exec into a dev box container.](./basic-management-operations.md#pai-service-management-and-paictl) + +Step 2. In the dev box container, stop all PAI services by `./paictl.py service stop`. + +Step 3. Log in to the master node. Find the internal storage folder (Default path is `/mnt/paiInternal`). Move it to another place like: `sudo mv /mnt/paiInternal /mnt/paiInternalBak` + +Step 4. Update the internal storage config in the `services-configuration.yaml`. For example, set the quota to 100 GB: +``` +internal-storage: + quota-gb: 100 +``` +If there is no `internal-storage` section in the file, you can add it manually. + +Update it by `./paictl.py config push -p -m service` + +Step 5. In the dev box container, start the internal storage service by `./paictl.py service start -n internal-storage` + +Step 6. After the internal storage service is ready, there will be a new `/mnt/paiInternal` in the master node. Move the previous data to it. Currently, we only need to move the `pgdata` folder: `sudo mv /mnt/paiInternalBak/pgdata /mnt/paiInternal/`. -``` \ No newline at end of file +Step 7. In the dev box container, start all PAI services by `./paictl.py service start`. diff --git a/examples/cluster-configuration/services-configuration.yaml b/examples/cluster-configuration/services-configuration.yaml index 7b3975b445..5b8e7bfdc8 100644 --- a/examples/cluster-configuration/services-configuration.yaml +++ b/examples/cluster-configuration/services-configuration.yaml @@ -103,15 +103,21 @@ rest-server: # node-exporter: # port: 9100 -# if you want to enable alert manager to send alert email, uncomment following lines and fill +# if you want to enable alert manager to send alert email to admin, uncomment following lines and fill # the right values. # alert-manager: -# receiver: your_addr@example.com -# smtp_url: smtp.office365.com:587 -# smtp_from: alert_sender@example.com -# smtp_auth_username: alert_sender@example.com -# smtp_auth_password: password_for_alert_sender -# port: 9093 # this is optional, you should not write this if you do not want to change the port alert-manager is listening on +# port: 9093 # do not change this if you do not want to change the port alert-manager is listening on +# alert-handler: # alert-handler will only be enabled when this field is not empty +# port: 9095 # do not change this if you do not want to change the port alert-handler is listening on +# log-level: "info" +# pai-bearer-token: 'your-application-token-for-pai-rest-server' # required if you want to send email to job users +# email-configs: # email-notification will only be enabled when this field is not empty +# admin-receiver: addr-of-admin-receiver@example.com +# smtp-host: smtp.office365.com +# smtp-port: 587 +# smtp-from: alert-sender@example.com +# smtp-auth-username: alert-sender@example.com +# smtp-auth-password: password-for-alert-sender # uncomment following if you want to change customize prometheus # prometheus: diff --git a/mkdocs.yml b/mkdocs.yml index b29e315bc5..7a9f345554 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -11,6 +11,7 @@ nav: - Use Marketplace: manual/cluster-user/use-marketplace.md - Use VSCode Extension: manual/cluster-user/use-vscode-extension.md - Use Jupyter Notebook Extension: manual/cluster-user/use-jupyter-notebook-extension.md + - Frequently Asked Questions: manual/cluster-user/frequently-asked-questions.md - Admin Manual: - Introduction: manual/cluster-admin/README.md - Installation Guide: manual/cluster-admin/installation-guide.md @@ -21,7 +22,9 @@ nav: - How to Set Up Virtual Clusters: manual/cluster-admin/how-to-set-up-virtual-clusters.md - How to Add and Remove Nodes: manual/cluster-admin/how-to-add-and-remove-nodes.md - How to Customize Cluster by Plugins: manual/cluster-admin/how-to-customize-cluster-by-plugins.md + - How to Customize Alerts: manual/cluster-admin/how-to-customize-alerts.md - Troubleshooting: manual/cluster-admin/troubleshooting.md + - Recommended Practice: manual/cluster-admin/recommended-practice.md - How to Uninstall OpenPAI: manual/cluster-admin/how-to-uninstall-openpai.md - Upgrade Guide: manual/cluster-admin/upgrade-guide.md plugins: diff --git a/src/alert-manager/.gitignore b/src/alert-manager/.gitignore new file mode 100755 index 0000000000..c093d3cfbe --- /dev/null +++ b/src/alert-manager/.gitignore @@ -0,0 +1,2 @@ +# Dependency directories +node_modules/ diff --git a/src/alert-manager/build/alert-handler.common.dockerfile b/src/alert-manager/build/alert-handler.common.dockerfile new file mode 100755 index 0000000000..31f650aaa4 --- /dev/null +++ b/src/alert-manager/build/alert-handler.common.dockerfile @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft Corporation +# All rights reserved. +# +# MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +# to permit persons to whom the Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +FROM node:dubnium + +WORKDIR /usr/src/app + +ENV NODE_ENV=production \ + SERVER_PORT=9095 + +COPY ./src/alert-handler . + +RUN yarn install + +EXPOSE ${SERVER_PORT} + +CMD ["npm", "start"] diff --git a/src/alert-manager/config/alert-manager.md b/src/alert-manager/config/alert-manager.md index b5dcca2b90..740de8dca5 100644 --- a/src/alert-manager/config/alert-manager.md +++ b/src/alert-manager/config/alert-manager.md @@ -1,8 +1,8 @@ ## Alerter-Manager section parser -- [Default Configuration](#D_Config) -- [How to Configure](#HT_Config) -- [Generated Configuration](#G_Config) +* [Default Configuration](#D_Config) +* [How to Configure](#HT_Config) +* [Generated Configuration](#G_Config) #### Default configuration @@ -10,48 +10,88 @@ #### How to configure cluster section in service-configuration.yaml -Port configurations in this section is optional which default to 9093. All other config is mandatory. If not receiver is configured, the alert manager will not start. +So far, we have provided `email-admin`, `email-user`, `stop-job` and `tag-job` actions in `alert-handler`. +To make all these actions available, +you should configure `alert-manager` in your `service-configuration.yaml` like following: -To configure alert-manager to send out alert email, you should configure alert manager with receiver in your service-configuration like following: -```yaml +``` yaml alert-manager: - receiver: your_addr@example.com - smtp_url: smtp.office365.com:587 - smtp_from: alert_sender@example.com - smtp_auth_username: alert_sender@example.com - smtp_auth_password: password_for_alert_sender - port: 9093 # this is optional, you should not write this if you do not want to change the port alert-manager is listening on + port: 9093 # optional, do not change this if you do not want to change the port alert-manager is listening on + alert-handler: # alert-handler will only be enabled when this field is not empty + port: 9095 # optional, do not change this if you do not want to change the port alert-handler is listening on + pai-bearer-token: 'your-application-token-for-pai-rest-server' + email-configs: # email-notification will only be enabled when this field is not empty + admin-receiver: addr-of-admin-receiver@example.com + smtp-host: smtp.office365.com + smtp-port: 587 + smtp-from: alert-sender@example.com + smtp-auth-username: alert-sender@example.com + smtp-auth-password: password-for-alert-sender ``` -In addition, if you deployed pai behind firewall, you should configure alert-manager with `use-pylon: True`, to make url from alert email public available. +In the configuration above, `email-configs` is necessary for `email-admin` and `email-user` actions, +`pai-bearer-token` is necessary for `email-user`, `stop-jobs` and `tag-jobs` actions. +This can be summrized in the following table: + +| | email-configs | pai-bearer-token | +| :-----------:| :-----------: | :--------------: | +| email-admin | True | False | +| email-user | True | True | +| stop-jobs | False | True | +| tag-jobs | False | True | + +If `alert-handler` is not configured, the `alert-handler` container will not start. + +In addition, if you deployed pai behind firewall, you should configure alert-manager with `use-pylon: True` , to make url from alert email public available. Also you can control the interval of sending same alert email if problem unsolved, the default interval is 24h, you can shorten it to 30m, by adding `repeat-interval: 30m` undert alert-manager config. #### Generated Configuration -After parsing, if you configured the alert-manager the model will be like: -```yaml -alert-manager: - receiver: your_addr@example.com - smtp_url: smtp.office365.com:587 - smtp_from: alert_sender@example.com - smtp_auth_username: alert_sender@example.com - smtp_auth_password: password_for_alert_sender - port: 9093 +After parsing, if you properly configured `email-configs` and `pai-bearer-token`, the configuration generated will be like: + +``` yaml +alert-manager: + port: 9093 + actions-available: + - webportal-notification + - email-admin + - email-user + - stop-jobs + - tag-jobs + alert-handler: + log-level: info + port: 9095 configured: True - host: master_ip - url: "http://master_ip:9093" - use-pylon: False - repeat-interval: 24h + pai-bearer-token: 'your-application-token-for-pai-rest-server' + email-configs: # email-notification will only be enabled when this field is not empty + admin-receiver: addr-of-admin-receiver@example.com + smtp-host: smtp.office365.com + smtp-port: 587 + smtp-from: alert-sender@example.com + smtp-auth-username: alert-sender@example.com + smtp-auth-password: password-for-alert-sender + host: master_ip + url: "http://master_ip:9093" + use-pylon: False + repeat-interval: 24h ``` -if you didn't configured alert-manager, it will be like: -```yaml +if you didn't configured `alert-handler`, it will be like: + +``` yaml alert-manager: - port: 9093 + port: 9093 + actions-available: + - webportal-notification + alert-handler: + log-level: info + port: 9095 configured: False - host: master_ip - url: "http://master_ip:9093" - use-pylon: False - repeat-interval: 24h + host: master_ip + url: "http://master_ip:9093" + use-pylon: False + repeat-interval: 24h ``` + +Similarly, we can get the generated configuration if `alert-handler` is partially configured. diff --git a/src/alert-manager/config/alert-manager.yaml b/src/alert-manager/config/alert-manager.yaml index db701b4643..d99037fe91 100644 --- a/src/alert-manager/config/alert-manager.yaml +++ b/src/alert-manager/config/alert-manager.yaml @@ -17,6 +17,14 @@ service_type: "common" +# Log level of alert-handler. You can choose from error, warn, info, http, verbose, debug, and silly. + port: 9093 +actions-available: + - webportal-notification +alert-handler: + log-level: 'info' + port: 9095 + configured: False use-pylon: False repeat-interval: '24h' \ No newline at end of file diff --git a/src/alert-manager/config/alert_manager.py b/src/alert-manager/config/alert_manager.py index 273d092231..a6feca9be4 100644 --- a/src/alert-manager/config/alert_manager.py +++ b/src/alert-manager/config/alert_manager.py @@ -19,14 +19,39 @@ def validation_pre(self): def run(self): result = copy.deepcopy(self.default_service_conf) result.update(self.service_conf) - if result.get("receiver") is not None and \ - result.get("smtp_url") is not None and \ - result.get("smtp_from") is not None and \ - result.get("smtp_auth_username") is not None and \ - result.get("smtp_auth_password") is not None: - result["configured"] = True + + # check if email_configs is properly configured + if result.get("alert-handler") is not None and \ + result["alert-handler"].get("email-configs") is not None and \ + result["alert-handler"]["email-configs"].get("admin-receiver") is not None and \ + result["alert-handler"]["email-configs"].get("smtp-host") is not None and \ + result["alert-handler"]["email-configs"].get("smtp-port") is not None and \ + result["alert-handler"]["email-configs"].get("smtp-from") is not None and \ + result["alert-handler"]["email-configs"].get("smtp-auth-username") is not None and \ + result["alert-handler"]["email-configs"].get("smtp-auth-password") is not None: + email_configured = True + else: + email_configured = False + + # check if `pai-bearer-token` is properly configureds + if result.get("alert-handler") is not None and \ + result["alert-handler"].get("pai-bearer-token") is not None: + token_configured = True else: - result["configured"] = False + token_configured = False + + if email_configured and token_configured: + result["alert-handler"]["configured"] = True + result["actions-available"].extend(["email-admin", "email-user", "stop-jobs", "tag-jobs"]) + elif email_configured: + result["alert-handler"]["configured"] = True + result["actions-available"].append("email-admin") + elif token_configured: + result["alert-handler"]["configured"] = True + result["actions-available"].extend(["stop-jobs", "tag-jobs"]) + else: + result["alert-handler"]["configured"] = False + result["host"] = self.get_master_ip() result["url"] = "http://{0}:{1}".format(self.get_master_ip(), result["port"]) diff --git a/src/alert-manager/deploy/alert-configmap.yaml.template b/src/alert-manager/deploy/alert-configmap.yaml.template deleted file mode 100644 index 7c6c946165..0000000000 --- a/src/alert-manager/deploy/alert-configmap.yaml.template +++ /dev/null @@ -1,31 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: alertmanager -data: - config.yml: |- -{% if cluster_cfg["alert-manager"]["configured"] %} -{% set alert_info = cluster_cfg["alert-manager"] %} - global: - resolve_timeout: 5m - smtp_smarthost: {{ alert_info["smtp_url"] }} - smtp_from: {{ alert_info["smtp_from"] }} - smtp_auth_username: {{ alert_info["smtp_auth_username"] }} - smtp_auth_password: {{ alert_info["smtp_auth_password"] }} - templates: - - "/etc/alertmanager/template/*.tmpl" - route: - receiver: pai-alert - group_wait: 30s - group_interval: 5m - repeat_interval: {{ cluster_cfg["alert-manager"]["repeat-interval"] }} - group_by: [alertname, alertstate] - receivers: - - name: "pai-alert" - email_configs: - - to: {{ alert_info["receiver"] }} - send_resolved: true - html: '{{ "{{" }} template "email.pai.html" . {{ "}}" }}' - headers: - subject: '{{ cluster_cfg["cluster"]["common"]["cluster-id"] }}: {{ "{{" }} template "__subject" . {{ "}}" }}' -{% endif %} diff --git a/src/alert-manager/deploy/alert-manager-configmap.yaml.template b/src/alert-manager/deploy/alert-manager-configmap.yaml.template new file mode 100755 index 0000000000..fdeb9872a6 --- /dev/null +++ b/src/alert-manager/deploy/alert-manager-configmap.yaml.template @@ -0,0 +1,93 @@ +# Copyright (c) Microsoft Corporation +# All rights reserved. +# +# MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +# to permit persons to whom the Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +apiVersion: v1 +kind: ConfigMap +metadata: + name: alertmanager-configmap +data: + config.yml: |- + global: + resolve_timeout: 5m + + route: + receiver: pai-email-admin + group_wait: 30s + group_interval: 5m + repeat_interval: {{ cluster_cfg["alert-manager"]["repeat-interval"] }} + group_by: [alertname, alertstate] + + {% if 'routes' in cluster_cfg["alert-manager"]["customized-routes"] %} + routes: + {% for route in cluster_cfg["alert-manager"]["customized-routes"]["routes"] %} + - receiver: {{ route.receiver}} + {% if 'match' in route %} + match: + {% for key, item in route["match"].items() %} + {{ key }}: {{ item }} + {% endfor %} + {% endif %} + {% if 'match_re' in route %} + match_re: + {% for key, item in route["match_re"].items() %} + {{ key }}: {{ item }} + {% endfor %} + {% endif %} + {% endfor %} + {% endif %} + + receivers: + - name: "pai-email-admin" + webhook_configs: +{% if 'email-admin' in cluster_cfg["alert-manager"]["actions-available"] %} + - url: 'http://localhost:{{ cluster_cfg["alert-manager"]["alert-handler"]["port"] }}/alert-handler/send-email-to-admin' + send_resolved: true +{% endif %} + + {% for receiver in cluster_cfg["alert-manager"]["customized-receivers"] %} + - name: {{ receiver.name}} + webhook_configs: + {% if 'email-admin' in receiver.actions %} + - url: 'http://localhost:{{ cluster_cfg["alert-manager"]["alert-handler"]["port"] }}/alert-handler/send-email-to-admin' + send_resolved: true + {% endif %} + + {% if 'email-user' in receiver.actions %} + - url: 'http://localhost:{{ cluster_cfg["alert-manager"]["alert-handler"]["port"] }}/alert-handler/send-email-to-user' + send_resolved: true + http_config: + bearer_token: {{ cluster_cfg["alert-manager"]["alert-handler"]["pai-bearer-token"] }} + {% endif %} + + {% if 'stop-jobs' in receiver.actions %} + - url: 'http://localhost:{{ cluster_cfg["alert-manager"]["alert-handler"]["port"] }}/alert-handler/stop-jobs' + send_resolved: false + http_config: + bearer_token: {{ cluster_cfg["alert-manager"]["alert-handler"]["pai-bearer-token"] }} + {% endif %} + + {% if 'tag-jobs' in receiver.actions %} + {% for tag in receiver["tags"] %} + - url: 'http://localhost:{{ cluster_cfg["alert-manager"]["alert-handler"]["port"] }}/alert-handler/tag-jobs/{{ tag }}' + send_resolved: false + http_config: + bearer_token: {{ cluster_cfg["alert-manager"]["alert-handler"]["pai-bearer-token"] }} + {% endfor %} + {% endif %} + + {% endfor %} diff --git a/src/alert-manager/deploy/alert-manager.yaml.template b/src/alert-manager/deploy/alert-manager-deployment.yaml.template old mode 100644 new mode 100755 similarity index 57% rename from src/alert-manager/deploy/alert-manager.yaml.template rename to src/alert-manager/deploy/alert-manager-deployment.yaml.template index 2bb59362d5..ce195331ac --- a/src/alert-manager/deploy/alert-manager.yaml.template +++ b/src/alert-manager/deploy/alert-manager-deployment.yaml.template @@ -15,7 +15,6 @@ # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -{% if cluster_cfg["alert-manager"]["configured"] %} {% if cluster_cfg["alert-manager"]["use-pylon"] %} {% set external_url = cluster_cfg["pylon"]["uri"] %} @@ -53,17 +52,43 @@ spec: volumeMounts: - name: config-volume mountPath: /etc/alertmanager - - name: templates-volume - mountPath: /etc/alertmanager/template - name: alertmanager mountPath: /alertmanager +{% if cluster_cfg["alert-manager"]["alert-handler"]["configured"] %} + - name: alerthandler + image: {{ cluster_cfg['cluster']['docker-registry']['prefix'] }}alert-handler:{{ cluster_cfg['cluster']['docker-registry']['tag'] }} + imagePullPolicy: Always + ports: + - name: alerthandler + containerPort: {{ cluster_cfg["alert-manager"]["alert-handler"]["port"] }} + env: + - name: CLUSTER_ID + value: {{ cluster_cfg["cluster"]["common"]["cluster-id"] }} + - name: REST_SERVER_URI + value: {{ cluster_cfg['rest-server']['uri'] }} + - name: LOG_LEVEL + value: {{ cluster_cfg["alert-manager"]["alert-handler"]["log-level"] }} +{% if 'email-admin' in cluster_cfg["alert-manager"]["actions-available"] %} + - name: EMAIL_CONFIGS_ADMIN_RECEIVER + value: {{ cluster_cfg["alert-manager"]["alert-handler"]["email-configs"]["admin-receiver"] }} + - name: EMAIL_CONFIGS_SMTP_HOST + value: {{ cluster_cfg["alert-manager"]["alert-handler"]["email-configs"]["smtp-host"] }} + - name: EMAIL_CONFIGS_SMTP_PORT + value: "{{ cluster_cfg["alert-manager"]["alert-handler"]["email-configs"]["smtp-port"] }}" + - name: EMAIL_CONFIGS_SMTP_FROM + value: {{ cluster_cfg["alert-manager"]["alert-handler"]["email-configs"]["smtp-from"] }} + - name: EMAIL_CONFIGS_SMTP_AUTH_USERNAME + value: {{ cluster_cfg["alert-manager"]["alert-handler"]["email-configs"]["smtp-auth-username"] }} + - name: EMAIL_CONFIGS_SMTP_AUTH_PASSWORD + value: {{ cluster_cfg["alert-manager"]["alert-handler"]["email-configs"]["smtp-auth-password"] }} +{% endif %} +{% endif %} + imagePullSecrets: + - name: {{ cluster_cfg["cluster"]["docker-registry"]["secret-name"] }} volumes: - name: config-volume configMap: - name: alertmanager - - name: templates-volume - configMap: - name: alert-templates + name: alertmanager-configmap - name: alertmanager emptyDir: {} tolerations: @@ -71,4 +96,3 @@ spec: operator: "Exists" - key: node.kubernetes.io/disk-pressure operator: "Exists" -{% endif %} diff --git a/src/alert-manager/deploy/alert-templates/pai.tmpl b/src/alert-manager/deploy/alert-templates/pai.tmpl deleted file mode 100644 index 65eecbcce9..0000000000 --- a/src/alert-manager/deploy/alert-templates/pai.tmpl +++ /dev/null @@ -1,128 +0,0 @@ -{{ define "email.pai.html" }} - - - - - - -{{ template "__subject" . }} - - - - - - - - - - - -
-
- - - {{ if gt (len .Alerts.Firing) 0 }} - - - - - -
- {{ else }} - - {{ end }} - {{ .Alerts | len }} alert{{ if gt (len .Alerts) 1 }}s{{ end }} for {{ range .GroupLabels.SortedPairs }} - {{ .Name }}={{ .Value }} - {{ end }} -
- - - - - {{ if gt (len .Alerts.Firing) 0 }} - - - - {{ end }} - {{ range .Alerts.Firing }} - - - - {{ end }} - - {{ if gt (len .Alerts.Resolved) 0 }} - - - - {{ end }} - {{ range .Alerts.Resolved }} - - - - {{ end }} -
- View in {{ template "__alertmanager" . }} -
- [{{ .Alerts.Firing | len }}] Firing -
- {{ if .Annotations.summary }} - {{ .Annotations.summary }} - {{ else }} - Labels
- {{ range .Labels.SortedPairs }}{{ .Name }} = {{ .Value }}
{{ end }} - {{ if gt (len .Annotations) 0 }}Annotations
{{ end }} - {{ range .Annotations.SortedPairs }}{{ .Name }} = {{ .Value }}
{{ end }} - {{ end }} - Source
-
- [{{ .Alerts.Resolved | len }}] Resolved -
- {{ if .Annotations.summary }} - {{ .Annotations.summary }} - {{ else }} - Labels
- {{ range .Labels.SortedPairs }}{{ .Name }} = {{ .Value }}
{{ end }} - {{ if gt (len .Annotations) 0 }}Annotations
{{ end }} - {{ range .Annotations.SortedPairs }}{{ .Name }} = {{ .Value }}
{{ end }} - {{ end }} - Source
-
-
- -
-
- - - -{{ end }} diff --git a/src/alert-manager/deploy/refresh.sh b/src/alert-manager/deploy/refresh.sh index 8ccb33c562..837f5cea05 100644 --- a/src/alert-manager/deploy/refresh.sh +++ b/src/alert-manager/deploy/refresh.sh @@ -21,7 +21,7 @@ pushd $(dirname "$0") > /dev/null echo "refresh alert-manager configuration" -kubectl apply -f alert-configmap.yaml || exit $? +kubectl apply -f alert-manager-configmap.yaml || exit $? -popd > /dev/null \ No newline at end of file +popd > /dev/null diff --git a/src/alert-manager/deploy/service.yaml b/src/alert-manager/deploy/service.yaml index 3a9c00d712..c87ab5ce01 100644 --- a/src/alert-manager/deploy/service.yaml +++ b/src/alert-manager/deploy/service.yaml @@ -24,9 +24,8 @@ prerequisite: - drivers template-list: - - alert-manager.yaml - - alert-configmap.yaml - - start.sh + - alert-manager-deployment.yaml + - alert-manager-configmap.yaml start-script: start.sh stop-script: stop.sh diff --git a/src/alert-manager/deploy/start.sh.template b/src/alert-manager/deploy/start.sh old mode 100644 new mode 100755 similarity index 79% rename from src/alert-manager/deploy/start.sh.template rename to src/alert-manager/deploy/start.sh index 5fc65322d7..854156b0e6 --- a/src/alert-manager/deploy/start.sh.template +++ b/src/alert-manager/deploy/start.sh @@ -1,7 +1,5 @@ #!/bin/bash -#!/bin/bash - # Copyright (c) Microsoft Corporation # All rights reserved. # @@ -21,15 +19,11 @@ pushd $(dirname "$0") > /dev/null -{% if cluster_cfg["alert-manager"]["configured"] %} -kubectl create configmap alert-templates --from-file=alert-templates --dry-run -o yaml | kubectl apply --overwrite=true -f - || exit $? -kubectl apply --overwrite=true -f alert-configmap.yaml || exit $? -kubectl apply --overwrite=true -f alert-manager.yaml || exit $? +kubectl apply --overwrite=true -f alert-manager-configmap.yaml || exit $? +kubectl apply --overwrite=true -f alert-manager-deployment.yaml || exit $? sleep 10 # wait until the service is ready. PYTHONPATH="../../../deployment" python -m k8sPaiLibrary.monitorTool.check_pod_ready_status -w -k app -v alertmanager || exit $? -{% endif %} - popd > /dev/null diff --git a/src/alert-manager/deploy/stop.sh b/src/alert-manager/deploy/stop.sh index 48e74a4bc2..2478d9e38e 100644 --- a/src/alert-manager/deploy/stop.sh +++ b/src/alert-manager/deploy/stop.sh @@ -1,5 +1,3 @@ -#!/bin/sh - #!/bin/bash # Copyright (c) Microsoft Corporation @@ -20,5 +18,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. kubectl delete --ignore-not-found --now configmap/alertmanager -kubectl delete --ignore-not-found --now configmap/alert-templates kubectl delete --ignore-not-found --now deployment/alertmanager diff --git a/src/alert-manager/src/alert-handler/.editorconfig b/src/alert-manager/src/alert-handler/.editorconfig new file mode 100755 index 0000000000..0f1786729b --- /dev/null +++ b/src/alert-manager/src/alert-handler/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/src/alert-manager/src/alert-handler/.eslintrc.js b/src/alert-manager/src/alert-handler/.eslintrc.js new file mode 100755 index 0000000000..703d6ae9c1 --- /dev/null +++ b/src/alert-manager/src/alert-handler/.eslintrc.js @@ -0,0 +1,36 @@ +module.exports = { + plugins: ['eslint-plugin-prettier'], + env: { + browser: false, + es6: true, + node: true, + jquery: true, + }, + extends: ['standard', 'plugin:prettier/recommended', 'prettier'], + parserOptions: { + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + cookies: 'readonly', + }, + settings: { + react: { + version: 'detect', + }, + }, + rules: { + 'prettier/prettier': ['error'], + 'max-len': [ + 'error', + { + code: 120, + ignoreComments: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + }, + ], + }, +}; diff --git a/src/alert-manager/src/alert-handler/common/config.js b/src/alert-manager/src/alert-handler/common/config.js new file mode 100755 index 0000000000..ff81a5f3d2 --- /dev/null +++ b/src/alert-manager/src/alert-handler/common/config.js @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +const Joi = require('joi'); + +const configSchema = Joi.object() + .keys({ + logLevel: Joi.string() + .valid('error', 'warn', 'info', 'http', 'verbose', 'debug', 'silly') + .default('info'), + }) + .required(); + +const config = { + logLevel: process.env.LOG_LEVEL, +}; + +const { error, value } = configSchema.validate(config); +if (error) { + throw new Error(`Config error\n${error}`); +} + +module.exports = value; diff --git a/src/alert-manager/src/alert-handler/common/logger.js b/src/alert-manager/src/alert-handler/common/logger.js new file mode 100755 index 0000000000..0395b2d5cb --- /dev/null +++ b/src/alert-manager/src/alert-handler/common/logger.js @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +const util = require('util'); +const winston = require('winston'); +const config = require('./config'); + +const logTransports = { + console: new winston.transports.Console({ + json: false, + colorize: true, + timestamp: () => new Date().toISOString(), + formatter: (options) => { + const timestamp = options.timestamp(); + const level = winston.config.colorize( + options.level, + options.level.toUpperCase(), + ); + const message = options.message ? options.message : ''; + const meta = + options.meta && Object.keys(options.meta).length + ? '\nmeta = ' + JSON.stringify(options.meta, null, 2) + : ''; + return util.format(timestamp, '[' + level + ']', message, meta); + }, + }), +}; + +// create logger +const logger = new winston.Logger({ + level: config.logLevel, + transports: [logTransports.console], + exitOnError: false, +}); + +logger.stream = { + write: (message, encoding) => { + logger.info(message.trim()); + }, +}; + +// module exports +module.exports = logger; diff --git a/src/alert-manager/src/alert-handler/controllers/job.js b/src/alert-manager/src/alert-handler/controllers/job.js new file mode 100755 index 0000000000..c9c2f7cb66 --- /dev/null +++ b/src/alert-manager/src/alert-handler/controllers/job.js @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +const unirest = require('unirest'); +const logger = require('@alert-handler/common/logger'); + +const stopJobs = (req, res) => { + logger.info( + 'alert-handler received `stop-jobs` post request from alert-manager.', + ); + // extract jobs to kill + const jobNames = []; + req.body.alerts.forEach(function (alert) { + if (alert.status === 'firing') { + jobNames.push(alert.labels.job_name); + } + }); + + if (jobNames.length === 0) { + res.status(200).json({ + message: 'No job to stop.', + }); + } + logger.info(`alert-handler will stop these jobs: ${jobNames}`); + + const url = process.env.REST_SERVER_URI; + const token = req.token; + // stop job by sending put request to rest server + jobNames.forEach(function (jobName) { + unirest + .put(`${url}/api/v2/jobs/${jobName}/executionType`) + .headers({ + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }) + .send(JSON.stringify({ value: 'STOP' })) + .end(function (response) { + if (!response.ok) { + logger.error('alert-handler failed to stop-job.'); + logger.error(response.raw_body); + res.status(500).json({ + message: 'alert-handler failed to stop-job.', + }); + } + }); + }); + + logger.info('alert-handler successfully stop jobs.'); + res.status(200).json({ + message: 'alert-handler successfully stop jobs.', + }); +}; + +const tagJobs = (req, res) => { + logger.info( + 'alert-handler received `tag-jobs` post request from alert-manager.', + ); + + const url = process.env.REST_SERVER_URI; + const token = req.token; + const tag = req.params.tag; + + // tag job with alertname + req.body.alerts.forEach(function (alert) { + if (alert.status === 'firing') { + const jobName = alert.labels.job_name; + // tag job by sending put request to rest server + unirest + .put(`${url}/api/v2/jobs/${jobName}/tag`) + .headers({ + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }) + .send(JSON.stringify({ value: tag })) + .end(function (response) { + if (!response.ok) { + logger.error('alert-handler failed to tag jobs.'); + logger.error(response.raw_body); + res.status(500).json({ + message: 'alert-handler failed to tag jobs.', + }); + } + }); + } + }); + + logger.info('alert-handler successfully tag jobs.'); + res.status(200).json({ + message: 'alert-handler successfully tag jobs.', + }); +}; + +// module exports +module.exports = { + stopJobs, + tagJobs, +}; diff --git a/src/alert-manager/src/alert-handler/controllers/mail.js b/src/alert-manager/src/alert-handler/controllers/mail.js new file mode 100755 index 0000000000..db15c91719 --- /dev/null +++ b/src/alert-manager/src/alert-handler/controllers/mail.js @@ -0,0 +1,207 @@ +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +const unirest = require('unirest'); +const nodemailer = require('nodemailer'); +const Email = require('email-templates'); +const logger = require('@alert-handler/common/logger'); + +// create reusable transporter object using the default SMTP transport +const transporter = nodemailer.createTransport({ + host: process.env.EMAIL_CONFIGS_SMTP_HOST, + port: parseInt(process.env.EMAIL_CONFIGS_SMTP_PORT), + secure: false, + auth: { + user: process.env.EMAIL_CONFIGS_SMTP_AUTH_USERNAME, + pass: process.env.EMAIL_CONFIGS_SMTP_AUTH_PASSWORD, + }, +}); + +const email = new Email({ + message: { + from: process.env.EMAIL_CONFIGS_SMTP_FROM, + }, + send: true, + transport: transporter, + views: { + options: { + extension: 'ejs', + }, + }, +}); + +const getAlertsGroupedByUser = (alerts, url, token) => { + // create promise group + const promises = []; + alerts.map(function (alert) { + const jobName = alert.labels.job_name; + if (jobName) { + promises.push( + new Promise(function (resolve, reject) { + return unirest + .get(`${url}/api/v2/jobs/${jobName}`) + .headers({ + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }) + .end(function (res) { + if (!res.ok) { + logger.error( + 'alert-handler failed to get username with jobname.', + ); + logger.error(res.raw_body); + reject( + new Error( + 'alert-handler failed to get username with jobname.', + ), + ); + } else { + resolve([res.body.jobStatus.username, alert]); + } + }); + }), + ); + } + }); + + // group alerts by username + const alertsGrouped = {}; + return ( + Promise.all(promises) + .then(function (values) { + values.forEach(function (value) { + const username = value[0]; + const alert = value[1]; + if (username in alertsGrouped) { + alertsGrouped[username].push(alert); + } else { + alertsGrouped[username] = [alert]; + } + }); + return alertsGrouped; + }) + // catch ? + .catch(function (error) { + return error; + }) + ); +}; + +const getUserEmail = (username, url, token) => { + return new Promise(function (resolve) { + return unirest + .get(`${url}/api/v2/users/${username}`) + .headers({ + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }) + .end(function (res) { + resolve(res.body.email); + }); + }); +}; + +const sendEmailToAdmin = async (req, res) => { + // send email to admin + email + .send({ + template: 'general-templates', + message: { + to: process.env.EMAIL_CONFIGS_ADMIN_RECEIVER, + }, + locals: { + cluster_id: process.env.CLUSTER_ID, + alerts: req.body.alerts, + groupLabels: req.body.groupLabels, + externalURL: req.body.externalURL, + }, + }) + .then(function () { + logger.info( + `alert-handler successfully send email to admin at ${process.env.EMAIL_CONFIGS_ADMIN_RECEIVER}`, + ); + res.status(200).json({ + message: `alert-handler successfully send email to admin at ${process.env.EMAIL_CONFIGS_ADMIN_RECEIVER}`, + }); + }) + .catch(function (data) { + logger.error('alert-handler failed to send email to admin'); + logger.error(data); + res.status(500).json({ + message: `alert-handler failed to send email to admin`, + }); + }); +}; + +const sendEmailToUser = async (req, res) => { + // send email to job user + // group alerts by username + const url = process.env.REST_SERVER_URI; + const token = req.token; + let alertsGrouped; + + try { + alertsGrouped = await getAlertsGroupedByUser(req.body.alerts, url, token); + } catch (data) { + logger.error(data); + res.status(500).json({ + message: `Send email encourted Unknown Error`, + }); + } + + if (alertsGrouped) { + // send emails to different users separately + Object.keys(alertsGrouped).forEach(async (username) => { + const userEmail = await getUserEmail(username, url, token); + email + .send({ + template: 'general-templates', + message: { + to: userEmail, + }, + locals: { + cluster_id: process.env.CLUSTER_ID, + alerts: alertsGrouped[username], + groupLabels: req.body.groupLabels, + externalURL: req.body.externalURL, + }, + }) + .then(function () { + logger.info( + `alert-handler successfully send email to ${username} at ${userEmail}`, + ); + }) + .catch(function (data) { + logger.error('alert-handler failed to send email to user'); + logger.error(data); + res.status(500).json({ + message: 'alert-handler failed to send email to user', + }); + }); + }); + + res.status(200).json({ + message: `alert-handler successfully send email to users`, + }); + } +}; + +// module exports +module.exports = { + sendEmailToAdmin, + sendEmailToUser, +}; diff --git a/src/alert-manager/src/alert-handler/emails/general-templates/html.ejs b/src/alert-manager/src/alert-handler/emails/general-templates/html.ejs new file mode 100755 index 0000000000..98aa7e65e4 --- /dev/null +++ b/src/alert-manager/src/alert-handler/emails/general-templates/html.ejs @@ -0,0 +1,166 @@ + + + + + + + + OpenPAI Alerts: [<%= alerts[0].status %>:<%= alerts.length %>] <%= alerts[0].labels.alertname %> + + + + + + + + + + +
+
+ + + <% if (alerts.filter( element => element.status =="firing").length > 0) { %> + + + + + +
+ <% } %> + <% if (alerts.filter( element => element.status =="firing").length == 0) { %> + + + <% } %> + <%= alerts.length %> alert<% if (alerts.length > 1) { %>s <% } %> for + <%= JSON.stringify(groupLabels) %> + from Cluster-ID: <%= cluster_id %> +
+ + + + + <% if (alerts.filter( element => element.status =="firing").length > 0) { %> + + + + <% } %> + <% alerts.filter( element => element.status =="firing").forEach(function(alert){ %> + + + + <% }); %> + + <% if (alerts.filter( element => element.status =="resolved").length > 0) { %> + + + + <% } %> + <% alerts.filter( element => element.status =="resolved").forEach(function(alert){ %> + + + + <% }); %> +
+ + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; line-height: 2em; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize; background-color: #348eda; margin: 0; border-color: #348eda; border-style: solid; border-width: 10px 20px;">View + in AlertManager +
+ [<%= alerts.filter( element => element.status =="firing").length %>] + Firing +
+ <% if (alert.annotations.summary) { %> + <%= alert.annotations.summary %> + <% } %> + <% if (!alert.annotations.summary) { %> + Labels
+ <%= JSON.stringify(alert.labels) %> + <% if (alert.annotations.length > 0) { %> + Annotations
+ <%= JSON.stringify(alert.annotations) %> + <% } %> + <% } %> + + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #348eda; text-decoration: underline; margin: 0;">Source
+
+ [<%= alerts.filter( element => element.status =="resolved").length %>] + Resolved +
+ <% if (alert.annotations.summary) { %> + <%= alert.annotations.summary %> + <% } %> + <% if (!alert.annotations.summary) { %> + Labels
+ <%= JSON.stringify(alert.labels) %> + <% if (alert.annotations.length > 0) { %> + Annotations
+ <%= JSON.stringify(alert.annotations) %> + <% } %> + <% } %> + + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #348eda; text-decoration: underline; margin: 0;">Source
+
+
+ + +
+
+ + + + \ No newline at end of file diff --git a/src/alert-manager/src/alert-handler/emails/general-templates/subject.ejs b/src/alert-manager/src/alert-handler/emails/general-templates/subject.ejs new file mode 100755 index 0000000000..2760de3f5f --- /dev/null +++ b/src/alert-manager/src/alert-handler/emails/general-templates/subject.ejs @@ -0,0 +1,7 @@ +OpenPAI Alerts : <%= groupLabels.alertname %>, +<% if (alerts.filter( element => element.status =="firing").length > 0) { %> +<%= alerts.filter( element => element.status =="firing").length %> Firing +<% } %> +<% if (alerts.filter( element => element.status =="resolved").length > 0) { %> +<%= alerts.filter( element => element.status =="resolved").length %> Resolved +<% } %> \ No newline at end of file diff --git a/src/alert-manager/src/alert-handler/index.js b/src/alert-manager/src/alert-handler/index.js new file mode 100755 index 0000000000..7b25b17a0e --- /dev/null +++ b/src/alert-manager/src/alert-handler/index.js @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +/** + * Implementation of Alert Handler. + */ + +require('module-alias/register'); +const express = require('express'); +const bearerToken = require('express-bearer-token'); +const actions = require('@alert-handler/routes/actions'); +const logger = require('@alert-handler/common/logger'); + +const app = express(); + +app.use(express.json()); +app.use(bearerToken()); + +app.use('/', actions); + +const port = process.env.SERVER_PORT; +app.listen(port, () => { + logger.info(`alert-handler listening at http://localhost:${port}`); +}); diff --git a/src/alert-manager/src/alert-handler/package.json b/src/alert-manager/src/alert-handler/package.json new file mode 100755 index 0000000000..98f4c8f1cf --- /dev/null +++ b/src/alert-manager/src/alert-handler/package.json @@ -0,0 +1,50 @@ +{ + "name": "pai-alert-handler", + "version": "0.0.0", + "description": "Alert Handler for Microsoft Platform for AI", + "keywords": [ + "Alert" + ], + "author": "Microsoft", + "license": "MIT", + "homepage": "https://github.com/Microsoft/pai", + "repository": { + "type": "git", + "url": "https://github.com/Microsoft/pai.git" + }, + "bugs": { + "url": "https://github.com/Microsoft/pai/issues" + }, + "engines": { + "node": "^10" + }, + "_moduleAliases": { + "@alert-handler": "." + }, + "devDependencies": { + "eslint": "^7.7.0", + "eslint-config-prettier": "~6.11.0", + "eslint-config-standard": "~14.1.1", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "~3.1.4", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1", + "prettier": "~2.0.5" + }, + "dependencies": { + "ejs": "^3.1.5", + "email-templates": "^7.1.0", + "express": "^4.16.2", + "express-bearer-token": "^2.4.0", + "joi": "^14.3.1", + "module-alias": "^2.2.2", + "nodemailer": "^6.4.11", + "unirest": "^0.6.0", + "winston": "2" + }, + "scripts": { + "lint": "eslint .", + "start": "node index.js" + } +} diff --git a/src/alert-manager/src/alert-handler/prettier.config.js b/src/alert-manager/src/alert-handler/prettier.config.js new file mode 100755 index 0000000000..219e71e448 --- /dev/null +++ b/src/alert-manager/src/alert-handler/prettier.config.js @@ -0,0 +1,8 @@ +module.exports = { + semi: true, + // Trailing commas help with git merging and conflict resolution + trailingComma: 'all', + // Use single quote in all files. https://github.com/prettier/prettier/issues/1080#issuecomment-390363232 + singleQuote: true, + jsxSingleQuote: true, +}; diff --git a/src/alert-manager/src/alert-handler/routes/actions.js b/src/alert-manager/src/alert-handler/routes/actions.js new file mode 100755 index 0000000000..1e5b3e9dca --- /dev/null +++ b/src/alert-manager/src/alert-handler/routes/actions.js @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation +// All rights reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +const express = require('express'); +const emailController = require('@alert-handler/controllers/mail'); +const jobController = require('@alert-handler/controllers/job'); + +const router = express.Router(); + +router + .route('/alert-handler/stop-jobs') + /** POST /alert-handler/stop-jobs */ + .post(jobController.stopJobs); + +router + .route('/alert-handler/tag-jobs/:tag') + /** POST /alert-handler/tag-jobs/:tag */ + .post(jobController.tagJobs); + +router + .route('/alert-handler/send-email-to-admin') + /** POST /alert-handler/send-email-to-admin */ + .post(emailController.sendEmailToAdmin); + +router + .route('/alert-handler/send-email-to-user') + /** POST /alert-handler/send-email-to-user */ + .post(emailController.sendEmailToUser); + +module.exports = router; diff --git a/src/alert-manager/src/alert-handler/yarn.lock b/src/alert-manager/src/alert-handler/yarn.lock new file mode 100755 index 0000000000..228dc3bd78 --- /dev/null +++ b/src/alert-manager/src/alert-handler/yarn.lock @@ -0,0 +1,3102 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/runtime@^7.6.3": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== + dependencies: + regenerator-runtime "^0.13.4" + +"@eslint/eslintrc@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085" + integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@hapi/boom@^9.1.0": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.0.tgz#0d9517657a56ff1e0b42d0aca9da1b37706fec56" + integrity sha512-4nZmpp4tXbm162LaZT45P7F7sgiem8dwAh2vHWT6XX24dozNjGMg6BvKCRvtCUcmcXqeMIUqWN8Rc5X8yKuROQ== + dependencies: + "@hapi/hoek" "9.x.x" + +"@hapi/hoek@9.x.x": + version "9.1.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" + integrity sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw== + +"@ladjs/i18n@^3.0.10": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@ladjs/i18n/-/i18n-3.0.13.tgz#62ec19c94bccef91aaf3f064e0ed9913e35a4ac9" + integrity sha512-V4Y2xw/u7lQrOXqnmBUKTFRAuA6Hw6eJheddhbHvjGUav0XD57gUH6gNzuzqaHeZvyFll08YENVjcV7MuO4zOQ== + dependencies: + "@hapi/boom" "^9.1.0" + boolean "3.0.1" + country-language "^0.1.7" + debug "^4.1.1" + i18n "^0.9.1" + i18n-locales "^0.0.4" + lodash "^4.17.15" + moment "^2.25.3" + multimatch "^4.0.0" + qs "^6.9.4" + titleize "^2.1.0" + +"@sindresorhus/is@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-2.1.1.tgz#ceff6a28a5b4867c2dd4a1ba513de278ccbe8bb1" + integrity sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg== + +"@types/babel-types@*", "@types/babel-types@^7.0.0": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.9.tgz#01d7b86949f455402a94c788883fe4ba574cad41" + integrity sha512-qZLoYeXSTgQuK1h7QQS16hqLGdmqtRmN8w/rl3Au/l5x/zkHx+a4VHrHyBsi1I1vtK2oBHxSzKIu0R5p6spdOA== + +"@types/babylon@^6.16.2": + version "6.16.5" + resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4" + integrity sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w== + dependencies: + "@types/babel-types" "*" + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/minimatch@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-globals@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" + integrity sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8= + dependencies: + acorn "^4.0.4" + +acorn-jsx@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== + +acorn@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= + +acorn@^4.0.4, acorn@~4.0.2: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c= + +acorn@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" + integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== + +ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: + version "6.12.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" + integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-differ@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-includes@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flat@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async@0.9.x, async@~0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + +async@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + +async@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" + integrity sha1-+PwEyjoTeErenhZBr5hXjPvWR6k= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" + integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== + +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +bluebird@^3.1.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +boolean@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.1.tgz#35ecf2b4a2ee191b0b44986f14eb5f052a5cbb4f" + integrity sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^2.0.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-parser@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" + integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= + dependencies: + is-regex "^1.0.3" + +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + +clean-css@^4.1.11: + version "4.2.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" + integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== + dependencies: + source-map "~0.6.0" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colors@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +combined-stream@~0.0.4: + version "0.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + integrity sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8= + dependencies: + delayed-stream "0.0.5" + +commander@^2.15.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +consolidate@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw== + dependencies: + bluebird "^3.1.1" + +constantinople@^3.0.1, constantinople@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647" + integrity sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw== + dependencies: + "@types/babel-types" "^7.0.0" + "@types/babylon" "^6.16.2" + babel-types "^6.26.0" + babylon "^6.18.0" + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-parser@^1.4.4: + version "1.4.5" + resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.5.tgz#3e572d4b7c0c80f9c61daf604e4336831b5d1d49" + integrity sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw== + dependencies: + cookie "0.4.0" + cookie-signature "1.0.6" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +cookie@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +core-js@^2.4.0: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +country-language@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/country-language/-/country-language-0.1.7.tgz#7870f4ba125db9a6071f19737bd9ef9343ae35db" + integrity sha1-eHD0uhJduaYHHxlze9nvk0OuNds= + dependencies: + underscore "~1.7.0" + underscore.deep "~0.5.1" + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +cycle@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" + integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +datauri@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/datauri/-/datauri-2.0.0.tgz#ff0ee23729935a6bcc81f301621bed3e692bf3c7" + integrity sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g== + dependencies: + image-size "^0.7.3" + mimer "^1.0.0" + +dayjs@^1.8.16: + version "1.8.35" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.35.tgz#67118378f15d31623f3ee2992f5244b887606888" + integrity sha512-isAbIEenO4ilm6f8cpqvgjZCsuerDAz2Kb7ri201AiNn58aqXuaLJEnCtfIMdCvERZHNGRY5lDMTr/jdAnKSWQ== + +debug@*, debug@^4.0.1, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debug@2.6.9, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +decamelize@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +delayed-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + integrity sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8= + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +doctypes@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" + integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.0.1.tgz#79695eb49af3cd8abc8d93a73da382deb1ca0795" + integrity sha512-1Aj1Qy3YLbdslkI75QEOfdp9TkQ3o8LRISAzxOibjBs/xWwr1WxZFOQphFkZuepHFGo+kB8e5FVJSS0faAJ4Rw== + dependencies: + domelementtype "^2.0.1" + domhandler "^3.0.0" + entities "^2.0.0" + +dom-serializer@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" + integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domhandler@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.0.0.tgz#51cd13efca31da95bbb0c5bee3a48300e333b3e9" + integrity sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw== + dependencies: + domelementtype "^2.0.1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.2.0.tgz#f3ce1610af5c30280bde1b71f84b018b958f32cf" + integrity sha512-0haAxVr1PR0SqYwCH7mxMpHZUwjih9oPPedqpR/KufsnxPyZ9dyVw1R5093qnJF3WXSbjBkdzRWLw/knJV/fAg== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.0.1" + domhandler "^3.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b" + integrity sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w== + dependencies: + jake "^10.6.1" + +email-templates@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/email-templates/-/email-templates-7.1.0.tgz#d10dad8ae673e06eaf1bdff2c179ae39dc31ae82" + integrity sha512-cO+6RgrFk1CPqm1y8UbSRyjZ4mrtk3FleT7IR7l82EbXfwnP2qSo94KDIeacklR4+oFktep2Z6ulkUp5Cf+UNw== + dependencies: + "@ladjs/i18n" "^3.0.10" + "@sindresorhus/is" "^2.1.1" + consolidate "^0.15.1" + debug "^4.1.1" + get-paths "^0.0.7" + html-to-text "^5.1.1" + juice "^6.0.0" + lodash "^4.17.15" + nodemailer "^6.4.6" + pify "^5.0.0" + preview-email "^2.0.1" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding-japanese@1.0.30: + version "1.0.30" + resolved "https://registry.yarnpkg.com/encoding-japanese/-/encoding-japanese-1.0.30.tgz#537c4d62881767925d601acb4c79fb14db81703a" + integrity sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg== + +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" + integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: + version "1.17.6" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" + integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.0" + is-regex "^1.1.0" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-config-prettier@~6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" + integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== + dependencies: + get-stdin "^6.0.0" + +eslint-config-standard@~14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" + integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== + +eslint-import-resolver-node@^0.3.3: + version "0.3.4" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" + integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== + dependencies: + debug "^2.6.9" + resolve "^1.13.1" + +eslint-module-utils@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" + integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== + dependencies: + debug "^2.6.9" + pkg-dir "^2.0.0" + +eslint-plugin-es@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" + integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + +eslint-plugin-import@^2.22.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e" + integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg== + dependencies: + array-includes "^3.1.1" + array.prototype.flat "^1.2.3" + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.3" + eslint-module-utils "^2.6.0" + has "^1.0.3" + minimatch "^3.0.4" + object.values "^1.1.1" + read-pkg-up "^2.0.0" + resolve "^1.17.0" + tsconfig-paths "^3.9.0" + +eslint-plugin-node@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" + integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== + dependencies: + eslint-plugin-es "^3.0.0" + eslint-utils "^2.0.0" + ignore "^5.1.1" + minimatch "^3.0.4" + resolve "^1.10.1" + semver "^6.1.0" + +eslint-plugin-prettier@~3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2" + integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-plugin-promise@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" + integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== + +eslint-plugin-standard@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" + integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== + +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^2.0.0, eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint@^7.7.0: + version "7.8.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.8.1.tgz#e59de3573fb6a5be8ff526c791571646d124a8fa" + integrity sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w== + dependencies: + "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.1.3" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + eslint-scope "^5.1.0" + eslint-utils "^2.1.0" + eslint-visitor-keys "^1.3.0" + espree "^7.3.0" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.19" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" + integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +express-bearer-token@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/express-bearer-token/-/express-bearer-token-2.4.0.tgz#f4d9d5a1e318953445e7f0d2bde00bb96d21c95a" + integrity sha512-2+kRZT2xo+pmmvSY7Ma5FzxTJpO3kGaPCEXPbAm3GaoZ/z6FE4K6L7cvs1AUZwY2xkk15PcQw7t4dWjsl5rdJw== + dependencies: + cookie "^0.3.1" + cookie-parser "^1.4.4" + +express@^4.16.2: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +eyes@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +filelist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.1.tgz#f10d1a3ae86c1694808e8f20906f43d4c9132dbb" + integrity sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ== + dependencies: + minimatch "^3.0.4" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.2.0.tgz#26f8bc26da6440e299cbdcfb69035c4f77a6e466" + integrity sha1-Jvi8JtpkQOKZy9z7aQNcT3em5GY= + dependencies: + async "~0.9.0" + combined-stream "~0.0.4" + mime-types "~2.0.3" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +get-paths@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/get-paths/-/get-paths-0.0.7.tgz#15331086752077cf130166ccd233a1cdbeefcf38" + integrity sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA== + dependencies: + pify "^4.0.1" + +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +graceful-fs@^4.1.2: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0, he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hoek@6.x.x: + version "6.1.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c" + integrity sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ== + +hosted-git-info@^2.1.4: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +html-to-text@5.1.1, html-to-text@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-5.1.1.tgz#2d89db7bf34bc7bcb7d546b1b228991a16926e87" + integrity sha512-Bci6bD/JIfZSvG4s0gW/9mMKwBRoe/1RWLxUME/d6WUSZCdY7T60bssf/jFf7EYXRyqU4P5xdClVqiYU0/ypdA== + dependencies: + he "^1.2.0" + htmlparser2 "^3.10.1" + lodash "^4.17.11" + minimist "^1.2.0" + +htmlparser2@^3.10.1, htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +htmlparser2@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" + integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== + dependencies: + domelementtype "^2.0.1" + domhandler "^3.0.0" + domutils "^2.0.0" + entities "^2.0.0" + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +i18n-locales@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/i18n-locales/-/i18n-locales-0.0.4.tgz#95d6505f6563f870f68860c23d35f82bd805cbf5" + integrity sha512-aP6VjhoBwSC8uZUehHWSszqdeWiheNXp0+oLPcZY4QAktsqcouHNYQee2NQFM4KNcCTKHHbfXrRUuOxjxF2jYw== + dependencies: + country-language "^0.1.7" + +i18n@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/i18n/-/i18n-0.9.1.tgz#a9dda09e582286c81a584374ac9f2aaef7ec37fb" + integrity sha512-ERo9WloOP2inRsJzAlzn4JDm3jvX7FW1+KB/JGXTzUVzi9Bsf4LNLXUQTMgM/aze4LNW/kvmxQX6bzg5UzqMJw== + dependencies: + debug "*" + make-plural "^6.2.1" + math-interval-parser "^2.0.1" + messageformat "^2.3.0" + mustache "^4.0.1" + sprintf-js "^1.1.2" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.0.tgz#59cdde0a2a297cc2aeb0c6445a195ee89f127550" + integrity sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" + integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.1: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +image-size@^0.7.3: + version "0.7.5" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.7.5.tgz#269f357cf5797cb44683dfa99790e54c705ead04" + integrity sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" + integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-expression@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-3.0.0.tgz#39acaa6be7fd1f3471dc42c7416e61c24317ac9f" + integrity sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8= + dependencies: + acorn "~4.0.2" + object-assign "^4.0.1" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-promise@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-regex@^1.0.3, is-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== + dependencies: + has-symbols "^1.0.1" + +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isemail@3.x.x: + version "3.2.0" + resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c" + integrity sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg== + dependencies: + punycode "2.x.x" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isstream@0.1.x, isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +jake@^10.6.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" + integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + dependencies: + async "0.9.x" + chalk "^2.4.2" + filelist "^1.0.1" + minimatch "^3.0.4" + +joi@^14.3.1: + version "14.3.1" + resolved "https://registry.yarnpkg.com/joi/-/joi-14.3.1.tgz#164a262ec0b855466e0c35eea2a885ae8b6c703c" + integrity sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ== + dependencies: + hoek "6.x.x" + isemail "3.x.x" + topo "3.x.x" + +js-stringify@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" + integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jstransformer@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" + integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= + dependencies: + is-promise "^2.0.0" + promise "^7.0.1" + +juice@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/juice/-/juice-6.0.0.tgz#cd8f8fe5210ef129d186fe2c41c0ec169f7b07b6" + integrity sha512-5T3JPgXYiw6A6axsb9E09Gzq46WbfJeDirY6nMrqY55iAdqEoPDxSr1GpXqYfoyndx4ujpBPXGLzBRzbiqOOaw== + dependencies: + cheerio "^0.22.0" + commander "^2.15.1" + cross-spawn "^6.0.5" + deep-extend "^0.6.0" + mensch "^0.3.4" + slick "^1.12.2" + web-resource-inliner "^4.3.3" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +libbase64@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/libbase64/-/libbase64-1.2.1.tgz#fb93bf4cb6d730f29b92155b6408d1bd2176a8c8" + integrity sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew== + +libmime@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/libmime/-/libmime-4.2.1.tgz#d21aa5db88b131af18bf5a3caa1013da2c21a9dd" + integrity sha512-09y7zjSc5im1aNsq815zgo4/G3DnIzym3aDOHsGq4Ee5vrX4PdgQRybAsztz9Rv0NhO+J5C0llEUloa3sUmjmA== + dependencies: + encoding-japanese "1.0.30" + iconv-lite "0.5.0" + libbase64 "1.2.1" + libqp "1.1.0" + +libmime@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/libmime/-/libmime-5.0.0.tgz#4759c76eb219985c5d4057b3a9359922194d9ff7" + integrity sha512-2Bm96d5ktnE217Ib1FldvUaPAaOst6GtZrsxJCwnJgi9lnsoAKIHyU0sae8rNx6DNYbjdqqh8lv5/b9poD8qOg== + dependencies: + encoding-japanese "1.0.30" + iconv-lite "0.6.2" + libbase64 "1.2.1" + libqp "1.1.0" + +libqp@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" + integrity sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g= + +linkify-it@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8" + integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ== + dependencies: + uc.micro "^1.0.1" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= + +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= + +lodash.merge@^4.4.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= + +lodash.unescape@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= + +mailparser@^2.7.7: + version "2.8.1" + resolved "https://registry.yarnpkg.com/mailparser/-/mailparser-2.8.1.tgz#a95b062e49dcb39051018962504a1a79646c7195" + integrity sha512-H/CYAO9dsw6SFNbEGGpZsejVSWDcFlyHjb1OkHUWg0wggUekva1tNc28trB155nSqM8rhtbwTKt//orX0AmJxQ== + dependencies: + encoding-japanese "1.0.30" + he "1.2.0" + html-to-text "5.1.1" + iconv-lite "0.6.2" + libmime "5.0.0" + linkify-it "3.0.2" + mailsplit "5.0.0" + nodemailer "6.4.11" + tlds "1.208.0" + +mailsplit@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/mailsplit/-/mailsplit-5.0.0.tgz#0924c89142deadb75ef3825860181e436d7557a1" + integrity sha512-HeXA0eyCKBtZqbr7uoeb3Nn2L7VV8Vm27x6/YBb0ZiNzRzLoNS2PqRgGYADwh0cBzLYtqddq40bSSirqLO2LGw== + dependencies: + libbase64 "1.2.1" + libmime "4.2.1" + libqp "1.1.0" + +make-plural@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-4.3.0.tgz#f23de08efdb0cac2e0c9ba9f315b0dff6b4c2735" + integrity sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA== + optionalDependencies: + minimist "^1.2.0" + +make-plural@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-6.2.2.tgz#beb5fd751355e72660eeb2218bb98eec92853c6c" + integrity sha512-8iTuFioatnTTmb/YJjywkVIHLjcwkFD9Ms0JpxjEm9Mo8eQYkh1z+55dwv4yc1jQ8ftVBxWQbihvZL1DfzGGWA== + +math-interval-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/math-interval-parser/-/math-interval-parser-2.0.1.tgz#e22cd6d15a0a7f4c03aec560db76513da615bed4" + integrity sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mensch@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/mensch/-/mensch-0.3.4.tgz#770f91b46cb16ea5b204ee735768c3f0c491fecd" + integrity sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +messageformat-formatters@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/messageformat-formatters/-/messageformat-formatters-2.0.1.tgz#0492c1402a48775f751c9b17c0354e92be012b08" + integrity sha512-E/lQRXhtHwGuiQjI7qxkLp8AHbMD5r2217XNe/SREbBlSawe0lOqsFb7rflZJmlQFSULNLIqlcjjsCPlB3m3Mg== + +messageformat-parser@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/messageformat-parser/-/messageformat-parser-4.1.3.tgz#b824787f57fcda7d50769f5b63e8d4fda68f5b9e" + integrity sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg== + +messageformat@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/messageformat/-/messageformat-2.3.0.tgz#de263c49029d5eae65d7ee25e0754f57f425ad91" + integrity sha512-uTzvsv0lTeQxYI2y1NPa1lItL5VRI8Gb93Y2K2ue5gBPyrbJxfDi/EYWxh2PKv5yO42AJeeqblS9MJSh/IEk4w== + dependencies: + make-plural "^4.3.0" + messageformat-formatters "^2.0.1" + messageformat-parser "^4.1.2" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-db@~1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.12.0.tgz#3d0c63180f458eb10d325aaa37d7c58ae312e9d7" + integrity sha1-PQxjGA9FjrENMlqqN9fFiuMS6dc= + +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mime-types@~2.0.3: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.0.14.tgz#310e159db23e077f8bb22b748dabfa4957140aa6" + integrity sha1-MQ4VnbI+B3+Lsit0jav6SVcUCqY= + dependencies: + mime-db "~1.12.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.0: + version "2.4.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" + integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== + +mimer@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mimer/-/mimer-1.1.0.tgz#2cb67f7093998e772a0e62c090f77daa1b8a2dbe" + integrity sha512-y9dVfy2uiycQvDNiAYW6zp49ZhFlXDMr5wfdOiMbdzGM/0N5LNR6HTUn3un+WUQcM0koaw8FMTG1bt5EnHJdvQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +module-alias@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0" + integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q== + +moment@^2.25.3: + version "2.27.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d" + integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +multimatch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" + integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== + dependencies: + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" + minimatch "^3.0.4" + +mustache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.0.1.tgz#d99beb031701ad433338e7ea65e0489416c854a2" + integrity sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +nodemailer@6.4.11, nodemailer@^6.3.1, nodemailer@^6.4.11, nodemailer@^6.4.6: + version "6.4.11" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.11.tgz#1f00b4ffd106403f17c03f3d43d5945b2677046c" + integrity sha512-BVZBDi+aJV4O38rxsUh164Dk1NCqgh6Cm0rQSb9SK/DHGll/DrCMnycVDD7msJgZCnmVa8ASo8EZzR7jsgTukQ== + +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-inspect@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" + integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.values@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +open@^6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" + integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== + dependencies: + is-wsl "^1.1.0" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" + integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@~2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" + integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg== + +preview-email@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/preview-email/-/preview-email-2.0.2.tgz#6cecec27ec91eb1ec1b0b67581d2f44f15c27b69" + integrity sha512-FADpJ1p5VX0F/V57gcxc8IoxX63JuyDOOMN4Y7tJwil8K1/lvN0HtO7mZHIP2kgwhMMehjYTxqnjFtSGg1/LXw== + dependencies: + "@babel/runtime" "^7.6.3" + dayjs "^1.8.16" + debug "^4.1.1" + mailparser "^2.7.7" + nodemailer "^6.3.1" + open "^6.4.0" + pify "^4.0.1" + pug "^2.0.4" + uuid "^3.3.3" + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise@^7.0.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +pug-attrs@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-2.0.4.tgz#b2f44c439e4eb4ad5d4ef25cac20d18ad28cc336" + integrity sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ== + dependencies: + constantinople "^3.0.1" + js-stringify "^1.0.1" + pug-runtime "^2.0.5" + +pug-code-gen@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-2.0.2.tgz#ad0967162aea077dcf787838d94ed14acb0217c2" + integrity sha512-kROFWv/AHx/9CRgoGJeRSm+4mLWchbgpRzTEn8XCiwwOy6Vh0gAClS8Vh5TEJ9DBjaP8wCjS3J6HKsEsYdvaCw== + dependencies: + constantinople "^3.1.2" + doctypes "^1.1.0" + js-stringify "^1.0.1" + pug-attrs "^2.0.4" + pug-error "^1.3.3" + pug-runtime "^2.0.5" + void-elements "^2.0.1" + with "^5.0.0" + +pug-error@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-1.3.3.tgz#f342fb008752d58034c185de03602dd9ffe15fa6" + integrity sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ== + +pug-filters@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-3.1.1.tgz#ab2cc82db9eeccf578bda89130e252a0db026aa7" + integrity sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg== + dependencies: + clean-css "^4.1.11" + constantinople "^3.0.1" + jstransformer "1.0.0" + pug-error "^1.3.3" + pug-walk "^1.1.8" + resolve "^1.1.6" + uglify-js "^2.6.1" + +pug-lexer@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-4.1.0.tgz#531cde48c7c0b1fcbbc2b85485c8665e31489cfd" + integrity sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA== + dependencies: + character-parser "^2.1.1" + is-expression "^3.0.0" + pug-error "^1.3.3" + +pug-linker@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-3.0.6.tgz#f5bf218b0efd65ce6670f7afc51658d0f82989fb" + integrity sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg== + dependencies: + pug-error "^1.3.3" + pug-walk "^1.1.8" + +pug-load@^2.0.12: + version "2.0.12" + resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-2.0.12.tgz#d38c85eb85f6e2f704dea14dcca94144d35d3e7b" + integrity sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg== + dependencies: + object-assign "^4.1.0" + pug-walk "^1.1.8" + +pug-parser@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-5.0.1.tgz#03e7ada48b6840bd3822f867d7d90f842d0ffdc9" + integrity sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA== + dependencies: + pug-error "^1.3.3" + token-stream "0.0.1" + +pug-runtime@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-2.0.5.tgz#6da7976c36bf22f68e733c359240d8ae7a32953a" + integrity sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw== + +pug-strip-comments@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz#cc1b6de1f6e8f5931cf02ec66cdffd3f50eaf8a8" + integrity sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw== + dependencies: + pug-error "^1.3.3" + +pug-walk@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-1.1.8.tgz#b408f67f27912f8c21da2f45b7230c4bd2a5ea7a" + integrity sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA== + +pug@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pug/-/pug-2.0.4.tgz#ee7682ec0a60494b38d48a88f05f3b0ac931377d" + integrity sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw== + dependencies: + pug-code-gen "^2.0.2" + pug-filters "^3.1.1" + pug-lexer "^4.1.0" + pug-linker "^3.0.6" + pug-load "^2.0.12" + pug-parser "^5.0.1" + pug-runtime "^2.0.5" + pug-strip-comments "^1.0.4" + +punycode@2.x.x, punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" + integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + +regexpp@^3.0.0, regexpp@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= + dependencies: + align-text "^0.1.1" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +"semver@2 || 3 || 4 || 5", semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.1.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.2.1: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +slick@^1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/slick/-/slick-1.12.2.tgz#bd048ddb74de7d1ca6915faa4a57570b3550c2d7" + integrity sha1-vQSN23TefRymkV+qSldXCzVQwtc= + +source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +sprintf-js@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimend@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimstart@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +titleize@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/titleize/-/titleize-2.1.0.tgz#5530de07c22147a0488887172b5bd94f5b30a48f" + integrity sha512-m+apkYlfiQTKLW+sI4vqUkwMEzfgEUEYSqljx1voUE3Wz/z1ZsxyzSxvH2X8uKVrOp7QkByWt0rA6+gvhCKy6g== + +tlds@1.208.0: + version "1.208.0" + resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.208.0.tgz#f9a85c272aa500e56c92e7d342fbfdfbddaa9757" + integrity sha512-6kbY7GJpRQXwBddSOAbVUZXjObbCGFXliWWN+kOSEoRWIOyRWLB6zdeKC/Tguwwenl/KsUx016XR50EdHYsxZw== + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +token-stream@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-0.0.1.tgz#ceeefc717a76c4316f126d0b9dbaa55d7e7df01a" + integrity sha1-zu78cXp2xDFvEm0LnbqlXX598Bo= + +topo@3.x.x: + version "3.0.3" + resolved "https://registry.yarnpkg.com/topo/-/topo-3.0.3.tgz#d5a67fb2e69307ebeeb08402ec2a2a6f5f7ad95c" + integrity sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ== + dependencies: + hoek "6.x.x" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tsconfig-paths@^3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" + integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +uc.micro@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@^2.6.1: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= + +underscore.deep@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/underscore.deep/-/underscore.deep-0.5.1.tgz#072671f48d68735c34223fcfef63e69e5276cc2b" + integrity sha1-ByZx9I1oc1w0Ij/P72PmnlJ2zCs= + +underscore@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" + integrity sha1-a7rwh3UA02vjTsqlhODbn+8DUgk= + +unirest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/unirest/-/unirest-0.6.0.tgz#289b5ae59cc9fa9fdfff3b5866e0dd50bf5eb280" + integrity sha512-BdYdcYJHXACqZ53k8Zz7QlNK/1W/HjCZlmg1OaaN/oTSp4FTWh0upXGSJsG88PljDBpSrNc2R649drasUA9NEg== + dependencies: + form-data "^0.2.0" + mime "^2.4.0" + request "^2.88.0" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +uri-js@^4.2.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2, uuid@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +v8-compile-cache@^2.0.3: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" + integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== + +valid-data-url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/valid-data-url/-/valid-data-url-2.0.0.tgz#2220fa9f8d4e761ebd3f3bb02770f1212b810537" + integrity sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +void-elements@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= + +web-resource-inliner@^4.3.3: + version "4.3.4" + resolved "https://registry.yarnpkg.com/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz#07e1b4bcbcbee1021251b018e902bac5713f1be0" + integrity sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA== + dependencies: + async "^3.1.0" + chalk "^2.4.2" + datauri "^2.0.0" + htmlparser2 "^4.0.0" + lodash.unescape "^4.0.1" + request "^2.88.0" + safer-buffer "^2.1.2" + valid-data-url "^2.0.0" + xtend "^4.0.2" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= + +winston@2: + version "2.4.5" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.5.tgz#f2e431d56154c4ea765545fc1003bd340c95b59a" + integrity sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A== + dependencies: + async "~1.0.0" + colors "1.0.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + stack-trace "0.0.x" + +with@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/with/-/with-5.1.1.tgz#fa4daa92daf32c4ea94ed453c81f04686b575dfe" + integrity sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4= + dependencies: + acorn "^3.1.0" + acorn-globals "^3.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" diff --git a/src/job-exporter/src/collector.py b/src/job-exporter/src/collector.py index 469f612a5c..0d6117d050 100644 --- a/src/job-exporter/src/collector.py +++ b/src/job-exporter/src/collector.py @@ -134,6 +134,7 @@ def __init__(self): "role_name", "task_index", "job_instance_id", # Used to distinguish job instance with same name but different retry number. + "virtual_cluster" ] self.service_labels = ["name"] @@ -529,6 +530,7 @@ class ContainerCollector(Collector): lsof_timeout = 2 # 99th latency is 0.5s pai_services = list(map(lambda s: "k8s_" + s, [ + # Run in master node "rest-server", "pylon", "webportal", @@ -536,28 +538,30 @@ class ContainerCollector(Collector): "prometheus", "alertmanager", "watchdog", - "end-to-end-test", - "yarn-frameworklauncher", - "hadoop-jobhistory-service", - "hadoop-name-node", - "hadoop-node-manager", - "hadoop-resource-manager", - "hadoop-data-node", - "zookeeper", + "frameworkcontroller", + "hivedscheduler", + "framework-watcher_database-controller", + "write-merger_database-controller", + "poller_database-controller", + "dshuttle-master", + "dshuttle-job-master", + "fluentd", + "postgresql_postgresql", + + # Run as daemon set "node-exporter", "job-exporter", - "yarn-exporter", - "nvidia-drivers", - "docker-cleaner", - - # Below are DLTS services - "nginx", - "restfulapi", + "log-manager-nginx", + "log-manager-logrotate", + "dshuttle-worker", + "dshuttle-job-worker", + "dshuttle-csi-daemon", "weave", "weave-npc", "nvidia-device-plugin-ctr", - "mysql", - "jobmanager", + "k8s-host-device", + "amdgpu", + "k8s-rdma", ])) def __init__(self, name, sleep_time, atomic_ref, iteration_counter, gpu_info_ref, @@ -605,6 +609,7 @@ def parse_from_labels(inspect_info, gpu_infos): result_labels["role_name"] = inspect_info.role_name or "unknown" result_labels["task_index"] = inspect_info.task_index or "unknown" result_labels["job_instance_id"] = inspect_info.job_instance_id or "unknown" + result_labels["virtual_cluster"] = inspect_info.virtual_cluster or "unknown" if inspect_info.gpu_ids: ids = inspect_info.gpu_ids.replace("\"", "").split(",") diff --git a/src/job-exporter/src/docker_inspect.py b/src/job-exporter/src/docker_inspect.py index 2e5b10d635..222312986b 100644 --- a/src/job-exporter/src/docker_inspect.py +++ b/src/job-exporter/src/docker_inspect.py @@ -28,18 +28,19 @@ class InspectResult(object): """ Represents a task meta data, parsed from docker inspect result """ - def __init__(self, username, job_name, role_name, task_index, gpu_ids, job_instance_id, pid): + def __init__(self, username, job_name, role_name, task_index, gpu_ids, job_instance_id, virtual_cluster, pid): self.username = username self.job_name = job_name self.role_name = role_name self.task_index = task_index self.gpu_ids = gpu_ids # comma separated str, str may be minor_number or UUID - self.pid = pid self.job_instance_id = job_instance_id # Used to distinguish job instance with same name but different retry number. + self.virtual_cluster = virtual_cluster + self.pid = pid def __repr__(self): - return "username %s, job_name %s, role_name %s, task_index %s, gpu_ids %s, job_instance_id %s pid %s" % \ - (self.username, self.job_name, self.role_name, self.task_index, self.gpu_ids, self.job_instance_id, self.pid) + return "username %s, job_name %s, role_name %s, task_index %s, gpu_ids %s, job_instance_id %s virtual_cluster %s pid %s " % \ + (self.username, self.job_name, self.role_name, self.task_index, self.gpu_ids, self.job_instance_id, self.virtual_cluster, self.pid) def __eq__(self, o): return self.username == o.username and \ @@ -48,11 +49,12 @@ def __eq__(self, o): self.task_index == o.task_index and \ self.gpu_ids == o.gpu_ids and \ self.job_instance_id == o.job_instance_id and \ + self.virtual_cluster == o.virtual_cluster and \ self.pid == o.pid keys = {"PAI_JOB_NAME", "PAI_USER_NAME", "PAI_CURRENT_TASK_ROLE_NAME", "GPU_ID", - "PAI_TASK_INDEX", "DLWS_JOB_ID", "DLWS_USER_NAME"} + "PAI_TASK_INDEX", "DLWS_JOB_ID", "DLWS_USER_NAME", "PAI_VIRTUAL_CLUSTER"} def parse_docker_inspect(inspect_output, gpu_vender): @@ -95,6 +97,7 @@ def parse_docker_inspect(inspect_output, gpu_vender): m.get("PAI_TASK_INDEX"), m.get("GPU_ID"), m.get("JOB_INSTANCE_ID"), + m.get("PAI_VIRTUAL_CLUSTER"), pid) def inspect(container_id, histogram, timeout, gpu_vender): diff --git a/src/job-exporter/test/data/docker_inspect_amd.json b/src/job-exporter/test/data/docker_inspect_amd.json index e3eb7892d6..19e5be98b1 100644 --- a/src/job-exporter/test/data/docker_inspect_amd.json +++ b/src/job-exporter/test/data/docker_inspect_amd.json @@ -231,6 +231,7 @@ "PAI_MIN_SUCCEEDED_TASK_COUNT_worker=1", "PAI_USERNAME=dgxadmin", "PAI_CURRENT_TASK_ROLE_NAME=worker", + "PAI_VIRTUAL_CLUSTER=default", "PAI_TASK_INDEX=0", "FC_FRAMEWORK_NAMESPACE=default", "FC_TASK_ATTEMPT_INSTANCE_UID=0_a1310f10-5ea6-11ea-8a2a-90b11c27f535", diff --git a/src/job-exporter/test/data/docker_inspect_kube_launcher_task.json b/src/job-exporter/test/data/docker_inspect_kube_launcher_task.json index 242d792bcd..c65710819a 100644 --- a/src/job-exporter/test/data/docker_inspect_kube_launcher_task.json +++ b/src/job-exporter/test/data/docker_inspect_kube_launcher_task.json @@ -180,6 +180,7 @@ "FC_CONFIGMAP_UID=69c05215-46fa-11e9-8937-000d3ab38724", "PAI_CURRENT_TASK_ROLE_MEM_MB=32768", "PAI_CURRENT_TASK_ROLE_NAME=worker", + "PAI_VIRTUAL_CLUSTER=default", "PAI_OUTPUT_DIR=", "PAI_MIN_FAILED_INSTANCE_worker=", "PAI_JOB_NAME=core~tensorflowcifar10", diff --git a/src/job-exporter/test/data/docker_inspect_sample.json b/src/job-exporter/test/data/docker_inspect_sample.json index d3eb1f22d9..f5f4b0e10b 100644 --- a/src/job-exporter/test/data/docker_inspect_sample.json +++ b/src/job-exporter/test/data/docker_inspect_sample.json @@ -88,6 +88,7 @@ "PAI_HOSTNAME": "paigcr-a-gpu-1058", "PAI_JOB_NAME": "trialslot_nnimain_d65bc5ac", "PAI_USER_NAME": "openmindstudio", + "PAI_VIRTUAL_CLUSTER": "default", "com.nvidia.build.id": "32579957", "com.nvidia.build.ref": "88bc4e08cac2668ec821eead444e5ede2cafcf25", "com.nvidia.cuda.version": "8.0.61", diff --git a/src/job-exporter/test/data/inspect_result_bug_fix.json b/src/job-exporter/test/data/inspect_result_bug_fix.json index 171c58a23c..4ececad688 100644 --- a/src/job-exporter/test/data/inspect_result_bug_fix.json +++ b/src/job-exporter/test/data/inspect_result_bug_fix.json @@ -250,6 +250,7 @@ "FRAMEWORK_NAME=sokoya~train-exp_offrl_sc_discard_0231-10th-beta07-lrfixed_13e9bf5_gCYv", "HADOOP_USER_NAME=sokoya", "PAI_TASK_INDEX=0", + "PAI_VIRTUAL_CLUSTER=default", "PAI_CONTAINER_HOST_IP=10.151.40.211", "PAI_CONTAINER_HOST_PORT_LIST=tensorboard:15452;http:15453;ssh:15454;", "PAI_CONTAINER_ID=container_e47_1553664769226_0080_01_000025", diff --git a/src/job-exporter/test/test_collector.py b/src/job-exporter/test/test_collector.py index 6477a1dd8b..d96ec79a68 100644 --- a/src/job-exporter/test/test_collector.py +++ b/src/job-exporter/test/test_collector.py @@ -48,6 +48,7 @@ def test_parse_from_labels(self): "0", "0,1,", "application_1522829300813_1943", + "default", 12345) gpu_ids, labels = ContainerCollector.parse_from_labels(inspect_result, None) @@ -58,7 +59,8 @@ def test_parse_from_labels(self): "job_name": "trialslot_nnimain_d65bc5ac", "role_name": "tuner", "task_index": "0", - "job_instance_id": "application_1522829300813_1943"} + "job_instance_id": "application_1522829300813_1943", + "virtual_cluster":"default"} self.assertEqual(target_labels, labels) diff --git a/src/job-exporter/test/test_docker_inspect.py b/src/job-exporter/test/test_docker_inspect.py index a6a76cad3c..53f3e5dcff 100644 --- a/src/job-exporter/test/test_docker_inspect.py +++ b/src/job-exporter/test/test_docker_inspect.py @@ -49,6 +49,7 @@ def test_parse_docker_inspect(self): "trialslot_nnimain_d65bc5ac", "tuner", "0", "0,1,", "application_1522829300813_1943", + "default", 95539) self.assertEqual(target_inspect_info, inspect_info) @@ -62,7 +63,7 @@ def test_parse_docker_inspect_kube(self): target_inspect_info = InspectResult( "core", "core~tensorflowcifar10", "worker", "0", "GPU-dc0671b0-61a4-443e-f456-f8fa6359b788", - "0_69c05215-46fa-11e9-8937-000d3ab38724", 23774) + "0_69c05215-46fa-11e9-8937-000d3ab38724", "default", 23774) self.assertEqual(target_inspect_info, inspect_info) def test_parse_docker_inspect_BUGFIX(self): @@ -74,7 +75,7 @@ def test_parse_docker_inspect_BUGFIX(self): target_inspect_info = InspectResult( "sokoya", "sokoya~train-exp_offrl_sc_discard_0231-10th-beta07-lrfixed_13e9bf5_gCYv", - "train", "0", "3,2,1,0", "application_1553664769226_0080", 30332) + "train", "0", "3,2,1,0", "application_1553664769226_0080", "default", 30332) self.assertEqual(target_inspect_info, inspect_info) def test_adapt_dlts_jobs(self): @@ -85,7 +86,7 @@ def test_adapt_dlts_jobs(self): inspect_info = parse_docker_inspect(docker_inspect, GpuVendor.NVIDIA) target_inspect_info = InspectResult( "dixu", "0c435eee-d31f-43d5-a1b3-442845fa1d0c", None, None, - "GPU-7c583998-b3ff-a885-8979-2d32d334cde4", None, 3533) + "GPU-7c583998-b3ff-a885-8979-2d32d334cde4", None, None, 3533) self.assertEqual(target_inspect_info, inspect_info) def test_parse_docker_inspect_amd(self): @@ -96,7 +97,7 @@ def test_parse_docker_inspect_amd(self): inspect_info = parse_docker_inspect(docker_inspect, GpuVendor.AMD) target_inspect_info = InspectResult( "dgxadmin", "dgxadmin~rocm_pytorch_mnist_a", "worker", "0", - "0,1", "0_a12d82af-5ea6-11ea-8a2a-90b11c27f535", 29647) + "0,1", "0_a12d82af-5ea6-11ea-8a2a-90b11c27f535", "default", 29647) self.assertEqual(target_inspect_info, inspect_info) diff --git a/src/prometheus/config/prometheus.md b/src/prometheus/config/prometheus.md index 45361fa9f3..80bb94d653 100644 --- a/src/prometheus/config/prometheus.md +++ b/src/prometheus/config/prometheus.md @@ -11,9 +11,9 @@ #### How to configure cluster section in service-configuration.yaml -All configurations in this section is optional. If you want to customized these value, you can configure it in service-configuration.yaml. +All configurations in this section are optional. If you want to customize these values, you can configure it in service-configuration.yaml. -For example, if you want to use different port than the default 9091, add following to your service-configuration.yaml as following: +For example, if you want to use different a port than the default 9091, add following to your service-configuration.yaml as following: ```yaml prometheus: port: new-value @@ -50,7 +50,7 @@ prometheus: prometheus.scrape_interval com["prometheus"]["scrape_interval"] cluster_cfg["prometheus"]["scrape_interval"] - URL + Int prometheus.url diff --git a/src/prometheus/deploy/alerting/customized.rules.template b/src/prometheus/deploy/alerting/customized.rules.template new file mode 100755 index 0000000000..b1405d3a7e --- /dev/null +++ b/src/prometheus/deploy/alerting/customized.rules.template @@ -0,0 +1,20 @@ +# Copyright (c) Microsoft Corporation +# All rights reserved. +# +# MIT License +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +# to permit persons to whom the Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +# Rule Syntax Reference: https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ + +{{ cluster_cfg['prometheus']['customized-alerts'] }} diff --git a/src/prometheus/deploy/alerting/jobs.rules b/src/prometheus/deploy/alerting/jobs.rules index 216743315a..ba7fafe332 100644 --- a/src/prometheus/deploy/alerting/jobs.rules +++ b/src/prometheus/deploy/alerting/jobs.rules @@ -18,16 +18,15 @@ # Rule Syntax Reference: https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ groups: - - name: pai-jobs - rules: - - alert: PaiJobsZombie - expr: zombie_container_count > 0 - for: 1h # only when it exceed 1 hour - annotations: - summary: "zombie container in {{$labels.instance}} detected" - - - alert: PaiJobPending - expr: pai_job_pod_count{pod_bound="true", phase="pending"} > 0 - for: 30m - annotations: - summary: "Job {{$labels.job_name}} in pending status detected" +- name: pai-jobs + rules: + - alert: PaiJobsZombie + expr: zombie_container_count > 0 + for: 1h # only when it exceed 1 hour + annotations: + summary: "zombie container in {{$labels.instance}}detected" + - alert: PaiJobPending + expr: pai_job_pod_count{pod_bound="true", phase="pending"} > 0 + for: 30m + annotations: + summary: "Job {{$labels.job_name}}in pending status detected" diff --git a/src/prometheus/deploy/prometheus-configmap.yaml.template b/src/prometheus/deploy/prometheus-configmap.yaml.template index 285a5776f5..95e21c7d17 100644 --- a/src/prometheus/deploy/prometheus-configmap.yaml.template +++ b/src/prometheus/deploy/prometheus-configmap.yaml.template @@ -16,7 +16,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. {% set prom_info = cluster_cfg["prometheus"] %} -{% set has_alert_manager = cluster_cfg["alert-manager"]["configured"] %} {% set alert_manager_port = cluster_cfg["alert-manager"]["port"] %} apiVersion: v1 kind: ConfigMap @@ -29,7 +28,7 @@ data: - "/etc/prometheus-alert/*.rules" - "/etc/prometheus-record/*.rules" scrape_configs: - - job_name: 'pai_serivce_exporter' + - job_name: 'pai_service_exporter' scrape_interval: {{ prom_info["scrape_interval"] }}s kubernetes_sd_configs: - role: pod @@ -57,11 +56,9 @@ data: - source_labels: [__meta_kubernetes_pod_label_app] action: replace target_label: pai_service_name -{% if has_alert_manager %} alerting: alertmanagers: - path_prefix: alert-manager static_configs: - targets: - {{ cluster_cfg['alert-manager']['host'] }}:{{ alert_manager_port }} -{% endif %} diff --git a/src/prometheus/deploy/service.yaml b/src/prometheus/deploy/service.yaml index 9d71c45786..e887bdc018 100644 --- a/src/prometheus/deploy/service.yaml +++ b/src/prometheus/deploy/service.yaml @@ -27,6 +27,7 @@ template-list: - prometheus-deployment.yaml - start.sh - delete.yaml + - alerting/customized.rules start-script: start.sh stop-script: stop.sh diff --git a/src/rest-server/build/build-pre.sh b/src/rest-server/build/build-pre.sh index e989221a37..bb764e6047 100755 --- a/src/rest-server/build/build-pre.sh +++ b/src/rest-server/build/build-pre.sh @@ -20,6 +20,7 @@ pushd $(dirname "$0") > /dev/null cp -arf "../../../version" "../version" +rm -rf "../openpaidbsdk" cp -arf "../../database-controller/sdk" "../openpaidbsdk" popd > /dev/null diff --git a/src/rest-server/src/models/v2/job/k8s.js b/src/rest-server/src/models/v2/job/k8s.js index 7e68e3ee03..f6229b9ab7 100644 --- a/src/rest-server/src/models/v2/job/k8s.js +++ b/src/rest-server/src/models/v2/job/k8s.js @@ -36,6 +36,8 @@ const { apiserver } = require('@pai/config/kubernetes'); const schedulePort = require('@pai/config/schedule-port'); const databaseModel = require('@pai/utils/dbUtils'); +const Sequelize = require('sequelize'); + let exitSpecPath; if (process.env[env.exitSpecPath]) { exitSpecPath = process.env[env.exitSpecPath]; @@ -134,6 +136,7 @@ const convertFrameworkSummary = (framework) => { state: framework.state, subState: framework.subState, executionType: framework.executionType.toUpperCase(), + tags: framework.tags.reduce((arr, curr) => [...arr, curr.name], []), retries: framework.retries, retryDetails: { user: framework.userRetries, @@ -241,7 +244,7 @@ const convertTaskDetail = async (taskStatus, ports, logPathPrefix) => { }; }; -const convertFrameworkDetail = async (framework) => { +const convertFrameworkDetail = async (framework, tags) => { const attemptStatus = framework.status.attemptStatus; // check fields which may be compressed if (attemptStatus.taskRoleStatuses == null) { @@ -267,9 +270,11 @@ const convertFrameworkDetail = async (framework) => { const completionStatus = attemptStatus.completionStatus; const diagnostics = completionStatus ? completionStatus.diagnostics : null; const exitDiagnostics = generateExitDiagnostics(diagnostics); + const detail = { debugId: framework.metadata.name, name: jobName, + tags: tags.reduce((arr, curr) => [...arr, curr.name], []), jobStatus: { username: userName, state: convertState( @@ -768,7 +773,12 @@ const generateFrameworkDescription = ( }; // generate framework env - const frameworkEnv = runtimeEnv.generateFrameworkEnv(frameworkName, config); + const frameworkEnv = runtimeEnv.generateFrameworkEnv( + frameworkName, + config, + virtualCluster, + ); + const frameworkEnvList = Object.keys(frameworkEnv).map((name) => { return { name, value: `${frameworkEnv[name]}` }; }); @@ -878,6 +888,8 @@ const getConfigSecretDef = (frameworkName, secrets) => { const list = async ( attributes, filters, + tagsContainFilter, + tagsNotContainFilter, order, offset, limit, @@ -885,12 +897,53 @@ const list = async ( ) => { let frameworks; let totalCount; + + if ( + Object.keys(tagsContainFilter).length !== 0 || + Object.keys(tagsNotContainFilter).length !== 0 + ) { + filters.name = {}; + // tagsContain + if (Object.keys(tagsContainFilter).length !== 0) { + const queryContainFrameworkName = databaseModel.sequelize.dialect.QueryGenerator.selectQuery( + 'tags', + { + attributes: ['frameworkName'], + where: tagsContainFilter, + }, + ); + filters.name[Sequelize.Op.in] = Sequelize.literal(` + (${queryContainFrameworkName.slice(0, -1)}) + `); + } + // tagsNotContain + if (Object.keys(tagsNotContainFilter).length !== 0) { + const queryNotContainFrameworkName = databaseModel.sequelize.dialect.QueryGenerator.selectQuery( + 'tags', + { + attributes: ['frameworkName'], + where: tagsNotContainFilter, + }, + ); + filters.name[Sequelize.Op.notIn] = Sequelize.literal(` + (${queryNotContainFrameworkName.slice(0, -1)}) + `); + } + } + frameworks = await databaseModel.Framework.findAll({ attributes: attributes, where: filters, offset: offset, limit: limit, order: order, + include: [ + { + attributes: ['name'], + required: Object.keys(tagsContainFilter).length !== 0, + model: databaseModel.Tag, + }, + ], }); if (withTotalCount) { totalCount = await databaseModel.Framework.count({ where: filters }); @@ -912,10 +965,18 @@ const get = async (frameworkName) => { const framework = await databaseModel.Framework.findOne({ attributes: ['submissionTime', 'snapshot'], where: { name: encodeName(frameworkName) }, + include: [ + { + attributes: ['name'], + model: databaseModel.Tag, + as: 'tags', + }, + ], }); if (framework) { const frameworkDetail = await convertFrameworkDetail( JSON.parse(framework.snapshot), + framework.tags, ); frameworkDetail.jobStatus.submissionTime = new Date( framework.submissionTime, @@ -1142,6 +1203,63 @@ const getSshInfo = async (frameworkName) => { ); }; +const addTag = async (frameworkName, tag) => { + // check if frameworkName exist + const framework = await databaseModel.Framework.findOne({ + where: { name: encodeName(frameworkName) }, + }); + + if (framework) { + // add tag + const data = await databaseModel.Tag.findOrCreate({ + where: { + frameworkName: encodeName(frameworkName), + name: tag, + uid: encodeName(`${frameworkName}+${tag}`), + }, + }); + return data; + } else { + throw createError( + 'Not Found', + 'NoJobError', + `Job ${frameworkName} is not found.`, + ); + } +}; + +const deleteTag = async (frameworkName, tag) => { + // check if frameworkName exist + const framework = await databaseModel.Framework.findOne({ + where: { name: encodeName(frameworkName) }, + }); + + if (framework) { + // remove tag + const numDestroyedRows = await databaseModel.Tag.destroy({ + where: { + frameworkName: encodeName(frameworkName), + name: tag, + }, + }); + if (numDestroyedRows === 0) { + throw createError( + 'Not Found', + 'NoTagError', + `Tag ${tag} is not found for job ${frameworkName}.`, + ); + } else { + return numDestroyedRows; + } + } else { + throw createError( + 'Not Found', + 'NoJobError', + `Job ${frameworkName} is not found.`, + ); + } +}; + const generateExitDiagnostics = (diag) => { if (_.isEmpty(diag)) { return null; @@ -1249,4 +1367,6 @@ module.exports = { execute, getConfig, getSshInfo, + addTag, + deleteTag, }; diff --git a/src/rest-server/src/models/v2/job/runtime-env.js b/src/rest-server/src/models/v2/job/runtime-env.js index 34646487dc..d1de30432e 100644 --- a/src/rest-server/src/models/v2/job/runtime-env.js +++ b/src/rest-server/src/models/v2/job/runtime-env.js @@ -15,7 +15,7 @@ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -const generateFrameworkEnv = (frameworkName, config) => { +const generateFrameworkEnv = (frameworkName, config, virtualCluster) => { const [userName] = frameworkName.split('~'); const env = { PAI_FRAMEWORK_NAME: frameworkName, @@ -24,6 +24,7 @@ const generateFrameworkEnv = (frameworkName, config) => { PAI_DEFAULT_FS_URI: '', PAI_TASK_ROLE_COUNT: Object.keys(config.taskRoles).length, PAI_TASK_ROLE_LIST: Object.keys(config.taskRoles).join(','), + PAI_VIRTUAL_CLUSTER: virtualCluster, }; let tasksNum = 0; for (const taskRole of Object.keys(config.taskRoles)) { diff --git a/src/tools/tests/test_alert_operator.py b/src/tools/tests/test_alert_operator.py index 76d23fde08..d00b27e75f 100644 --- a/src/tools/tests/test_alert_operator.py +++ b/src/tools/tests/test_alert_operator.py @@ -40,7 +40,7 @@ def success_response(): "alertname": "JobExporterHangs", "alertstate": "pending", "instance": "10.0.0.1:9102", - "job": "pai_serivce_exporter", + "job": "pai_service_exporter", "name": "docker_daemon_collector", "pai_service_name": "job-exporter", "scraped_from": "job-exporter-p4skn", @@ -57,7 +57,7 @@ def success_response(): "alertname": "NodeMemoryUsage", "alertstate": "firing", "instance": "10.0.0.2:9100", - "job": "pai_serivce_exporter", + "job": "pai_service_exporter", "pai_service_name": "node-exporter", "scraped_from": "node-exporter-blkpp" }, @@ -73,7 +73,7 @@ def success_response(): "alertstate": "firing", "command": "nvidia-smi", "instance": "10.0.0.3:9102", - "job": "pai_serivce_exporter", + "job": "pai_service_exporter", "pai_service_name": "job-exporter", "scraped_from": "job-exporter-t4sv6" }, From c573146c3f0517e885042dddb84d63be407398ba Mon Sep 17 00:00:00 2001 From: shaiic-pai Date: Tue, 29 Sep 2020 15:15:54 +0800 Subject: [PATCH 2/2] fix --- .../paiLibrary/common/template_handler.py | 4 +- .../alerting-and-troubleshooting.md | 153 ------------------ .../cluster-admin/imgs/alert-on-webportal.png | Bin 147948 -> 0 bytes 3 files changed, 2 insertions(+), 155 deletions(-) delete mode 100644 docs/manual/cluster-admin/alerting-and-troubleshooting.md delete mode 100644 docs/manual/cluster-admin/imgs/alert-on-webportal.png diff --git a/deployment/paiLibrary/common/template_handler.py b/deployment/paiLibrary/common/template_handler.py index 86e44b639f..fc7f304173 100644 --- a/deployment/paiLibrary/common/template_handler.py +++ b/deployment/paiLibrary/common/template_handler.py @@ -19,8 +19,8 @@ import logging import logging.config -logger = logging.getLogger(__name__) +logger = logging.getLogger(__name__) def generate_from_template_dict(template_data, map_table): @@ -28,4 +28,4 @@ def generate_from_template_dict(template_data, map_table): map_table ) - return generated_file \ No newline at end of file + return generated_file diff --git a/docs/manual/cluster-admin/alerting-and-troubleshooting.md b/docs/manual/cluster-admin/alerting-and-troubleshooting.md deleted file mode 100644 index f53961d4ca..0000000000 --- a/docs/manual/cluster-admin/alerting-and-troubleshooting.md +++ /dev/null @@ -1,153 +0,0 @@ -# Alerting and Troubleshooting - -OpenPAI uses [Prometheus](https://prometheus.io/) to monitor the system. You can view the monitoring information [on webportal](./basic-management-operations.md#management-on-webportal). For alerting, OpenPAI uses [alert manager](https://prometheus.io/docs/alerting/latest/alertmanager/), but it is not set up in default installation. This document describes how to set up alert manager, and how to deal with some common alerts. It also includes some other troubleshooting cases in practice. - -## Set Up Alert Manager - -OpenPAI's alert manager is set to send alerting e-mails when alert happens. To begin with, you should get an SMTP account to send these e-mails. - -After getting an SMTP account, how to set up the alert manager in PAI? Please read the document about [service management and paictl](./basic-management-operations.md#pai-service-management-and-paictl) first, and start a dev box container. Then, in the dev box container, pull the configuration by: - -```bash -./paictl config pull -o /cluster-configuration -``` - -Uncomment the alert manager section in `/cluster-configuration/services-configuration.yaml`, and set your SMTP account and the receiver's e-mail address. Here is an example: - -```bash -alert-manager: - port: 9093 - receiver: - smtp_auth_password: - smtp_auth_username: - smtp_from: - smtp_url: : -``` - -Configuration `port` stands for the port of alert manager. In most cases, you don't need to change it. Configuration `receiver` is usually set to be the administrator's e-mail address to receive alerting e-mails. - -Save the configuration file, and start alert manager by: - -```bash -./paictl.py service stop -n alert-manager -./paictl.py config push -p /cluster-configuration -m service -./paictl.py service start -n alert-manager -``` - -After alert manager is successfully started, the receiver's e-mail address will receive alerting e-mails from the SMTP account. Also, you can view the alerting information on Webportal (in the top-right corner): - - - - -## Troubleshooting - -### PaiServicePodNotReady Alert - -This is a kind of alert from alert manager, and usually caused by container being killed by operator or OOM killer. To check if it was killed by OOM killer, you can check node's free memory via Prometheus: - - 1. visit Prometheus web page, it is usually `http://:9091`. - 2. Enter query `node_memory_MemFree_bytes`. - 3. If free memory drop to near 0, the container should be killed by OOM killer - 4. You can double check this by logging into node and run command `dmesg` and looking for phase `oom`. Or you can run `docker inspect ` to get more detailed information. - -Solutions: - - 1. Force remove unhealth containers with this command in terminal: - `kubectl delete pod pod-name --grace-period=0 --force` - 2. Recreate pod in Kubernetes, this operation may block indefinitely because dockerd may not functioning correctly after OOM. If recreate blocked too long, you can log into the node and restart dockerd via `/etc/init.d/docker restart`. - 3. If restarting doesn't solve it, you can consider increase the pod's memory limit. - -### NodeNotReady Alert - -This is a kind of alert from alert manager, and is reported by watchdog service. Watchdog gets such metrics from Kubernetes API. Example metrics is like: - -``` -pai_node_count{disk_pressure="false",instance="10.0.0.1:9101",job="pai_serivce_exporter",memory_pressure="false",name="10.0.0.2",out_of_disk="false",pai_service_name="watchdog",ready="true",scraped_from="watchdog-5ddd945975-kwhpr"} -``` - -The name label indicate what node this metric represents. - -If the node's ready label has value "unknown", this means the node may disconnect from Kubernetes master, this may due to several reasons: - - - Node is down - - Kubelet is down - - Network partition between node and Kubernetes master - -You can first try to log into the node. If you can not, and have no ping response, the node may be down, and you should boot it up. - -If you can log in to the node, you should check if the kubelet is up and running, execute `sudo systemctl status kubelet` command in the node, normally you can see the kubelet service. - -After this step, you should check the log of kubelet, to see if it can access Kubernetes API. If you see something like: - -``` - E0410 04:24:30.663050 2491 kubelet_node_status.go:386] Error updating node status, will retry: error getting node "10.0.0.1": Get http://10.0.1.2:8080/api/v1/nodes/10.0.0.1: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) -``` - -This means the node can not report its status to Kubernetes, and hence the Kubernetes will post unknown status, and this triggered the alert. - -You should check what caused this connectivity problem. - -### NodeFilesystemUsage Alert - -This is a kind of alert from alert manager, and is used to monitor disk space of each server. If usage of disk space is greater than 80%, this alert will be triggered. OpenPAI has two services may use a lot of disk space. They are storage manager and docker image cache. If there is other usage of OpenPAI servers, they should be checked to avoid the disk usage is caused by outside of OpenPAI. - -Solutions: - - 1. Check user file on the NFS storage server launched by storage manager. If you didn't set up a storage manager, ignore this step. - 2. Check the docker cache. The docker may use too many disk space for caching, it's worth to have a check. - 3. Check PAI log folder size. The path is `/var/log/pai`. - -### NVIDIA GPU is Not Detected - -If you cannot use GPU in your job, please check the following items on the corresponding worker node: - - 1. The NVIDIA drivers should be installed correctly. Use `nvidia-smi` to confirm. - 2. [nvidia-container-runtime](https://github.com/NVIDIA/nvidia-container-runtime) is installed, and configured as the default runtime of docker. Use `docker info -f "{{json .DefaultRuntime}}"` to confirm. - -If the GPU number shown in webportal is wrong, check the [hivedscheduler and VC configuration](./how-to-set-up-virtual-clusters.md). - -### Cannot See Utilization Information. - -If you cannot see utilization information (e.g. GPU, CPU, and network usage) in cluster, please check if the service `prometheus`, `grafana`, `job-exporter`, and `node-exporter` are working. - -To be detailed, you can [exec into a dev box container](./basic-management-operations.md#pai-service-management-and-paictl), then check the service status by `kubectl get pod`. You can see the pod log by `kubectl logs `. After you fix the problem, you can [restart the whole cluster using paictl](./basic-management-operations.md#pai-service-management-and-paictl). - - -### Node is De-allocated and doesn't Appear in Kubernetes System when it Comes Back - -Working nodes can be de-allocated if you are using a cloud service and set up PAI on low-priority machines. Usually, if the node is lost temporarily, you can wait until the node comes back. It doesn't need any special care. - -However, some cloud service providers not only de-allocate nodes, but also remove all disk contents on the certain nodes. Thus the node cannot connect to Kubernetes automatically when it comes back. If it is your case, we recommend you to set up a crontab job on the dev box node to bring back these nodes periodically. - -In [How to Add and Remove Nodes](how-to-add-and-remove-nodes.md), we have described how to add a node. The crontab job doesn't need to do all of these things. It only needs to add the node to the Kubernetes. It figures out which nodes have come back but are still considered `NotReady` in Kubernetes, then, run the following command to bring it back: - -```bash -ansible-playbook -i inventory/mycluster/hosts.yml upgrade-cluster.yml --become --become-user=root --limit=${limit_list} -e "@inventory/mycluster/openpai.yml" -``` - -`${limit_list}` stands for the names of these de-allocated nodes. For example, if the crontab job finds node `a` and node `b` are available now, but they are still in `NotReady` status in Kuberentes, then it can set `limit_list=a,b`. - -### How to Enlarge Internal Storage Size - -Currently, OpenPAI uses [internal storage](https://github.com/microsoft/pai/tree/master/src/internal-storage) to hold database. Internal storage is a limited size storage. It leverages loop device in Linux to provide a storage with strictly limited quota. The default quota is 30 GB (or 10GB for OpenPAI <= `v1.1.0`), which can hold about 1,000,000 jobs. If you want a larger space to hold more jobs, please follow these steps to enlarge the internal storage: - -Step 1. [Exec into a dev box container.](./basic-management-operations.md#pai-service-management-and-paictl) - -Step 2. In the dev box container, stop all PAI services by `./paictl.py service stop`. - -Step 3. Log in to the master node. Find the internal storage folder (Default path is `/mnt/paiInternal`). Move it to another place like: `sudo mv /mnt/paiInternal /mnt/paiInternalBak` - -Step 4. Update the internal storage config in the `services-configuration.yaml`. For example, set the quota to 100 GB: -``` -internal-storage: - quota-gb: 100 -``` -If there is no `internal-storage` section in the file, you can add it manually. - -Update it by `./paictl.py config push -p -m service` - -Step 5. In the dev box container, start the internal storage service by `./paictl.py service start -n internal-storage` - -Step 6. After the internal storage service is ready, there will be a new `/mnt/paiInternal` in the master node. Move the previous data to it. Currently, we only need to move the `pgdata` folder: `sudo mv /mnt/paiInternalBak/pgdata /mnt/paiInternal/`. - -Step 7. In the dev box container, start all PAI services by `./paictl.py service start`. diff --git a/docs/manual/cluster-admin/imgs/alert-on-webportal.png b/docs/manual/cluster-admin/imgs/alert-on-webportal.png deleted file mode 100644 index 252aac0f98e3e7a2e271723afa612cff808a7f6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147948 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­`M*oo0?8aPeXnVwI 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 f50p9o)+2a#-RDe?zo4LCyQ0{LlXaI5Qyu